Add sample for cloudevents-nodejs (#2446)

* Add sample for cloudevents-nodejs

Signed-off-by: Carlos Santana <csantana@us.ibm.com>

* Add license headers

Signed-off-by: Carlos Santana <csantana@us.ibm.com>

* better to return 202 Accepted

Signed-off-by: Carlos Santana <csantana@us.ibm.com>
This commit is contained in:
Carlos Santana 2020-05-22 14:30:58 -04:00 committed by GitHub
parent 2cc9a5afe9
commit 7c8c382e88
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 3361 additions and 2 deletions

View File

@ -7,9 +7,9 @@ Serving resources and how they can be applied across common use cases.
| Name | Description | Languages |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
| Hello World | A quick introduction that highlights how to deploy an app using Knative Serving. | [C#](./hello-world/helloworld-csharp/README.md), [Go](./hello-world/helloworld-go/README.md), [Java (Spark)](./hello-world/helloworld-java-spark/README.md), [Java (Spring)](./hello-world/helloworld-java-spring/README.md), [Kotlin](./hello-world/helloworld-kotlin/README.md), [Node.js](./hello-world/helloworld-nodejs/README.md), [PHP](./hello-world/helloworld-php/README.md), [Python](./hello-world/helloworld-python/README.md), [Ruby](./hello-world/helloworld-ruby/README.md), [Scala](./hello-world/helloworld-scala/README.md), [Shell](./hello-world/helloworld-shell/README.md) |
| Cloud Events | A quick introduction that highlights how to send and receive Cloud Events. | [C#](./cloudevents/cloudevents-dotnet/README.md), [Go](./cloudevents/cloudevents-go/README.md) |
| Cloud Events | A quick introduction that highlights how to send and receive Cloud Events. | [C#](./cloudevents/cloudevents-dotnet/README.md), [Go](./cloudevents/cloudevents-go/README.md), [Node.js](./cloudevents/cloudevents-nodejs/README.md) |
| Advanced Deployment | Simple blue/green-like application deployment pattern illustrating the process of updating a live application without dropping any traffic. | [YAML](./blue-green-deployment.md) |
| Autoscale | A demonstration of the autoscaling capabilities of Knative. | [Go](./autoscale-go/README.md) | | | |
| Autoscale | A demonstration of the autoscaling capabilities of Knative. | [Go](./autoscale-go/README.md) |
| Github Webhook | A simple webhook handler that demonstrates interacting with Github. | [Go](./gitwebhook-go/README.md) |
| gRPC | A simple gRPC server. | [Go](./grpc-ping-go/README.md) |
| Knative Routing | An example of mapping multiple Knative services to different paths under a single domain name using the Istio VirtualService concept. | [Go](./knative-routing-go/README.md) |

View File

@ -0,0 +1,4 @@
Dockerfile
README.md
node_modules/
npm-debug.log

View File

@ -0,0 +1,2 @@
node_modules/
npm-debug.log*

View File

@ -0,0 +1,38 @@
# Copyright 2020 The Knative Authors
#
# Licensed 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
#
# https://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 registry.access.redhat.com/ubi8/nodejs-12
# Copy application dependency manifests to the container image.
# A wildcard is used to ensure both package.json AND package-lock.json are copied.
# Copying this separately prevents re-running npm install on every code change.
COPY package*.json ./
# Use ci is faster and more reliable following package-lock.json
RUN npm ci --only=production
# Doc port listening port
ENV PORT 8080
EXPOSE $PORT
ARG ENV=production
ENV NODE_ENV $ENV
# Run the web service on container startup.
CMD npm run $NODE_ENV
# Copy local code to the container image.
COPY . ./

View File

@ -0,0 +1,100 @@
A simple web app written in Node.js that can receive and send Cloud Events that you
can use for testing. 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.
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 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-nodejs
```
## 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).
## The sample code.
1. If you look in `index.js`, you will see two key functions for the
different modes of operation:
```js
const receiveAndSend = (cloudEvent, res) => {
// This is called whenever an event is received if $K_SINK is set, and sends a new event
// to the url in $K_SINK.
}
const receiveAndReply = (cloudEvent, res) => {
// This is called whenever an event is received if $K_SINK is NOT set, and it replies with
// the new event instead.
}
```
1. If you look in `Dockerfile`, you will see how the dependencies are installed using npm.
You can build and push this to your registry of choice via:
```shell
docker build -t <image> .
docker push <image>
```
1. If you look in `service.yaml`, take the `<image>` name above and insert it
into the `image:`.
```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-nodejs http://cloudevents-nodejs.default.1.2.3.4.xip.io cloudevents-nodejs-ss5pj cloudevents-nodejs-ss5pj True
```
Then send a cloud event to it with:
```shell
$ curl -X POST \
-H "content-type: application/json" \
-H "ce-specversion: 1.0" \
-H "ce-source: curl-command" \
-H "ce-type: curl.demo" \
-H "ce-id: 123-abc" \
-d '{"name":"Dave"}' \
http://cloudevents-nodejs.default.1.2.3.4.xip.io
```
You will get back:
```shell
{"message":"Hello, Dave"}
```
## Removing the sample app deployment
To remove the sample app from your cluster, delete the service record:
```shell
kubectl delete --filename service.yaml
```

View File

@ -0,0 +1,107 @@
/*
Copyright 2020 The Knative Authors
Licensed 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.
*/
const express = require('express')
const { CloudEvent, HTTPEmitter, HTTPReceiver } = require('cloudevents-sdk')
const PORT = process.env.PORT || 8080
const target = process.env.K_SINK
const app = express()
const receiver = new HTTPReceiver()
const main = () => {
app.listen(PORT, function () {
console.log(`Cookie monster is hungry for some cloudevents on port ${PORT}!`)
const modeMessage = target ? `send cloudevents to K_SINK: ${target}` : 'reply back with cloudevents'
console.log(`Cookie monster is going to ${modeMessage}`)
})
}
// handle shared the logic for producing the Response event from the Request.
const handle = (data) => {
return { message: `Hello, ${data.name ? data.name : 'nameless'}` }
}
// receiveAndSend responds with ack, and send a new event forward
const receiveAndSend = (cloudEvent, res) => {
const data = handle(cloudEvent.getData())
const newCloudEvent = new CloudEvent()
.type('dev.knative.docs.sample')
.source('https://github.com/knative/docs/docs/serving/samples/cloudevents/cloudevents-nodejs')
.time(new Date())
.data(data)
// With only an endpoint URL, this creates a v1 emitter
const emitter = new HTTPEmitter({
url: target
})
// Reply back to dispatcher/client as soon as possible
res.status(202).end()
// Send the new Event to the K_SINK
emitter.send(newCloudEvent)
.then((res) => {
console.log(`Sent event: ${JSON.stringify(newCloudEvent.format(), null, 2)}`)
console.log(`K_SINK responded: ${JSON.stringify({ status: res.status, headers: res.headers, data: res.data }, null, 2)}`)
})
.catch(console.error)
}
// receiveAndReply responds with new event
const receiveAndReply = (cloudEvent, res) => {
const data = handle(cloudEvent.getData())
const newCloudEvent = new CloudEvent()
.type('dev.knative.docs.sample')
.source('https://github.com/knative/docs/docs/serving/samples/cloudevents/cloudevents-nodejs')
.time(new Date())
console.log(`Reply event: ${JSON.stringify(newCloudEvent.format(), null, 2)}`)
res.set(getHeaders(newCloudEvent))
res.status(200).send(data)
}
const getHeaders = (cloudEvent) => {
/* TODO: SDK should provide a better way to get the headers from a cloudEvent, using fake url for now ¯\_(ツ)_/¯ */
const emitter = new HTTPEmitter({
url: 'http://example.com'
})
return emitter.headers(cloudEvent)
}
app.use((req, res, next) => {
let data = ''
req.setEncoding('utf8')
req.on('data', function (chunk) {
data += chunk
})
req.on('end', function () {
req.body = data
next()
})
})
app.post('/', function (req, res) {
try {
const event = receiver.accept(req.headers, req.body)
console.log(`Accepted event: ${JSON.stringify(event.format(), null, 2)}`)
target ? receiveAndSend(event, res) : receiveAndReply(event, res)
} catch (err) {
console.error(err)
res.status(415)
.header('Content-Type', 'application/json')
.send(JSON.stringify(err))
}
})
main()

View File

@ -0,0 +1,8 @@
---
title: "Cloud Events - Node.js"
linkTitle: "Node.js"
weight: 1
type: "docs"
---
{{% readfile file="README.md" %}}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,23 @@
{
"name": "knative-serving-cloudevents",
"version": "1.0.0",
"description": "Simple CloudEvents sample in Node.js",
"repository": "https://github.com/knative/docs",
"main": "index.js",
"scripts": {
"start": "node index.js",
"production": "npm start",
"dev": "nodemon index.js",
"lint": "standard --fix"
},
"author": "",
"license": "Apache-2.0",
"dependencies": {
"cloudevents-sdk": "cloudevents/sdk-javascript#57991e1",
"express": "^4.17.1",
"nodemon": "^2.0.3"
},
"devDependencies": {
"standard": "^14.3.4"
}
}

View File

@ -0,0 +1,28 @@
# Copyright 2020 The Knative Authors
#
# Licensed 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
#
# https://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.
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: cloudevents-nodejs
namespace: default
spec:
template:
spec:
containers:
- image: <registry/repository/image:tag>
# Uncomment this to send events somewhere.
# env:
# - name: K_SINK
# value: http://default-broker.default.svc.cluster.local