From 8a8b9bf7d82c0c4c375f0125922b6e9ab5b7ca3f Mon Sep 17 00:00:00 2001 From: Wolfgang Nagele Date: Mon, 9 Dec 2013 21:45:15 +1100 Subject: [PATCH 1/7] Implementation for Amazon DynamoDB --- README.md | 2 ++ storage/ddb/69-ddbout.html | 72 ++++++++++++++++++++++++++++++++++++++ storage/ddb/69-ddbout.js | 45 ++++++++++++++++++++++++ 3 files changed, 119 insertions(+) create mode 100644 storage/ddb/69-ddbout.html create mode 100644 storage/ddb/69-ddbout.js diff --git a/README.md b/README.md index 5c150f4c..fa93915e 100644 --- a/README.md +++ b/README.md @@ -96,6 +96,8 @@ Uses a simple read of the serial port as a file to input data. You **must** set **68-mysql** - Allows basic access to a MySQL database. This node uses the **query** operation against the configured database. This does allow both INSERTS and DELETES. By it's very nature it allows SQL injection... *so be careful out there...* +**69-ddbout** - Support output to Amazon DynamoDB. + ### Time **79-suncalc** - Uses the suncalc module to generate an output at sunrise and sunset based on a specified location. Several choices of definition of sunrise and sunset are available, diff --git a/storage/ddb/69-ddbout.html b/storage/ddb/69-ddbout.html new file mode 100644 index 00000000..70235393 --- /dev/null +++ b/storage/ddb/69-ddbout.html @@ -0,0 +1,72 @@ + + + + + + + diff --git a/storage/ddb/69-ddbout.js b/storage/ddb/69-ddbout.js new file mode 100644 index 00000000..8f51576b --- /dev/null +++ b/storage/ddb/69-ddbout.js @@ -0,0 +1,45 @@ +/** + * Copyright 2013 Wolfgang Nagele + * + * 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. + **/ + +var RED = require(process.env.NODE_RED_HOME+"/red/red"); +var util = require("util"); +var aws = require("aws-sdk"); +var attrWrapper = require("dynamodb-data-types").AttributeValue; + +function DDBOutNode(n) { + RED.nodes.createNode(this, n); + this.accessKey = n.accessKey; + this.secretAccessKey = n.secretAccessKey; + this.region = n.region || "us-east-1"; + this.table = n.table; + + aws.config.update({ accessKeyId: this.accessKey, + secretAccessKey: this.secretAccessKey, + region: this.region }); + + var ddb = new aws.DynamoDB(); + + this.on("input", function(msg) { + if (msg != null) { + ddb.putItem({ "TableName": this.table, + "Item": attrWrapper.wrap(msg.payload) }, + function(err, data) { + err && util.log(err); + }); + } + }); +} +RED.nodes.registerType("ddb out", DDBOutNode); From 17a040adfe3103200da5b2336584683401a35a57 Mon Sep 17 00:00:00 2001 From: Wolfgang Nagele Date: Thu, 19 Dec 2013 13:07:40 +1100 Subject: [PATCH 2/7] Support external credentials Add base node with credentials --- storage/ddb/69-ddbout.html | 65 +++++++++++++++++++++++++++++++++----- storage/ddb/69-ddbout.js | 55 +++++++++++++++++++++++++++++--- 2 files changed, 108 insertions(+), 12 deletions(-) diff --git a/storage/ddb/69-ddbout.html b/storage/ddb/69-ddbout.html index 70235393..33b5463e 100644 --- a/storage/ddb/69-ddbout.html +++ b/storage/ddb/69-ddbout.html @@ -16,12 +16,8 @@ + + + + diff --git a/storage/ddb/69-ddbout.js b/storage/ddb/69-ddbout.js index 8f51576b..8cf0d753 100644 --- a/storage/ddb/69-ddbout.js +++ b/storage/ddb/69-ddbout.js @@ -16,18 +16,65 @@ var RED = require(process.env.NODE_RED_HOME+"/red/red"); var util = require("util"); +var querystring = require('querystring'); var aws = require("aws-sdk"); var attrWrapper = require("dynamodb-data-types").AttributeValue; +function DDBNode(n) { + RED.nodes.createNode(this, n); + var credentials = RED.nodes.getCredentials(n.id); + if (credentials) { + this.accessKey = credentials.accessKey; + this.secretAccessKey = credentials.secretAccessKey; + } +} +RED.nodes.registerType("awscredentials", DDBNode); + +RED.app.get('/awscredentials/:id', function(req, res) { + var credentials = RED.nodes.getCredentials(req.params.id); + if (credentials) { + res.send(JSON.stringify({ accessKey: credentials.accessKey, secretAccessKey: credentials.secretAccessKey })); + } else { + res.send(JSON.stringify({})); + } +}); + +RED.app.delete('/awscredentials/:id', function(req, res) { + RED.nodes.deleteCredentials(req.params.id); + res.send(200); +}); + +RED.app.post('/awscredentials/:id', function(req, res) { + var body = ""; + req.on("data", function(chunk) { + body += chunk; + }); + req.on("end", function() { + var newCreds = querystring.parse(body); + var credentials = RED.nodes.getCredentials(req.params.id) || {}; + if (newCreds.accessKey == null || newCreds.accessKey == "") { + delete credentials.accessKey; + } else { + credentials.accessKey = newCreds.accessKey || credentials.accessKey; + } + if (newCreds.secretAccessKey == null || newCreds.secretAccessKey == "") { + delete credentials.secretAccessKey; + } else { + credentials.secretAccessKey = newCreds.secretAccessKey || credentials.secretAccessKey; + } + RED.nodes.addCredentials(req.params.id, credentials); + res.send(200); + }); +}); + function DDBOutNode(n) { RED.nodes.createNode(this, n); - this.accessKey = n.accessKey; - this.secretAccessKey = n.secretAccessKey; + this.credentials = RED.nodes.getNode(n.credentials); this.region = n.region || "us-east-1"; this.table = n.table; - aws.config.update({ accessKeyId: this.accessKey, - secretAccessKey: this.secretAccessKey, + aws.config.update({ accessKeyId: this.credentials.accessKey, + secretAccessKey: this.credentials.secretAccessKey, region: this.region }); var ddb = new aws.DynamoDB(); From 243fc9ffd4da4de5e73d2252aba892abb18581e5 Mon Sep 17 00:00:00 2001 From: Wolfgang Nagele Date: Sat, 21 Dec 2013 18:44:50 +0100 Subject: [PATCH 3/7] Setting defaults with credentials fields persists them in the flows file. Fixed. --- storage/ddb/69-ddbout.html | 4 ---- 1 file changed, 4 deletions(-) diff --git a/storage/ddb/69-ddbout.html b/storage/ddb/69-ddbout.html index 33b5463e..dfe8dac0 100644 --- a/storage/ddb/69-ddbout.html +++ b/storage/ddb/69-ddbout.html @@ -80,10 +80,6 @@ + + diff --git a/lib/aws.js b/lib/aws.js new file mode 100644 index 00000000..9997b676 --- /dev/null +++ b/lib/aws.js @@ -0,0 +1,65 @@ +/** + * Copyright 2013 Wolfgang Nagele + * + * 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. + **/ + +var RED = require(process.env.NODE_RED_HOME+"/red/red"); +var querystring = require('querystring'); + +function AWSCredentialsNode(n) { + RED.nodes.createNode(this, n); + var credentials = RED.nodes.getCredentials(n.id); + if (credentials) { + this.accessKey = credentials.accessKey; + this.secretAccessKey = credentials.secretAccessKey; + } +} +RED.nodes.registerType("aws credentials", AWSCredentialsNode); + +RED.app.get('/aws-credentials/:id', function(req, res) { + var credentials = RED.nodes.getCredentials(req.params.id); + if (credentials) { + res.send(JSON.stringify({ accessKey: credentials.accessKey, secretAccessKey: credentials.secretAccessKey })); + } else { + res.send(JSON.stringify({})); + } +}); + +RED.app.delete('/aws-credentials/:id', function(req, res) { + RED.nodes.deleteCredentials(req.params.id); + res.send(200); +}); + +RED.app.post('/aws-credentials/:id', function(req, res) { + var body = ""; + req.on("data", function(chunk) { + body += chunk; + }); + req.on("end", function() { + var newCreds = querystring.parse(body); + var credentials = RED.nodes.getCredentials(req.params.id) || {}; + if (newCreds.accessKey == null || newCreds.accessKey == "") { + delete credentials.accessKey; + } else { + credentials.accessKey = newCreds.accessKey || credentials.accessKey; + } + if (newCreds.secretAccessKey == null || newCreds.secretAccessKey == "") { + delete credentials.secretAccessKey; + } else { + credentials.secretAccessKey = newCreds.secretAccessKey || credentials.secretAccessKey; + } + RED.nodes.addCredentials(req.params.id, credentials); + res.send(200); + }); +}); diff --git a/storage/ddb/69-ddbout.html b/storage/ddb/69-ddbout.html index dfe8dac0..4262ea5a 100644 --- a/storage/ddb/69-ddbout.html +++ b/storage/ddb/69-ddbout.html @@ -51,7 +51,7 @@ category: "storage-output", color: "#ffaaaa", defaults: { - credentials: { type: "awscredentials", required: true }, + credentials: { type: "aws credentials", required: true }, region: { value: "us-east-1" }, table: { value: "", required: true }, name: { value: "" } @@ -65,53 +65,3 @@ } }); - - - - diff --git a/storage/ddb/69-ddbout.js b/storage/ddb/69-ddbout.js index 8cf0d753..3a9120d5 100644 --- a/storage/ddb/69-ddbout.js +++ b/storage/ddb/69-ddbout.js @@ -15,58 +15,11 @@ **/ var RED = require(process.env.NODE_RED_HOME+"/red/red"); +require("../../lib/aws"); var util = require("util"); -var querystring = require('querystring'); var aws = require("aws-sdk"); var attrWrapper = require("dynamodb-data-types").AttributeValue; -function DDBNode(n) { - RED.nodes.createNode(this, n); - var credentials = RED.nodes.getCredentials(n.id); - if (credentials) { - this.accessKey = credentials.accessKey; - this.secretAccessKey = credentials.secretAccessKey; - } -} -RED.nodes.registerType("awscredentials", DDBNode); - -RED.app.get('/awscredentials/:id', function(req, res) { - var credentials = RED.nodes.getCredentials(req.params.id); - if (credentials) { - res.send(JSON.stringify({ accessKey: credentials.accessKey, secretAccessKey: credentials.secretAccessKey })); - } else { - res.send(JSON.stringify({})); - } -}); - -RED.app.delete('/awscredentials/:id', function(req, res) { - RED.nodes.deleteCredentials(req.params.id); - res.send(200); -}); - -RED.app.post('/awscredentials/:id', function(req, res) { - var body = ""; - req.on("data", function(chunk) { - body += chunk; - }); - req.on("end", function() { - var newCreds = querystring.parse(body); - var credentials = RED.nodes.getCredentials(req.params.id) || {}; - if (newCreds.accessKey == null || newCreds.accessKey == "") { - delete credentials.accessKey; - } else { - credentials.accessKey = newCreds.accessKey || credentials.accessKey; - } - if (newCreds.secretAccessKey == null || newCreds.secretAccessKey == "") { - delete credentials.secretAccessKey; - } else { - credentials.secretAccessKey = newCreds.secretAccessKey || credentials.secretAccessKey; - } - RED.nodes.addCredentials(req.params.id, credentials); - res.send(200); - }); -}); - function DDBOutNode(n) { RED.nodes.createNode(this, n); this.credentials = RED.nodes.getNode(n.credentials); From 4e20f70bfde35b31427f36ca1231322252f69985 Mon Sep 17 00:00:00 2001 From: Wolfgang Nagele Date: Sun, 22 Dec 2013 08:48:02 +0100 Subject: [PATCH 5/7] Leave region selection open so new regions are quicker to use. --- storage/ddb/69-ddbout.html | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/storage/ddb/69-ddbout.html b/storage/ddb/69-ddbout.html index 4262ea5a..3f0859bd 100644 --- a/storage/ddb/69-ddbout.html +++ b/storage/ddb/69-ddbout.html @@ -21,16 +21,7 @@
- +
@@ -52,7 +43,7 @@ color: "#ffaaaa", defaults: { credentials: { type: "aws credentials", required: true }, - region: { value: "us-east-1" }, + region: { value: "us-east-1", required: true }, table: { value: "", required: true }, name: { value: "" } }, From 5342637132108a6914f99c2960088d72edadc0ee Mon Sep 17 00:00:00 2001 From: Wolfgang Nagele Date: Tue, 24 Dec 2013 17:21:22 +0100 Subject: [PATCH 6/7] Need to retain the accessKey defaults to be able to show them in the UI --- lib/aws.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/aws.html b/lib/aws.html index da463c52..5c26c904 100644 --- a/lib/aws.html +++ b/lib/aws.html @@ -31,6 +31,9 @@ label: function() { return this.accessKey; }, + defaults: { + accessKey: { value: "", required: true } + }, oneditprepare: function() { $.getJSON("aws-credentials/" + this.id, function(data) { if (data.accessKey) { From efb9fbb92b10dee2d8c93b0f9a29745db8970f46 Mon Sep 17 00:00:00 2001 From: Wolfgang Nagele Date: Sun, 2 Feb 2014 21:52:08 +1100 Subject: [PATCH 7/7] Move AWS credentials to DDB node --- storage/ddb/69-ddbout.js | 1 - {lib => storage/ddb}/aws.html | 0 {lib => storage/ddb}/aws.js | 0 3 files changed, 1 deletion(-) rename {lib => storage/ddb}/aws.html (100%) rename {lib => storage/ddb}/aws.js (100%) diff --git a/storage/ddb/69-ddbout.js b/storage/ddb/69-ddbout.js index 3a9120d5..939d7d23 100644 --- a/storage/ddb/69-ddbout.js +++ b/storage/ddb/69-ddbout.js @@ -15,7 +15,6 @@ **/ var RED = require(process.env.NODE_RED_HOME+"/red/red"); -require("../../lib/aws"); var util = require("util"); var aws = require("aws-sdk"); var attrWrapper = require("dynamodb-data-types").AttributeValue; diff --git a/lib/aws.html b/storage/ddb/aws.html similarity index 100% rename from lib/aws.html rename to storage/ddb/aws.html diff --git a/lib/aws.js b/storage/ddb/aws.js similarity index 100% rename from lib/aws.js rename to storage/ddb/aws.js