From 324ee36fe31763e507b422ab0a88e4230045e205 Mon Sep 17 00:00:00 2001 From: "Timoney, Daniel (dt5972)" Date: Wed, 15 Feb 2017 10:37:53 -0500 Subject: Initial commit for OpenECOMP SDN-C OA&M Change-Id: I7ab579fd0d206bf356f36d52dcdf4f71f1fa2680 Signed-off-by: Timoney, Daniel (dt5972) Former-commit-id: 2a9f0edd09581f907e62ec4689b5ac94dd5382ba --- dgbuilder/red/nodes/Node.js | 147 ++++++++ dgbuilder/red/nodes/credentials.js | 208 +++++++++++ dgbuilder/red/nodes/flows.js | 220 ++++++++++++ dgbuilder/red/nodes/index.js | 134 +++++++ dgbuilder/red/nodes/registry.js | 693 +++++++++++++++++++++++++++++++++++++ 5 files changed, 1402 insertions(+) create mode 100644 dgbuilder/red/nodes/Node.js create mode 100644 dgbuilder/red/nodes/credentials.js create mode 100644 dgbuilder/red/nodes/flows.js create mode 100644 dgbuilder/red/nodes/index.js create mode 100644 dgbuilder/red/nodes/registry.js (limited to 'dgbuilder/red/nodes') diff --git a/dgbuilder/red/nodes/Node.js b/dgbuilder/red/nodes/Node.js new file mode 100644 index 00000000..0e6fc525 --- /dev/null +++ b/dgbuilder/red/nodes/Node.js @@ -0,0 +1,147 @@ +/** + * Copyright 2014 IBM Corp. + * + * 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 util = require("util"); +var EventEmitter = require("events").EventEmitter; +var clone = require("clone"); +var when = require("when"); + +var flows = require("./flows"); +var comms = require("../comms"); + +function Node(n) { + this.id = n.id; + flows.add(this); + this.type = n.type; + if (n.name) { + this.name = n.name; + } + this.wires = n.wires||[]; +} + +util.inherits(Node,EventEmitter); + +Node.prototype._on = Node.prototype.on; + +Node.prototype.on = function(event,callback) { + var node = this; + if (event == "close") { + if (callback.length == 1) { + this.close = function() { + return when.promise(function(resolve) { + callback.call(node,function() { + resolve(); + }); + }); + } + } else { + this.close = callback; + } + } else { + this._on(event,callback); + } +} + +Node.prototype.close = function() { +} + +Node.prototype.send = function(msg) { + // instanceof doesn't work for some reason here + if (msg == null) { + return; + } else if (!util.isArray(msg)) { + msg = [msg]; + } + for (var i=0;i 0) { + var i = missingTypes.indexOf(type); + if (i != -1) { + missingTypes.splice(i,1); + util.log("[red] Missing type registered: "+type); + if (missingTypes.length === 0) { + parseConfig(); + } + } + } +}); + +/** + * Parses the current activeConfig and creates the required node instances + */ +function parseConfig() { + var i; + var nt; + missingTypes = []; + + // Scan the configuration for any unknown node types + for (i=0;i 0) { + util.log("[red] Waiting for missing types to be registered:"); + for (i=0;i 0) { + util.log("[red] Stopping flows"); + } + return flowNodes.clear(); +} + +var flowNodes = module.exports = { + init: function(_storage) { + storage = _storage; + }, + + /** + * Load the current activeConfig from storage and start it running + * @return a promise for the loading of the config + */ + load: function() { + return storage.getFlows().then(function(flows) { + return credentials.load().then(function() { + activeConfig = flows; + if (activeConfig && activeConfig.length > 0) { + parseConfig(); + } + }); + }).otherwise(function(err) { + util.log("[red] Error loading flows : "+err); + }); + }, + + /** + * Add a node to the current active set + * @param n the node to add + */ + add: function(n) { + nodes[n.id] = n; + n.on("log",log.log); + }, + + /** + * Get a node + * @param i the node id + * @return the node + */ + get: function(i) { + return nodes[i]; + }, + + /** + * Stops all active nodes and clears the active set + * @return a promise for the stopping of all active nodes + */ + clear: function() { + return when.promise(function(resolve) { + events.emit("nodes-stopping"); + var promises = []; + for (var n in nodes) { + if (nodes.hasOwnProperty(n)) { + try { + var p = nodes[n].close(); + if (p) { + promises.push(p); + } + } catch(err) { + nodes[n].error(err); + } + } + } + when.settle(promises).then(function() { + events.emit("nodes-stopped"); + nodes = {}; + resolve(); + }); + }); + }, + + /** + * Provides an iterator over the active set of nodes + * @param cb a function to be called for each node in the active set + */ + each: function(cb) { + for (var n in nodes) { + if (nodes.hasOwnProperty(n)) { + cb(nodes[n]); + } + } + }, + + /** + * @return the active configuration + */ + getFlows: function() { + return activeConfig; + }, + + /** + * Sets the current active config. + * @param config the configuration to enable + * @return a promise for the starting of the new flow + */ + setFlows: function (config) { + // Extract any credential updates + for (var i=0; i 0) { + var msg = nodesInUse.join(", "); + throw new Error("Type in use: "+msg); + } +} + +function removeNode(id) { + checkTypeInUse(id); + return registry.removeNode(id); +} + +function removeModule(module) { + var info = registry.getNodeModuleInfo(module); + for (var i=0;i -1) { + nodeList.splice(i,1); + } + config.types.forEach(function(t) { + delete nodeConstructors[t]; + delete nodeTypeToId[t]; + }); + config.enabled = false; + config.loaded = false; + nodeConfigCache = null; + return filterNodeInfo(config); + }, + removeModule: function(module) { + if (!settings.available()) { + throw new Error("Settings unavailable"); + } + var nodes = nodeModules[module]; + if (!nodes) { + throw new Error("Unrecognised module: "+module); + } + var infoList = []; + for (var i=0;i 0) { + result += ''; + } + nodeConfigCache = result; + } + return nodeConfigCache; + }, + + getNodeConfig: function(id) { + var config = nodeConfigs[id]; + if (config) { + var result = config.config; + if (config.script) { + result += ''; + } + return result; + } else { + return null; + } + }, + + getNodeConstructor: function(type) { + var config = nodeConfigs[nodeTypeToId[type]]; + if (!config || (config.enabled && !config.err)) { + return nodeConstructors[type]; + } + return null; + }, + + clear: function() { + nodeConfigCache = null; + nodeConfigs = {}; + nodeList = []; + nodeConstructors = {}; + nodeTypeToId = {}; + }, + + getTypeId: function(type) { + return nodeTypeToId[type]; + }, + + getModuleInfo: function(type) { + return nodeModules[type]; + }, + + enableNodeSet: function(id) { + if (!settings.available()) { + throw new Error("Settings unavailable"); + } + var config = nodeConfigs[id]; + if (config) { + delete config.err; + config.enabled = true; + if (!config.loaded) { + // TODO: honour the promise this returns + loadNodeModule(config); + } + nodeConfigCache = null; + saveNodeList(); + } else { + throw new Error("Unrecognised id: "+id); + } + return filterNodeInfo(config); + }, + + disableNodeSet: function(id) { + if (!settings.available()) { + throw new Error("Settings unavailable"); + } + var config = nodeConfigs[id]; + if (config) { + // TODO: persist setting + config.enabled = false; + nodeConfigCache = null; + saveNodeList(); + } else { + throw new Error("Unrecognised id: "+id); + } + return filterNodeInfo(config); + }, + + saveNodeList: saveNodeList, + + cleanNodeList: function() { + var removed = false; + for (var id in nodeConfigs) { + if (nodeConfigs.hasOwnProperty(id)) { + if (nodeConfigs[id].module && !nodeModules[nodeConfigs[id].module]) { + registry.removeNode(id); + removed = true; + } + } + } + if (removed) { + saveNodeList(); + } + } + } +})(); + + + +function init(_settings) { + Node = require("./Node"); + settings = _settings; + registry.init(); +} + +/** + * Synchronously walks the directory looking for node files. + * Emits 'node-icon-dir' events for an icon dirs found + * @param dir the directory to search + * @return an array of fully-qualified paths to .js files + */ +function getNodeFiles(dir) { + var result = []; + var files = []; + try { + files = fs.readdirSync(dir); + } catch(err) { + return result; + } + files.sort(); + files.forEach(function(fn) { + var stats = fs.statSync(path.join(dir,fn)); + if (stats.isFile()) { + if (/\.js$/.test(fn)) { + var valid = true; + if (settings.nodesExcludes) { + for (var i=0;i]*)data-template-name=['"]([^'"]*)['"]/gi; + var match = null; + + while((match = regExp.exec(content)) !== null) { + types.push(match[2]); + } + node.types = types; + node.config = content; + + // TODO: parse out the javascript portion of the template + node.script = ""; + + for (var i=0;i