| #!/bin/sh | ||
| EXAMPLES=`dirname $0` | ||
| node $EXAMPLES/controls.js myhost test 0 | ||
| node $EXAMPLES/controls.js myhost test 64 | ||
| node $EXAMPLES/controls.js mycluster test 0 | ||
| node $EXAMPLES/controls.js mycluster test 64 | ||
| node $EXAMPLES/controls.js mycluster scp | ||
| node $EXAMPLES/controls.js mycluster clean | ||
| node $EXAMPLES/controls.js myhost listeners | ||
| # node $EXAMPLES/controls.js myhost stdin | ||
| node $EXAMPLES/controls.js myclusterarray test 0 | ||
| node $EXAMPLES/controls.js myclusterjson test 0 | ||
| node $EXAMPLES/controls.js mymachine 127.0.0.1 test 0 | ||
+162
| task('mycluster', 'Config for my cluster', function () { | ||
| var shared = Object.create(control.controller); | ||
| shared.enhance(['ejs', 'fpro', 'ecr']); // Need method to trigger logic | ||
| shared.enhance = ['ejs', 'fpro', 'ecr']; // Only with defined setter | ||
| var config = { | ||
| 'a.domain.com': { | ||
| enhance = ['ejs']; | ||
| }, | ||
| 'b.domain.com': { | ||
| } | ||
| } | ||
| } | ||
| function enhance(enhancements) { | ||
| var i, l, f; | ||
| for (i = 0, l = enhancements.length; i < l; i += 1) { | ||
| enhancement = enhancements[i]; | ||
| try { | ||
| enhancement = require('control-' + enhancement); | ||
| } catch (e) { | ||
| if (e.message && e.message.match(/Cannot find module/)) { | ||
| // Get it from the directory of script execution control/ejs | ||
| module.exports = require('./node-control'); | ||
| } else { | ||
| throw e; | ||
| } | ||
| } | ||
| // Slap all the methods experted by the enhancement onto the controller | ||
| for (f in enhancement) { | ||
| this[f.name] = f; | ||
| } | ||
| } | ||
| } | ||
| var stack = []; // two kinds of events - sequence called, or upload finishes | ||
| function next() { | ||
| if (stack is not empty) { | ||
| item = stack.shift(); | ||
| item.upload(); | ||
| } | ||
| } | ||
| function sequence(upload, proceed) { | ||
| var item = {}; | ||
| step = item.upload; | ||
| proceed = item.proceed; | ||
| stack.push(item); | ||
| } | ||
| task('sequence', 'Upload file one controller at a time', function(controller) { | ||
| function upload() { | ||
| controller.scp('a', 'b', function () { | ||
| next(); | ||
| }; | ||
| } | ||
| function proceed() { | ||
| controller.ssh('ls'); | ||
| } | ||
| sequence(upload, proceed); | ||
| // Each controller | ||
| } | ||
| var queue = {}, queued = []; | ||
| var push(callback) { | ||
| queued.push(callback); | ||
| } | ||
| var start() { | ||
| } | ||
| queue(callback) { | ||
| queue.push(callback); | ||
| if (!queue.started) { | ||
| queue.start(); | ||
| } | ||
| } | ||
| task('queue', 'Upload file one controller at a time', function(controller) { | ||
| queue(function () { | ||
| controller.scp('a, 'b', function () { | ||
| queue.done(); | ||
| controller.ssh('ls'); | ||
| }); | ||
| } | ||
| } | ||
| task('sequence', 'Upload file one controller at a time', function(controller) { | ||
| controller.scpSync('a', 'b', function () { | ||
| controller.ssh('ls'); | ||
| }; | ||
| sequence(upload, proceed); | ||
| // Each controller | ||
| } | ||
| task('throttle', 'Allow only n controllers to operate simulataneously', | ||
| function(controller) { | ||
| controller.throttle.on('upload', 2, function () { | ||
| controller.scp('a', 'b', function () { | ||
| controller.ssh('ls'); | ||
| }); | ||
| }); | ||
| }); | ||
| task('waiton', 'Allow only n controllers to operate simulataneously', | ||
| function(controller) { | ||
| controller.wait.on('upload', function () { | ||
| controller.ssh('ls'); | ||
| }); | ||
| }); | ||
| // Allow two controllers at a time to do the scp simultaneously and then all | ||
| // controllers wait until all controllers are done with the upload to proceed | ||
| // with the ssh all simultaneously. | ||
| task('combined', 'Allow only n controllers to operate simulataneously', | ||
| function(controller) { | ||
| function callback(code) { | ||
| controller.throttle.off('upload'); | ||
| if (code === 0) { | ||
| controller.wait.on('upload', function () { | ||
| controller.ssh('ls'); | ||
| }); | ||
| } | ||
| } | ||
| controller.throttle.on('upload', 2, function () { | ||
| controller.scp('a', 'b', callback, callback); | ||
| }); | ||
| }); | ||
| task('sequence', 'Upload file one controller at a time', function(controller) { | ||
| controller.scpSync('a', 'b', function () { | ||
| controller.ssh('ls'); | ||
| }; | ||
| sequence(upload, proceed); | ||
| // Each controller | ||
| } | ||
| task('config:sshd', 'Confgure sshd from template', function (controller) { | ||
| controller.template('~/sshd_template.ejs', '/etc/ssh/sshd_config', | ||
| function () { | ||
| }); | ||
| } |
| task('mycluster', 'Config for my cluster', function () { | ||
| var shared = Object.create(control.controller); | ||
| shared.enhance(['ejs', 'fpro', 'ecr']); // Need method to trigger logic | ||
| shared.enhance = ['ejs', 'fpro', 'ecr']; // Only with defined setter | ||
| var config = { | ||
| 'a.domain.com': { | ||
| enhance = ['ejs']; | ||
| }, | ||
| 'b.domain.com': { | ||
| } | ||
| } | ||
| } | ||
| function enhance(enhancements) { | ||
| var i, l, f; | ||
| for (i = 0, l = enhancements.length; i < l; i += 1) { | ||
| enhancement = enhancements[i]; | ||
| try { | ||
| enhancement = require('control-' + enhancement); | ||
| } catch (e) { | ||
| if (e.message && e.message.match(/Cannot find module/)) { | ||
| // Get it from the directory of script execution control/ejs | ||
| module.exports = require('./node-control'); | ||
| } else { | ||
| throw e; | ||
| } | ||
| } | ||
| // Slap all the methods experted by the enhancement onto the controller | ||
| for (f in enhancement) { | ||
| this[f.name] = f; | ||
| } | ||
| } | ||
| } | ||
| task('sequence', 'Upload file one controller at a time', funciton (controller) { | ||
| function upload() { | ||
| controller.scp('a', 'b'); | ||
| } | ||
| function continue() { | ||
| controller.ssh('ls'); | ||
| } | ||
| sequence(controller, upload, continue); | ||
| } | ||
| task('config:sshd', 'Confgure sshd from template', function (controller) { | ||
| controller.template('~/sshd_template.ejs', '/etc/ssh/sshd_config', | ||
| function () { | ||
| }); | ||
| } |
| // How does a throttle work? | ||
| // It has to run only two of any controllers at one time | ||
| // It needs to start running them when the first one is received | ||
| // It needs to start running n more of them as more come in | ||
| // But not more than n at a time | ||
| // It needs to know when a controller is 'through' its throttled portion | ||
| // So it can tell another controller to get going | ||
| // It cannot wait for a function to return because the function may | ||
| // make asynchronous calls. | ||
| // It should ideally go away once all controllers are done | ||
| // But it doesn't know what controllers might enter it in the future | ||
| // So it always has to stay open waiting for another controller | ||
| // It needs to avoid interfering with other throttles | ||
| // Or put another way, it needs to support multiple throttle points | ||
| // If an exit callback is called, you need to inform the throttle becuase | ||
| // user throttle off won't be called. | ||
| // What if all throttles had a checkThrottle() method that returned true | ||
| // or false if they were throttled up or down. | ||
| // Still doesn't handle the how does the throttle know when it is done problem | ||
| // Gigabytes is size of cluster in GB. | ||
| // Recovery rate is KB/sec of recovery. | ||
| // Return hours | ||
| function calculateTime(gigabytes, recoveryRate) { | ||
| var kbs = gigabytes * 1024 * 1024, | ||
| seconds = kbs/recoveryRate; | ||
| return seconds / 60 / 60; | ||
| } | ||
| // Returns 28 hours | ||
| console.log(calculateTime(2000, 25 * 1024)); | ||
| /*global require, exports */ | ||
| var sys = require('sys'), | ||
| var util = require('util'), | ||
| controller = require('./controller'); | ||
@@ -18,7 +18,7 @@ | ||
| function configure(prototype, address, options) { | ||
| if (controller.prototype !== prototype && | ||
| if (controller.prototype !== prototype && | ||
| !controller.prototype.isPrototypeOf(prototype)) { | ||
| throw new Error("Prototype is not a controller"); | ||
| throw new Error("Prototype is not a controller"); | ||
| } | ||
| if (!address) { | ||
@@ -47,3 +47,3 @@ throw new Error("No address"); | ||
| var list = [], | ||
| var list = [], | ||
| i, length, configured; | ||
@@ -68,3 +68,3 @@ if (Array.prototype.isPrototypeOf(addresses)) { | ||
| function hosts(config, addresses) { | ||
| sys.puts("!! hosts() is deprecated"); | ||
| console.log("!! hosts() is deprecated"); | ||
@@ -71,0 +71,0 @@ if (!config) { |
+5
-5
@@ -6,3 +6,3 @@ /*global require, exports */ | ||
| configurator = require('./configurator'), | ||
| sys = require ('sys'); | ||
| util = require ('util'); | ||
@@ -13,6 +13,6 @@ function begin() { | ||
| } catch (e) { | ||
| if (e.name === 'TypeError' && e.message === | ||
| if (e.name === 'TypeError' && e.message === | ||
| "Property 'log' of object #<Object> is not a function") { | ||
| sys.puts('!! Set logPath instead of log on controllers.'); | ||
| } | ||
| console.log('!! Set logPath instead of log on controllers.'); | ||
| } | ||
| throw e; | ||
@@ -27,2 +27,2 @@ } | ||
| exports.controllers = configurator.controllers; | ||
| exports.begin = begin; | ||
| exports.begin = begin; |
+8
-8
@@ -7,3 +7,3 @@ // Provides a grep-friendly log where every line is prefixed with | ||
| var sys = require('sys'), | ||
| var util = require('util'), | ||
| fs = require('fs'); | ||
@@ -29,3 +29,3 @@ | ||
| this.path = path; | ||
| filestream = this.filestream = createWriteStream(path); | ||
| filestream = this.filestream = createWriteStream(path); | ||
| } | ||
@@ -42,6 +42,6 @@ | ||
| // indenting can be done more efficiently, please keep the carriage return | ||
| // issue in mind. | ||
| // issue in mind. | ||
| message = message.replace(/\r/g, "\n"); // Carriage return conversion | ||
| message = message.replace(/^\n+|\n+$/g, ""); // Start and end clean up | ||
| message = message.replace(/\n+/g, "\n"); // Group interstitial new lines | ||
| message = message.replace(/\n+/g, "\n"); // Group interstitial new lines | ||
@@ -54,3 +54,3 @@ lines = message.split("\n"); | ||
| if (filestream) { | ||
| filestream.write(timestamp.now() + ':' + | ||
| filestream.write(timestamp.now() + ':' + | ||
| logPrefix + line + '\n'); | ||
@@ -60,3 +60,3 @@ } | ||
| if (echo) { | ||
| sys.puts(logPrefix + line); | ||
| console.log(logPrefix + line); | ||
| } | ||
@@ -68,4 +68,4 @@ } | ||
| // prefix: prefix that will be prefixed to every line of output | ||
| // path: (optional) file path of persisted log | ||
| // echo: (optional) true to echo to console, false otherwise | ||
| // path: (optional) file path of persisted log | ||
| // echo: (optional) true to echo to console, false otherwise | ||
| // timestamper: (optional) object that returns a timestamp from now() method | ||
@@ -72,0 +72,0 @@ function Log(prefix, path, echo, timestamp) { |
+5
-5
| /*global require, exports, process */ | ||
| var sys = require('sys'); | ||
| var util = require('util'); | ||
@@ -14,3 +14,3 @@ var tasks = {}, | ||
| for (i = 1, length = unshifted.length; i < length; i += 1) { | ||
| shifted[i - 1] = unshifted[i]; | ||
| shifted[i - 1] = unshifted[i]; | ||
| } | ||
@@ -32,3 +32,3 @@ return shifted; | ||
| sys.puts(log); | ||
| console.log(log); | ||
@@ -48,3 +48,3 @@ if (!task) { | ||
| var i, length, config, | ||
| args = shift(arguments), | ||
| args = shift(arguments), | ||
| argsWithConfig; | ||
@@ -73,3 +73,3 @@ | ||
| if (tasks.hasOwnProperty(i)) { | ||
| sys.puts(i + ': ' + descriptions[i]); | ||
| console.log(i + ': ' + descriptions[i]); | ||
| } | ||
@@ -76,0 +76,0 @@ } |
+0
-2
@@ -6,4 +6,2 @@ // Creates a YYYYMMDDhhmmss timestamp. Ideas on how to do this more efficiently | ||
| var sys = require('sys'); | ||
| function padLeft(message, length) { | ||
@@ -10,0 +8,0 @@ var delta, i; |
+3
-2
| { "name" : "control", | ||
| "description" : "Scripted asynchronous control of remote machines in parallel via ssh", | ||
| "version" : "0.2.2", | ||
| "version" : "0.2.3", | ||
| "author" : "Thomas Smith <node@thomassmith.com>", | ||
| "repository" : { "type" : "git" , "url" : "git://github.com/tsmith/node-control.git" }, | ||
| "main" : "./lib", | ||
| "engines" : { "node" : ">=0.1.99" } | ||
| "engines" : { "node" : ">=0.6.0" } | ||
| } |
+10
-9
@@ -16,5 +16,5 @@ DESCRIPTION | ||
| If you want to control remote machines from individual scripts without the | ||
| tasks system, see QUICK EXAMPLE WITHOUT TASKS. Otherwise, to get the | ||
| current date from the two machines listed in the 'mycluster' config task as | ||
| the 'mylogin' user with a single command: | ||
| tasks system, see QUICK EXAMPLE WITHOUT TASKS. Otherwise, to get the current | ||
| date from the two machines listed in the 'mycluster' config with a single | ||
| command: | ||
@@ -56,5 +56,5 @@ var control = require('control'), | ||
| Performing date for a.domain.com | ||
| a.domain.com:mylogin:ssh: date | ||
| a.domain.com:alogin:ssh: date | ||
| Performing date for b.domain.com | ||
| b.domain.com:mylogin:ssh: date | ||
| b.domain.com:blogin:ssh: date | ||
| a.domain.com:stdout: Sun Jul 18 13:30:50 UTC 2010 | ||
@@ -151,3 +151,4 @@ b.domain.com:stdout: Sun Jul 18 13:30:51 UTC 2010 | ||
| controller-specific properties as defined in the JSON notation. In this case, | ||
| both controllers will effectively have sshOptions = ['-p 44']. | ||
| both controllers will effectively have sshOptions = ['-p 44'], but different | ||
| user names. | ||
@@ -170,3 +171,3 @@ If all machines in your cluster have the same properties, can you pass an array | ||
| You can also build up your list of controllers without the use of | ||
| Alternatively, you can build up your list of controllers without the use of | ||
| controllers(): | ||
@@ -409,3 +410,3 @@ | ||
| To use sudo, just include sudo as part of your command: | ||
| To use sudo, include sudo as part of your command: | ||
@@ -557,3 +558,2 @@ controller.ssh('sudo date'); | ||
| With this set of config tasks, if there is an ad hoc need to run certain tasks | ||
@@ -642,2 +642,3 @@ against a single machine in the cluster, but otherwise have identical | ||
| * David Pratt (https://github.com/fairwinds) | ||
| * Peter Lyons (https://github.com/focusaurus) | ||
@@ -644,0 +645,0 @@ |
Sorry, the diff of this file is too big to display
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Non-existent author
Supply chain riskThe package was published by an npm account that no longer exists.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
237609
99.85%30
15.38%1513
15.32%643
0.16%0
-100%22
-4.35%2
100%