mirror of https://github.com/knative/docs.git
Remove outdated samples (#509)
This commit is contained in:
parent
44cd74fe68
commit
67224a6786
|
@ -1,119 +0,0 @@
|
|||
# Sample: Binding running services to an IoT core
|
||||
|
||||
This sample shows how to bind a running service to an IoT core using PubSub as the event source.
|
||||
|
||||
> For the ease of the demonstration, a few variables here are hard-coded.
|
||||
|
||||
## Setup
|
||||
|
||||
Define environment variables:
|
||||
|
||||
```shell
|
||||
export IOTCORE_PROJECT="s9-demo"
|
||||
export IOTCORE_REG="next18-demo"
|
||||
export IOTCORE_DEVICE="next18-demo-client"
|
||||
export IOTCORE_REGION="us-central1"
|
||||
export IOTCORE_TOPIC_DATA="iot-demo"
|
||||
export IOTCORE_TOPIC_DEVICE="iot-demo-device"
|
||||
```
|
||||
|
||||
## Create a device registry
|
||||
|
||||
Run the following command to create a device registry:
|
||||
|
||||
```shell
|
||||
gcloud iot registries create $IOTCORE_REG \
|
||||
--project=$IOTCORE_PROJECT \
|
||||
--region=$IOTCORE_REGION \
|
||||
--event-notification-config=$IOTCORE_TOPIC_DATA \
|
||||
--state-pubsub-topic=$IOTCORE_TOPIC_DEVICE
|
||||
```
|
||||
|
||||
## Create device certificates
|
||||
|
||||
Create certificates to connect the device to the IoT Core gateway:
|
||||
|
||||
```shell
|
||||
openssl genrsa -out rsa_private.pem 2048
|
||||
openssl rsa -in rsa_private.pem -pubout -out rsa_public.pem
|
||||
```
|
||||
|
||||
## Register the IoT device
|
||||
|
||||
Once created, add the public key to the IoT core registry:
|
||||
|
||||
```shell
|
||||
gcloud iot devices create $IOTCORE_DEVICE \
|
||||
--project=$IOTCORE_PROJECT \
|
||||
--region=$IOTCORE_REGION \
|
||||
--registry=$IOTCORE_REG \
|
||||
--public-key path=./rsa_public.pem,type=rs256
|
||||
```
|
||||
|
||||
## Generate data
|
||||
|
||||
To mimic an IoT device sending data to the IoT gateway, run the provided
|
||||
Node.js client with the following parameters:
|
||||
|
||||
```shell
|
||||
node send-data.js \
|
||||
--projectId=$IOTCORE_PROJECT \
|
||||
--cloudRegion=$IOTCORE_REGION \
|
||||
--registryId=$IOTCORE_REG \
|
||||
--deviceId=$IOTCORE_DEVICE \
|
||||
--privateKeyFile=./iot_demo_private.pem \
|
||||
--algorithm=RS256
|
||||
```
|
||||
|
||||
This "device" will publish one event per second to the IoT Core gateway.
|
||||
The gateway will automatically publish the received events to the configured
|
||||
PubSub topic (`iot-demo`).
|
||||
|
||||
The following payload is sent by this simulated IoT client:
|
||||
|
||||
```shell
|
||||
{
|
||||
source_id: 'next18-demo-client',
|
||||
event_id: '41e13421-25aa-4e93-bca8-0ffeb5c040c8',
|
||||
event_ts: 1531515192370,
|
||||
metric: 9
|
||||
}
|
||||
```
|
||||
|
||||
The `event_id` value here is a unique UUIDv4 ID, `event_ts` is UNIX Epoch time, and `metric`
|
||||
is a random number 1-10.
|
||||
|
||||
## Create a function that handles events
|
||||
|
||||
Now we want to consume these IoT events, so let's create the function to handle the events:
|
||||
|
||||
```shell
|
||||
kubectl apply --filename route.yaml
|
||||
kubectl apply --filename configuration.yaml
|
||||
```
|
||||
|
||||
## Create an event source
|
||||
|
||||
Before we can bind an action to an event source, we have to create an event source
|
||||
that knows how to wire events into actions for that particular event type.
|
||||
|
||||
First let's create a ServiceAccount, so that we can run the local receive adapter
|
||||
in Pull mode to poll for the events from this topic.
|
||||
|
||||
Then let's create a GCP PubSub as an event source that we can bind to.
|
||||
|
||||
```shell
|
||||
kubectl apply --filename serviceaccount.yaml
|
||||
kubectl apply --filename serviceaccountbinding.yaml
|
||||
kubectl apply --filename eventsource.yaml
|
||||
kubectl apply --filename eventtype.yaml
|
||||
```
|
||||
|
||||
## Bind IoT events to our function
|
||||
|
||||
We have now created a function that we want to consume our IoT events, and we have an event
|
||||
source that's sending events via GCP PubSub, so let's wire the two together:
|
||||
|
||||
```shell
|
||||
kubectl apply --filename flow.yaml
|
||||
```
|
|
@ -1,27 +0,0 @@
|
|||
# Copyright 2018 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/v1alpha1
|
||||
kind: Configuration
|
||||
metadata:
|
||||
name: iot-function
|
||||
namespace: default
|
||||
spec:
|
||||
revisionTemplate:
|
||||
metadata:
|
||||
labels:
|
||||
knative.dev/type: container
|
||||
spec:
|
||||
container:
|
||||
image: github.com/mchmarny/next18/event-flow
|
|
@ -1,20 +0,0 @@
|
|||
{
|
||||
"name": "demo-device",
|
||||
"version": "0.0.1",
|
||||
"description": "MQTT Demo Device for Google Cloud IoT Core using NodeJS",
|
||||
"main": "device.js",
|
||||
"license": "Apache-2.0",
|
||||
"author": "Google Inc.",
|
||||
"dependencies": {
|
||||
"@google-cloud/nodejs-repo-tools": "2.2.1",
|
||||
"@google-cloud/pubsub": "0.16.4",
|
||||
"MD5": "^1.3.0",
|
||||
"ava": "0.25.0",
|
||||
"jsonwebtoken": "8.2.0",
|
||||
"mqtt": "2.16.0",
|
||||
"node-uuid": "1.4.8",
|
||||
"uuid": "3.2.1",
|
||||
"yargs": "11.0.0"
|
||||
},
|
||||
"devDependencies": {}
|
||||
}
|
|
@ -1,296 +0,0 @@
|
|||
/**
|
||||
* Copyright 2017, Google, Inc.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
// [START iot_mqtt_include]
|
||||
const fs = require('fs');
|
||||
const jwt = require('jsonwebtoken');
|
||||
const mqtt = require('mqtt');
|
||||
const uuid = require('node-uuid');
|
||||
const os = require('os');
|
||||
// [END iot_mqtt_include]
|
||||
|
||||
// The initial backoff time after a disconnection occurs, in seconds.
|
||||
var MINIMUM_BACKOFF_TIME = 1;
|
||||
|
||||
// The maximum backoff time before giving up, in seconds.
|
||||
var MAXIMUM_BACKOFF_TIME = 59;
|
||||
|
||||
// Whether to wait with exponential backoff before publishing.
|
||||
var shouldBackoff = false;
|
||||
|
||||
// The current backoff time.
|
||||
var backoffTime = 1;
|
||||
|
||||
// Whether an asynchronous publish chain is in progress.
|
||||
var publishChainInProgress = false;
|
||||
|
||||
console.log('Knative IoT Example');
|
||||
var argv = require(`yargs`)
|
||||
.options({
|
||||
projectId: {
|
||||
default: process.env.GCLOUD_PROJECT || process.env.GOOGLE_CLOUD_PROJECT,
|
||||
description: 'The Project ID to use. Defaults to the value of the GCLOUD_PROJECT or GOOGLE_CLOUD_PROJECT environment variables.',
|
||||
requiresArg: true,
|
||||
type: 'string'
|
||||
},
|
||||
cloudRegion: {
|
||||
default: 'us-central1',
|
||||
description: 'GCP cloud region.',
|
||||
requiresArg: true,
|
||||
type: 'string'
|
||||
},
|
||||
registryId: {
|
||||
description: 'Cloud IoT registry ID.',
|
||||
requiresArg: true,
|
||||
demandOption: true,
|
||||
type: 'string'
|
||||
},
|
||||
deviceId: {
|
||||
description: 'Cloud IoT device ID.',
|
||||
requiresArg: true,
|
||||
demandOption: true,
|
||||
type: 'string'
|
||||
},
|
||||
privateKeyFile: {
|
||||
description: 'Path to private key file.',
|
||||
requiresArg: true,
|
||||
demandOption: true,
|
||||
type: 'string'
|
||||
},
|
||||
algorithm: {
|
||||
description: 'Encryption algorithm to generate the JWT.',
|
||||
requiresArg: true,
|
||||
demandOption: true,
|
||||
choices: ['RS256', 'ES256'],
|
||||
type: 'string'
|
||||
},
|
||||
numMessages: {
|
||||
default: 100,
|
||||
description: 'Number of messages to publish.',
|
||||
requiresArg: true,
|
||||
type: 'number'
|
||||
},
|
||||
tokenExpMins: {
|
||||
default: 20,
|
||||
description: 'Minutes to JWT token expiration.',
|
||||
requiresArg: true,
|
||||
type: 'number'
|
||||
},
|
||||
mqttBridgeHostname: {
|
||||
default: 'mqtt.googleapis.com',
|
||||
description: 'MQTT bridge hostname.',
|
||||
requiresArg: true,
|
||||
type: 'string'
|
||||
},
|
||||
mqttBridgePort: {
|
||||
default: 8883,
|
||||
description: 'MQTT bridge port.',
|
||||
requiresArg: true,
|
||||
type: 'number'
|
||||
},
|
||||
messageType: {
|
||||
default: 'events',
|
||||
description: 'Message type to publish.',
|
||||
requiresArg: true,
|
||||
choices: ['events', 'state'],
|
||||
type: 'string'
|
||||
}
|
||||
})
|
||||
.example(`node $0 send-data.js --projectId=blue-jet-123 \\\n\t--registryId=my-registry --deviceId=my-node-device \\\n\t--privateKeyFile=../rsa_private.pem --algorithm=RS256 \\\n\t --cloudRegion=us-west1`)
|
||||
.wrap(120)
|
||||
.recommendCommands()
|
||||
.epilogue(`For more information, see https://cloud.google.com/iot-core/docs`)
|
||||
.help()
|
||||
.strict()
|
||||
.argv;
|
||||
|
||||
// Create a Cloud IoT Core JWT for the given project id, signed with the given
|
||||
// private key.
|
||||
// [START iot_mqtt_jwt]
|
||||
function createJwt(projectId, privateKeyFile, algorithm) {
|
||||
// Create a JWT to authenticate this device. The device will be disconnected
|
||||
// after the token expires, and will have to reconnect with a new token. The
|
||||
// audience field should always be set to the GCP project id.
|
||||
const token = {
|
||||
'iat': parseInt(Date.now() / 1000),
|
||||
'exp': parseInt(Date.now() / 1000) + 20 * 60, // 20 minutes
|
||||
'aud': projectId
|
||||
};
|
||||
const privateKey = fs.readFileSync(privateKeyFile);
|
||||
return jwt.sign(token, privateKey, { algorithm: algorithm });
|
||||
}
|
||||
// [END iot_mqtt_jwt]
|
||||
|
||||
// Mock some data
|
||||
var mockData = function () {
|
||||
var load = os.loadavg();
|
||||
var msg = {
|
||||
'source_id': "next18-demo-client",
|
||||
'event_id': uuid.v4(),
|
||||
'event_ts': new Date().getTime(),
|
||||
'metric': Math.floor(Math.random() * 10) + 1
|
||||
};
|
||||
console.dir(msg);
|
||||
return Buffer.from(JSON.stringify(msg)).toString('base64');
|
||||
}
|
||||
|
||||
// Publish numMessages messages asynchronously, starting from message
|
||||
// messagesSent.
|
||||
// [START iot_mqtt_publish]
|
||||
function publishAsync(messagesSent, numMessages) {
|
||||
// If we have published enough messages or backed off too many times, stop.
|
||||
if (messagesSent > numMessages || backoffTime >= MAXIMUM_BACKOFF_TIME) {
|
||||
if (backoffTime >= MAXIMUM_BACKOFF_TIME) {
|
||||
console.log('Backoff time is too high. Giving up.');
|
||||
}
|
||||
console.log('Closing connection to MQTT. Goodbye!');
|
||||
client.end();
|
||||
publishChainInProgress = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Publish and schedule the next publish.
|
||||
publishChainInProgress = true;
|
||||
var publishDelayMs = 0;
|
||||
if (shouldBackoff) {
|
||||
publishDelayMs = 1000 * (backoffTime + Math.random());
|
||||
backoffTime *= 2;
|
||||
console.log(`Backing off for ${publishDelayMs}ms before publishing.`);
|
||||
}
|
||||
|
||||
setTimeout(function () {
|
||||
|
||||
// const payload = `${argv.registryId}/${argv.deviceId}-payload-${messagesSent}`;
|
||||
|
||||
const payload = mockData();
|
||||
|
||||
// Publish "payload" to the MQTT topic. qos=1 means at least once delivery.
|
||||
// Cloud IoT Core also supports qos=0 for at most once delivery.
|
||||
console.log('Publishing message:', payload);
|
||||
client.publish(mqttTopic, payload, { qos: 1 }, function (err) {
|
||||
if (!err) {
|
||||
shouldBackoff = false;
|
||||
backoffTime = MINIMUM_BACKOFF_TIME;
|
||||
}
|
||||
});
|
||||
|
||||
var schedulePublishDelayMs = argv.messageType === 'events' ? 1000 : 2000;
|
||||
setTimeout(function () {
|
||||
// [START iot_mqtt_jwt_refresh]
|
||||
let secsFromIssue = parseInt(Date.now() / 1000) - iatTime;
|
||||
if (secsFromIssue > argv.tokenExpMins * 60) {
|
||||
iatTime = parseInt(Date.now() / 1000);
|
||||
console.log(`\tRefreshing token after ${secsFromIssue} seconds.`);
|
||||
|
||||
client.end();
|
||||
connectionArgs.password = createJwt(argv.projectId, argv.privateKeyFile, argv.algorithm);
|
||||
client = mqtt.connect(connectionArgs);
|
||||
|
||||
client.on('connect', (success) => {
|
||||
console.log('connect');
|
||||
if (!success) {
|
||||
console.log('Client not connected...');
|
||||
} else if (!publishChainInProgress) {
|
||||
publishAsync(1, argv.numMessages);
|
||||
}
|
||||
});
|
||||
|
||||
client.on('close', () => {
|
||||
console.log('close');
|
||||
shouldBackoff = true;
|
||||
});
|
||||
|
||||
client.on('error', (err) => {
|
||||
console.log('error', err);
|
||||
});
|
||||
|
||||
client.on('message', (topic, message, packet) => {
|
||||
console.log('message received: ', Buffer.from(message, 'base64').toString('ascii'));
|
||||
});
|
||||
|
||||
client.on('packetsend', () => {
|
||||
// Note: logging packet send is very verbose
|
||||
});
|
||||
}
|
||||
// [END iot_mqtt_jwt_refresh]
|
||||
publishAsync(messagesSent + 1, numMessages);
|
||||
}, schedulePublishDelayMs);
|
||||
}, publishDelayMs);
|
||||
}
|
||||
// [END iot_mqtt_publish]
|
||||
|
||||
// [START iot_mqtt_run]
|
||||
// The mqttClientId is a unique string that identifies this device. For Google
|
||||
// Cloud IoT Core, it must be in the format below.
|
||||
const mqttClientId = `projects/${argv.projectId}/locations/${argv.cloudRegion}/registries/${argv.registryId}/devices/${argv.deviceId}`;
|
||||
|
||||
// With Google Cloud IoT Core, the username field is ignored, however it must be
|
||||
// non-empty. The password field is used to transmit a JWT to authorize the
|
||||
// device. The "mqtts" protocol causes the library to connect using SSL, which
|
||||
// is required for Cloud IoT Core.
|
||||
let connectionArgs = {
|
||||
host: argv.mqttBridgeHostname,
|
||||
port: argv.mqttBridgePort,
|
||||
clientId: mqttClientId,
|
||||
username: 'unused',
|
||||
password: createJwt(argv.projectId, argv.privateKeyFile, argv.algorithm),
|
||||
protocol: 'mqtts',
|
||||
secureProtocol: 'TLSv1_2_method'
|
||||
};
|
||||
|
||||
// Create a client, and connect to the Google MQTT bridge.
|
||||
let iatTime = parseInt(Date.now() / 1000);
|
||||
let client = mqtt.connect(connectionArgs);
|
||||
|
||||
// Subscribe to the /devices/{device-id}/config topic to receive config updates.
|
||||
client.subscribe(`/devices/${argv.deviceId}/config`);
|
||||
|
||||
// The MQTT topic that this device will publish data to. The MQTT
|
||||
// topic name is required to be in the format below. The topic name must end in
|
||||
// 'state' to publish state and 'events' to publish telemetry. Note that this is
|
||||
// not the same as the device registry's Cloud Pub/Sub topic.
|
||||
const mqttTopic = `/devices/${argv.deviceId}/${argv.messageType}`;
|
||||
|
||||
client.on('connect', (success) => {
|
||||
console.log('connect');
|
||||
if (!success) {
|
||||
console.log('Client not connected...');
|
||||
} else if (!publishChainInProgress) {
|
||||
publishAsync(1, argv.numMessages);
|
||||
}
|
||||
});
|
||||
|
||||
client.on('close', () => {
|
||||
console.log('close');
|
||||
shouldBackoff = true;
|
||||
});
|
||||
|
||||
client.on('error', (err) => {
|
||||
console.log('error', err);
|
||||
});
|
||||
|
||||
client.on('message', (topic, message, packet) => {
|
||||
console.log('message received: ', Buffer.from(message, 'base64').toString('ascii'));
|
||||
});
|
||||
|
||||
client.on('packetsend', () => {
|
||||
// Note: logging packet send is very verbose
|
||||
});
|
||||
|
||||
// Once all of the messages have been published, the connection to Google Cloud
|
||||
// IoT will be closed and the process will exit. See the publishAsync method.
|
||||
// [END iot_mqtt_run]
|
|
@ -1,25 +0,0 @@
|
|||
# Copyright 2018 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: feeds.knative.dev/v1alpha1
|
||||
kind: EventSource
|
||||
metadata:
|
||||
name: gcppubsub
|
||||
namespace: default
|
||||
spec:
|
||||
type: gcppubsub
|
||||
source: gcppubsub
|
||||
image: github.com/knative/eventing/pkg/sources/gcppubsub
|
||||
parameters:
|
||||
image: github.com/knative/eventing/pkg/sources/gcppubsub/receive_adapter
|
|
@ -1,22 +0,0 @@
|
|||
# Copyright 2018 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: feeds.knative.dev/v1alpha1
|
||||
kind: EventType
|
||||
metadata:
|
||||
name: receive
|
||||
namespace: default
|
||||
spec:
|
||||
eventSource: gcppubsub
|
||||
description: "subscription for receiving pubsub messages"
|
|
@ -1,34 +0,0 @@
|
|||
# Copyright 2018 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: flows.knative.dev/v1alpha1
|
||||
kind: Flow
|
||||
metadata:
|
||||
name: iot-example
|
||||
namespace: default
|
||||
spec:
|
||||
serviceAccountName: binder
|
||||
trigger:
|
||||
service: gcppubsub
|
||||
eventType: receive
|
||||
resource: gcppubsub/receive
|
||||
parameters:
|
||||
projectID: s9-demo
|
||||
topic: iot-demo
|
||||
action:
|
||||
target:
|
||||
kind: Route
|
||||
apiVersion: serving.knative.dev/v1alpha1
|
||||
name: iot-function
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
/*
|
||||
Copyright 2018 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.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Event represents PubSub payload
|
||||
type Event struct {
|
||||
ID string `json:"ID"`
|
||||
Data string `json:"Data"`
|
||||
Attributes map[string]string `json:"Attributes"`
|
||||
}
|
||||
|
||||
// EventPayload represents PubSub Data payload
|
||||
type EventPayload struct {
|
||||
ID string `json:"event_id"`
|
||||
SourceID string `json:"source_id"`
|
||||
SentOn int `json:"event_ts"`
|
||||
Metric int `json:"metric"`
|
||||
}
|
||||
|
||||
func handlePost(rw http.ResponseWriter, req *http.Request) {
|
||||
|
||||
body, err := ioutil.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
//log.Println(string(body))
|
||||
|
||||
// decode the pubsub message
|
||||
// var event map[string]string
|
||||
var event Event
|
||||
if err := json.Unmarshal(body, &event); err != nil {
|
||||
log.Printf("Failed to unmarshal event: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
// decode pubsub payload
|
||||
rawEvent, _ := base64.StdEncoding.DecodeString(event.Data)
|
||||
|
||||
// decode iot data
|
||||
data, _ := base64.StdEncoding.DecodeString(string(rawEvent))
|
||||
|
||||
// decode the pubsub message payload
|
||||
var payload EventPayload
|
||||
if err := json.Unmarshal(data, &payload); err != nil {
|
||||
log.Printf("Failed to unmarshal payload: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("Data sent by device %q: [metric: %d, on: %v]",
|
||||
event.Attributes["deviceId"], payload.Metric, payload.SentOn)
|
||||
}
|
||||
|
||||
func main() {
|
||||
http.HandleFunc("/", handlePost)
|
||||
log.Fatal(http.ListenAndServe(":8080", nil))
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
# Copyright 2018 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/v1alpha1
|
||||
kind: Route
|
||||
metadata:
|
||||
name: iot-function
|
||||
namespace: default
|
||||
spec:
|
||||
traffic:
|
||||
- configurationName: iot-function
|
||||
percent: 100
|
|
@ -1,18 +0,0 @@
|
|||
# Copyright 2018 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.
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: binder
|
||||
namespace: default
|
|
@ -1,25 +0,0 @@
|
|||
# Copyright 2018 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.
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: bind-admin
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: binder
|
||||
namespace: default
|
||||
roleRef:
|
||||
kind: ClusterRole
|
||||
name: cluster-admin
|
||||
apiGroup: rbac.authorization.k8s.io
|
|
@ -1,27 +0,0 @@
|
|||
# Copyright 2018 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 golang AS builder
|
||||
|
||||
WORKDIR /go/src/github.com/knative/docs/
|
||||
ADD . /go/src/github.com/knative/docs/
|
||||
|
||||
RUN CGO_ENABLED=0 go build ./eventing/samples/github-events
|
||||
|
||||
FROM gcr.io/distroless/base
|
||||
|
||||
COPY --from=builder /go/src/github.com/knative/docs/github-events /sample
|
||||
|
||||
ENTRYPOINT ["/sample"]
|
||||
EXPOSE 8080
|
|
@ -1,181 +0,0 @@
|
|||
# Reacting to GitHub Events
|
||||
|
||||
In response to a pull request event, the sample app _legit_ Service will add
|
||||
`(looks pretty legit)` to the PR title.
|
||||
|
||||
A GitHub webhook will be created on a repository and a Knative `Service` will be
|
||||
deployed to receive the webhook's event deliveries and forward them into a
|
||||
`Channel`, through a `Bus`, and out to the consumer via a `Subscription`. The
|
||||
`Flow` resource takes care of provisioning the webhook, the `Service`, the
|
||||
`Channel`, and the `Subscription`.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
You will need:
|
||||
|
||||
- A Kubernetes cluster with Knative serving installed. Follow the
|
||||
[installation instructions](https://github.com/knative/docs/blob/master/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 (you'll use it for a container registry).
|
||||
- Knative eventing core installed on your Kubernetes cluster. You can install
|
||||
with:
|
||||
```shell
|
||||
kubectl apply --filename https://storage.googleapis.com/knative-releases/eventing/latest/release.yaml
|
||||
```
|
||||
- A domain name that allows GitHub to call into the cluster: Follow the
|
||||
[assign a static IP address](https://github.com/knative/docs/blob/master/serving/gke-assigning-static-ip-address.md)
|
||||
and
|
||||
[configure a custom domain](https://github.com/knative/docs/blob/master/serving/using-a-custom-domain.md)
|
||||
instructions.
|
||||
|
||||
## Configuring Knative
|
||||
|
||||
To use this sample, you'll need to install the `stub` ClusterBus and the
|
||||
`github` EventSource:
|
||||
|
||||
```shell
|
||||
# Installs ClusterBus
|
||||
kubectl apply --filename https://storage.googleapis.com/knative-releases/eventing/latest/release-clusterbus-stub.yaml
|
||||
# Installs EventSource
|
||||
kubectl apply --filename https://storage.googleapis.com/knative-releases/eventing/latest/release-source-github.yaml
|
||||
```
|
||||
|
||||
## Granting permissions
|
||||
|
||||
Because the `github` EventSource needs to create a Knative Service, you'll need
|
||||
to provision a special ServiceAccount with the necessary permissions.
|
||||
|
||||
The `auth.yaml` file provisions a service
|
||||
account, and creates a role which can create a Knative Service in the `default`
|
||||
namespace. In a production environment, you might want to limit the access of
|
||||
this service account to only specific namespaces.
|
||||
|
||||
```shell
|
||||
kubectl apply --filename auth.yaml
|
||||
```
|
||||
|
||||
## Building and deploying the sample
|
||||
|
||||
1. Create a [personal access token](https://github.com/settings/tokens) to
|
||||
GitHub repo that the GitHub source can use to register webhooks with the
|
||||
GitHub API. Also decide on a token that your code will use to authenticate
|
||||
the incoming webhooks from GitHub (*accessToken*).
|
||||
|
||||
The token can be named anything you find convenient. This sample requires
|
||||
full `repo` control to be able update the title of the _Pull Request_.
|
||||
The Source requires `admin:repo_hook`, this allows it to create webhooks
|
||||
into repos that your account is allowed to do so. Copy and save this token;
|
||||
GitHub will force you to generate it again if misplaced.
|
||||
|
||||
Here I named my token "EventingSample" and have selected the recommended
|
||||
scopes:
|
||||
|
||||

|
||||
|
||||
Update `githubsecret.yaml` with those
|
||||
values. If your generated access token is `'asdfasfdsaf'` and you choose
|
||||
your *secretToken* as `'personal_access_token_value'`, you'd modify
|
||||
`githubsecret.yaml` like so:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: githubsecret
|
||||
type: Opaque
|
||||
stringData:
|
||||
githubCredentials: >
|
||||
{
|
||||
"accessToken": "asdfasfdsaf",
|
||||
"secretToken": "personal_access_token_value"
|
||||
}
|
||||
```
|
||||
|
||||
Hint: you can makeup a random *accessToken* with:
|
||||
|
||||
```shell
|
||||
head -c 8 /dev/urandom | base64
|
||||
```
|
||||
|
||||
Then, apply the githubsecret using `kubectl`:
|
||||
|
||||
```shell
|
||||
kubectl apply --filename githubsecret.yaml
|
||||
```
|
||||
|
||||
1. Use Docker to build the sample code into a container. To build and push with
|
||||
Docker Hub, run the following commands, replacing `{username}` with your
|
||||
Docker Hub username. Run the following commands from the _root_ directory of
|
||||
the `knative/docs` repo:
|
||||
|
||||
```shell
|
||||
# Build the container on your local machine
|
||||
# Note: The relative path points to the _root_ of the `knative/docs` repo
|
||||
docker build -t {username}/github-events --file=Dockerfile ../../../
|
||||
|
||||
# Push the container to docker registry
|
||||
docker push {username}/github-events
|
||||
```
|
||||
|
||||
1. After the build has completed and the container is pushed to Docker Hub, you
|
||||
can deploy the function into your cluster. **Ensure that the container image
|
||||
value in `function.yaml` matches the container you built in the previous
|
||||
step.** Apply the configuration using `kubectl`:
|
||||
|
||||
```shell
|
||||
kubectl apply --filename function.yaml
|
||||
```
|
||||
|
||||
1. Check that your service is running using:
|
||||
|
||||
```shell
|
||||
kubectl get ksvc --output "custom-columns=NAME:.metadata.name,READY:.status.conditions[2].status,REASON:.status.conditions[2].message"
|
||||
NAME READY REASON
|
||||
legit True <none>
|
||||
```
|
||||
|
||||
> Note: `ksvc` is an alias for `services.serving.knative.dev`. If you have
|
||||
an older version (version 0.1.0) of Knative installed, you'll need to use
|
||||
the long name until you upgrade to version 0.1.1 or higher. See
|
||||
[Checking Knative Installation Version](../../../install/check-install-version.md)
|
||||
to learn how to see what version you have installed.
|
||||
|
||||
1. Update the resource inside `flow.yaml` to the
|
||||
org/repo of your choosing. Note that the personal access token must be valid
|
||||
for the chosen org/repo.
|
||||
|
||||
Then create the flow sending GitHub Events to the service:
|
||||
|
||||
```shell
|
||||
kubectl apply --filename flow.yaml
|
||||
```
|
||||
|
||||
1. Create a PR for the repo you configured the webhook for, and you'll see that
|
||||
the Title will be modified with the suffix `(looks pretty legit)`
|
||||
|
||||
|
||||
## Understanding what happened
|
||||
|
||||
`TODO: similar to k8s-events.`
|
||||
|
||||
<!--TODO:
|
||||
explain the resources and communication channels, as well as where the secret
|
||||
is used. In particular include a note to look at
|
||||
https://github.com/<owner>/<repo>/settings/hooks to see the webhook registered
|
||||
and then deleted.
|
||||
-->
|
||||
|
||||
## Cleaning up
|
||||
|
||||
To clean up the function, `Flow`, auth, and secret:
|
||||
|
||||
```shell
|
||||
kubectl delete --filename function.yaml
|
||||
kubectl delete --filename flow.yaml
|
||||
kubectl delete --filename auth.yaml
|
||||
kubectl delete --filename githubsecret.yaml
|
||||
```
|
||||
|
||||
And then delete the [personal access token](https://github.com/settings/tokens)
|
||||
created from GitHub.
|
|
@ -1,43 +0,0 @@
|
|||
# Copyright 2018 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.
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: feed-sa
|
||||
namespace: default
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: create-knative-service
|
||||
namespace: default
|
||||
rules:
|
||||
- apiGroups: ["serving.knative.dev"]
|
||||
resources: ["services"]
|
||||
verbs: ["get", "list", "watch", "create", "update", "delete", "patch"]
|
||||
---
|
||||
# This enables the feed-sa to deploy the receive adapter.
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: feed-sa-deploy
|
||||
namespace: default
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: feed-sa
|
||||
namespace: default
|
||||
roleRef:
|
||||
kind: Role
|
||||
name: create-knative-service
|
||||
apiGroup: rbac.authorization.k8s.io
|
|
@ -1,37 +0,0 @@
|
|||
# Copyright 2018 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: flows.knative.dev/v1alpha1
|
||||
kind: Flow
|
||||
metadata:
|
||||
name: github-flow
|
||||
namespace: default
|
||||
spec:
|
||||
serviceAccountName: feed-sa
|
||||
trigger:
|
||||
eventType: dev.knative.github.pullrequest
|
||||
resource: <org>/<repo> # TODO: update this
|
||||
service: github
|
||||
parameters:
|
||||
secretName: githubsecret
|
||||
secretKey: githubCredentials
|
||||
parametersFrom:
|
||||
- secretKeyRef:
|
||||
name: githubsecret
|
||||
key: githubCredentials
|
||||
action:
|
||||
target:
|
||||
kind: Service
|
||||
apiVersion: serving.knative.dev/v1alpha1
|
||||
name: legit
|
|
@ -1,106 +0,0 @@
|
|||
/*
|
||||
Copyright 2018 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.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
ghclient "github.com/google/go-github/github"
|
||||
"github.com/knative/eventing/pkg/event"
|
||||
"golang.org/x/oauth2"
|
||||
"gopkg.in/go-playground/webhooks.v3/github"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
// Environment variable containing json credentials
|
||||
envSecret = "GITHUB_SECRET"
|
||||
// this is what we tack onto each PR title if not there already
|
||||
titleSuffix = "looks pretty legit"
|
||||
)
|
||||
|
||||
// GithubHandler holds necessary objects for communicating with the Github.
|
||||
type GithubHandler struct {
|
||||
client *ghclient.Client
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
type GithubSecrets struct {
|
||||
AccessToken string `json:"accessToken"`
|
||||
SecretToken string `json:"secretToken"`
|
||||
}
|
||||
|
||||
func (h *GithubHandler) newPullRequestPayload(ctx context.Context, pl *github.PullRequestPayload) {
|
||||
|
||||
title := pl.PullRequest.Title
|
||||
log.Printf("GOT PR with Title: %q", title)
|
||||
|
||||
// Check the title and if it contains 'looks pretty legit' leave it alone
|
||||
if strings.Contains(title, titleSuffix) {
|
||||
// already modified, leave it alone.
|
||||
return
|
||||
}
|
||||
|
||||
newTitle := fmt.Sprintf("%s (%s)", title, titleSuffix)
|
||||
updatedPR := ghclient.PullRequest{
|
||||
Title: &newTitle,
|
||||
}
|
||||
newPR, response, err := h.client.PullRequests.Edit(h.ctx,
|
||||
pl.Repository.Owner.Login, pl.Repository.Name, int(pl.Number), &updatedPR)
|
||||
if err != nil {
|
||||
log.Printf("Failed to update PR: %s\n%s", err, response)
|
||||
return
|
||||
}
|
||||
if newPR.Title != nil {
|
||||
log.Printf("New PR Title: %q", *newPR.Title)
|
||||
} else {
|
||||
log.Printf("New PR title is nil")
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
githubSecrets := os.Getenv(envSecret)
|
||||
|
||||
var credentials GithubSecrets
|
||||
err := json.Unmarshal([]byte(githubSecrets), &credentials)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to unmarshal credentials: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Set up the auth for being able to talk to Github.
|
||||
ctx := context.Background()
|
||||
ts := oauth2.StaticTokenSource(
|
||||
&oauth2.Token{AccessToken: credentials.AccessToken},
|
||||
)
|
||||
tc := oauth2.NewClient(ctx, ts)
|
||||
|
||||
client := ghclient.NewClient(tc)
|
||||
|
||||
h := &GithubHandler{
|
||||
client: client,
|
||||
ctx: ctx,
|
||||
}
|
||||
|
||||
log.Fatal(http.ListenAndServe(":8080", event.Handler(h.newPullRequestPayload)))
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
# Copyright 2018 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/v1alpha1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: legit
|
||||
spec:
|
||||
runLatest:
|
||||
configuration:
|
||||
revisionTemplate:
|
||||
metadata:
|
||||
labels:
|
||||
knative.dev/type: function
|
||||
spec:
|
||||
container:
|
||||
image: docker.io/{username}/github-events # TODO: fill username out
|
||||
env:
|
||||
- name: GITHUB_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
key: githubCredentials
|
||||
name: githubsecret
|
|
@ -1,25 +0,0 @@
|
|||
# Copyright 2018 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: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: githubsecret
|
||||
type: Opaque
|
||||
stringData:
|
||||
githubCredentials: >
|
||||
{
|
||||
"accessToken": "<YOUR PERSONAL TOKEN FROM GITHUB>",
|
||||
"secretToken": "<YOUR RANDOM STRING>"
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 240 KiB |
Loading…
Reference in New Issue