Skip to content
Browse files

Initial Creation

  • Loading branch information...
0 parents commit eb4ac6a555999d4cae2675270c55fd51ea250cc2 Mark Cavage committed
1 .gitignore
@@ -0,0 +1 @@
+node_modules
19 LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2011 Joyent, Inc., All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE
94 README.md
@@ -0,0 +1,94 @@
+node-smartdc is a node.js client library for interacting with the Joyent
+SmartDataCenter API. This package additionally contains a CLI you can use
+to write scripts encapsulating most common tasks.
+
+## Installation
+
+You probably want to install this package globally, so the CLI commands are
+always in your path.
+
+ npm install smartdc -g
+
+## Usage
+
+### CLI
+
+There are CLI commands corresponding to almost every action available in the
+SmartDataCenter API; see the
+[SmartDataCenter documentation][http://apidocs.joyent.com/napi/cloudapi/] for
+complete information, but to get started, you'll want to run the following:
+
+ sdc-setup
+
+The `sdc-setup` command will prompt you for your username and password, and
+upload your SSH key. All the rest of the CLI commands use your RSA private
+key for signing requests to the API, rather than sending your password to the
+Joyent API. Once you've run `sdc-setup` (and set the environment variables
+it indicates), you can provision a machine, and check it's status. For example,
+here's an example that creates a new node.js machine and tags it as a
+'test' machine, then you can grab the status a few times until it's `running`.
+
+Note this assumes you've also got [jsontool][https://github.com/trentm/json]
+installed:
+
+ sdc-createmachine -e nodejs -n demo -t group=test
+ ...
+ sdc-listmachines | json 0.state
+ provisioning
+ sdc-listmachines | json 0.state
+ provisioning
+ sdc-listmachines | json 0.state
+ running
+
+At that point, you can ssh into the machine; try this:
+
+ ssh-add
+ ssh -A admin@`./sdc-listmachines | json 0.ips[0]`
+
+Note that we added your keys to the SSH agent, so that you can use the CLI
+seamlessly on your new SmartMachine. Once you've played around and are done,
+you can dispose of it; shut it down, then poll until it's `stopped`.
+
+ sdc-listmachines | json 0.id | xargs sdc-stopmachine
+ sdc-listmachines | json 0.state
+ stopped
+ sdc-listmachines | json 0.id | xargs sdc-deletemachine
+
+There's a lot more you can do, like manage snapshots, analytics, keys, tags,
+etc.
+
+### Programmatic Usage
+
+ var fs = require('fs');
+ var smartdc = require('smartdc');
+
+ // Read in the SSH private key
+ var home = process.env.HOME;
+ var key = fs.readFileSync(home + '/.ssh/id_rsa', 'ascii');
+
+ var client = smartdc.createClient({
+ url: 'https://api.no.de',
+ key: key,
+ keyId: '/<your login here>/keys/id_rsa'
+ });
+
+ client.listMachines(function(err, machines) {
+ if (err) {
+ console.log('Unable to list machines: ' + e);
+ return;
+ }
+
+ machines.forEach(function(m) {
+ console.log('Machine: ' + JSON.stringify(m, null, 2));
+ });
+ });
+
+Check out the source documentation for JSDocs on the API.
+
+## License
+
+MIT.
+
+## Bugs
+
+See <https://github.com/joyent/node-smartdc/issues>.
65 bin/sdc-addmachinetags
@@ -0,0 +1,65 @@
+#!/usr/bin/env node
+// -*- mode: js -*-
+// Copyright 2011 Joyent, Inc. All rights reserved.
+
+var fs = require('fs');
+var path = require('path');
+var url = require('url');
+
+var common = require('../lib/cli_common');
+
+
+
+///--- Globals
+
+var Options = {
+ "account": String,
+ "debug": Boolean,
+ "help": Boolean,
+ "identity": path,
+ "keyId": String,
+ "tag": [String, Array],
+ "url": url
+};
+
+var ShortOptions = {
+ "a": ["--account"],
+ "d": ["--debug"],
+ "h": ["--help"],
+ "?": ["--help"],
+ "i": ["--identity"],
+ "k": ["--keyId"],
+ "t": ["--tag"],
+ "u": ["--url"]
+};
+
+var usageStr = common.buildUsageString(Options);
+usageStr += ' machine';
+
+
+///--- Mainline
+
+common.parseArguments(Options, ShortOptions, function(parsed) {
+
+ if (parsed.argv.remain.length < 1)
+ common.usage(usageStr, 1, 'machine required');
+
+ var opts = {};
+ if (parsed.name)
+ opts.name = parsed.name;
+ if (!parsed.tag)
+ common.usage(usageStr, 1, '--tag required');
+
+ var tags = {};
+ for (var i = 0; i < parsed.tag.length; i++) {
+ var tmp = parsed.tag[i].split('=');
+ if (!tmp || tmp.length !== 2) {
+ console.error(parsed.tag[i] + ' is an invalid tag; try foo=bar');
+ process.exit(1);
+ }
+ tags[tmp[0]] = tmp[1];
+ }
+
+ var client = common.newClient(parsed);
+ client.addMachineTags(parsed.argv.remain[0], tags, common.callback);
+}, usageStr);
70 bin/sdc-createinstrumentation
@@ -0,0 +1,70 @@
+#!/usr/bin/env node
+// -*- mode: js -*-
+// Copyright 2011 Joyent, Inc. All rights reserved.
+
+var fs = require('fs');
+var path = require('path');
+var url = require('url');
+
+var common = require('../lib/cli_common');
+
+
+
+///--- Globals
+
+var Options = {
+ "account": String,
+ "clone": Number,
+ "debug": Boolean,
+ "decomposition": String,
+ "help": Boolean,
+ "identity": path,
+ "keyId": String,
+ "module": String,
+ "predicate": String,
+ "stat": String,
+ "url": url
+};
+
+var ShortOptions = {
+ "a": ["--account"],
+ "c": ["--clone"],
+ "d": ["--debug"],
+ "h": ["--help"],
+ "?": ["--help"],
+ "i": ["--identity"],
+ "k": ["--keyId"],
+ "m": ["--module"],
+ "n": ["--decomposition"],
+ "p": ["--predicate"],
+ "s": ["--stat"],
+ "u": ["--url"]
+};
+
+
+///--- Mainline
+
+common.parseArguments(Options, ShortOptions, function(parsed) {
+ var opts = {};
+ if (parsed.module)
+ opts.module = parsed.module;
+
+ if (parsed.stat)
+ opts.stat = parsed.stat;
+
+ if (parsed.decomposition)
+ opts.decomposition = parsed.decomposition;
+
+ if (parsed.predicate)
+ opts.predicate = parsed.predicate;
+
+ if (parsed.clone)
+ opts.clone = parsed.clone;
+
+ var client = common.newClient(parsed);
+ client.createInstrumentation(opts, common.callback);
+});
+
+
+
+
71 bin/sdc-createkey
@@ -0,0 +1,71 @@
+#!/usr/bin/env node
+// -*- mode: js -*-
+// Copyright 2011 Joyent, Inc. All rights reserved.
+
+var fs = require('fs');
+var path = require('path');
+var url = require('url');
+
+var common = require('../lib/cli_common');
+
+
+
+///--- Globals
+
+var Options = {
+ "account": String,
+ "debug": Boolean,
+ "help": Boolean,
+ "identity": path,
+ "keyId": String,
+ "name": String,
+ "url": url
+};
+
+var ShortOptions = {
+ "a": ["--account"],
+ "d": ["--debug"],
+ "h": ["--help"],
+ "?": ["--help"],
+ "i": ["--identity"],
+ "k": ["--keyId"],
+ "n": ["--name"],
+ "u": ["--url"]
+};
+
+var usageStr = common.buildUsageString(Options);
+usageStr += ' public_ssh_key';
+
+
+///--- Internal Functions
+
+function loadNewKey(key) {
+ try {
+ return fs.readFileSync(key, 'ascii');
+ } catch(e) {
+ common.usage(usageStr, 2, 'Unable to load key ' + identity + ': ' + e);
+ }
+}
+
+
+
+///--- Mainline
+
+common.parseArguments(Options, ShortOptions, function(parsed) {
+
+ if (parsed.argv.remain.length < 1)
+ common.usage(usageStr, 1, 'ssh_key required');
+
+ var opts = {
+ key: loadNewKey(parsed.argv.remain[0])
+ };
+ if (parsed.name) {
+ opts.name = parsed.name;
+ } else {
+ var name = parsed.argv.remain[0].split('/');
+ opts.name = name[name.length - 1];
+ }
+
+ var client = common.newClient(parsed);
+ client.createKey(opts, common.callback);
+}, usageStr);
63 bin/sdc-createmachine
@@ -0,0 +1,63 @@
+#!/usr/bin/env node
+// -*- mode: js -*-
+// Copyright 2011 Joyent, Inc. All rights reserved.
+
+var https = require('https');
+var path = require('path');
+var url = require('url');
+
+var common = require('../lib/cli_common');
+
+
+
+///--- Globals
+
+var Options = {
+ "account": String,
+ "debug": Boolean,
+ "dataset": String,
+ "help": Boolean,
+ "identity": path,
+ "keyId": String,
+ "name": String,
+ "package": String,
+ "tag": [String, Array],
+ "url": url
+};
+
+var ShortOptions = {
+ "a": ["--account"],
+ "d": ["--debug"],
+ "e": ["--dataset"],
+ "h": ["--help"],
+ "?": ["--help"],
+ "i": ["--identity"],
+ "k": ["--keyId"],
+ "n": ["--name"],
+ "p": ["--package"],
+ "t": ["--tag"],
+ "u": ["--url"]
+};
+
+
+///--- Mainline
+
+common.parseArguments(Options, ShortOptions, function(parsed) {
+ var opts = {}
+ if (parsed.dataset) opts.dataset = parsed.dataet;
+ if (parsed.name) opts.name = parsed.name;
+ if (parsed['package']) opts['package'] = parsed['package'];
+ if (parsed.tag) {
+ for (var i = 0; i < parsed.tag.length; i++) {
+ var tmp = parsed.tag[i].split('=');
+ if (!tmp || tmp.length !== 2) {
+ console.error(parsed.tag[i] + ' is an invalid tag; try foo=bar');
+ process.exit(1);
+ }
+ opts['tag.' + tmp[0]] = tmp[1];
+ }
+ }
+
+ var client = common.newClient(parsed);
+ client.createMachine(opts, common.callback);
+});
54 bin/sdc-createmachinesnapshot
@@ -0,0 +1,54 @@
+#!/usr/bin/env node
+// -*- mode: js -*-
+// Copyright 2011 Joyent, Inc. All rights reserved.
+
+var fs = require('fs');
+var path = require('path');
+var url = require('url');
+
+var common = require('../lib/cli_common');
+
+
+
+///--- Globals
+
+var Options = {
+ "account": String,
+ "debug": Boolean,
+ "help": Boolean,
+ "identity": path,
+ "keyId": String,
+ "name": String,
+ "url": url
+};
+
+var ShortOptions = {
+ "a": ["--account"],
+ "d": ["--debug"],
+ "h": ["--help"],
+ "?": ["--help"],
+ "i": ["--identity"],
+ "k": ["--keyId"],
+ "m": ["--machine"],
+ "n": ["--name"],
+ "u": ["--url"]
+};
+
+var usageStr = common.buildUsageString(Options);
+usageStr += ' machine';
+
+
+///--- Mainline
+
+common.parseArguments(Options, ShortOptions, function(parsed) {
+
+ if (parsed.argv.remain.length < 1)
+ common.usage(usageStr, 1, 'machine required');
+
+ var opts = {};
+ if (parsed.name)
+ opts.name = parsed.name;
+
+ var client = common.newClient(parsed);
+ client.createMachineSnapshot(parsed.argv.remain[0], opts, common.callback);
+}, usageStr);
47 bin/sdc-deleteinstrumentation
@@ -0,0 +1,47 @@
+#!/usr/bin/env node
+// -*- mode: js -*-
+// Copyright 2011 Joyent, Inc. All rights reserved.
+
+var path = require('path');
+var url = require('url');
+
+var common = require('../lib/cli_common');
+
+
+
+///--- Globals
+
+var Options = {
+ "account": String,
+ "debug": Boolean,
+ "help": Boolean,
+ "identity": path,
+ "keyId": String,
+ "url": url
+};
+
+var ShortOptions = {
+ "a": ["--account"],
+ "d": ["--debug"],
+ "h": ["--help"],
+ "?": ["--help"],
+ "i": ["--identity"],
+ "k": ["--keyId"],
+ "u": ["--url"]
+};
+
+var usageStr = common.buildUsageString(Options) + ' instrumentation_id';
+
+
+
+///--- Mainline
+
+common.parseArguments(Options, ShortOptions, function(parsed) {
+ if (parsed.argv.remain.length < 1)
+ common.usage(usageStr, 1, 'instrumentation required');
+
+ var id = parseInt(parsed.argv.remain[0], 10);
+ var client = common.newClient(parsed);
+
+ client.deleteInstrumentation(id, common.callback);
+}, usageStr);
45 bin/sdc-deletekey
@@ -0,0 +1,45 @@
+#!/usr/bin/env node
+// -*- mode: js -*-
+// Copyright 2011 Joyent, Inc. All rights reserved.
+
+var path = require('path');
+var url = require('url');
+
+var common = require('../lib/cli_common');
+
+
+
+///--- Globals
+
+var Options = {
+ "account": String,
+ "debug": Boolean,
+ "help": Boolean,
+ "identity": path,
+ "keyId": String,
+ "url": url
+};
+
+var ShortOptions = {
+ "a": ["--account"],
+ "d": ["--debug"],
+ "h": ["--help"],
+ "?": ["--help"],
+ "i": ["--identity"],
+ "k": ["--keyId"],
+ "u": ["--url"]
+};
+
+var usageStr = common.buildUsageString(Options);
+usageStr += ' key_name';
+
+
+///--- Mainline
+
+common.parseArguments(Options, ShortOptions, function(parsed) {
+ if (parsed.argv.remain.length < 1)
+ common.usage(usageStr, 1, 'key_name required');
+
+ var client = common.newClient(parsed);
+ client.deleteKey(parsed.argv.remain[0], common.callback);
+}, usageStr);
45 bin/sdc-deletemachine
@@ -0,0 +1,45 @@
+#!/usr/bin/env node
+// -*- mode: js -*-
+// Copyright 2011 Joyent, Inc. All rights reserved.
+
+var path = require('path');
+var url = require('url');
+
+var common = require('../lib/cli_common');
+
+
+
+///--- Globals
+
+var Options = {
+ "account": String,
+ "debug": Boolean,
+ "help": Boolean,
+ "identity": path,
+ "keyId": String,
+ "url": url
+};
+
+var ShortOptions = {
+ "a": ["--account"],
+ "d": ["--debug"],
+ "h": ["--help"],
+ "?": ["--help"],
+ "i": ["--identity"],
+ "k": ["--keyId"],
+ "u": ["--url"]
+};
+
+var usageStr = common.buildUsageString(Options);
+usageStr += ' machine';
+
+
+///--- Mainline
+
+common.parseArguments(Options, ShortOptions, function(parsed) {
+ if (parsed.argv.remain.length < 1)
+ common.usage(usageStr, 1, 'machine required');
+
+ var client = common.newClient(parsed);
+ client.deleteMachine(parsed.argv.remain[0], common.callback);
+}, usageStr);
51 bin/sdc-deletemachinesnapshot
@@ -0,0 +1,51 @@
+#!/usr/bin/env node
+// -*- mode: js -*-
+// Copyright 2011 Joyent, Inc. All rights reserved.
+
+var path = require('path');
+var url = require('url');
+
+var common = require('../lib/cli_common');
+
+
+
+///--- Globals
+
+var Options = {
+ "account": String,
+ "debug": Boolean,
+ "help": Boolean,
+ "identity": path,
+ "keyId": String,
+ "machine": String,
+ "url": url
+};
+
+var ShortOptions = {
+ "a": ["--account"],
+ "d": ["--debug"],
+ "h": ["--help"],
+ "?": ["--help"],
+ "i": ["--identity"],
+ "k": ["--keyId"],
+ "m": ["--machine"],
+ "u": ["--url"]
+};
+
+var usageStr = common.buildUsageString(Options) + ' snapshot';
+
+
+
+///--- Mainline
+
+common.parseArguments(Options, ShortOptions, function(parsed) {
+ if (!parsed.machine)
+ common.usage(usageStr, 1, 'machine required');
+ if (parsed.argv.remain.length < 1)
+ common.usage(usageStr, 1, 'snapshot required');
+
+ var client = common.newClient(parsed);
+ client.deleteMachineSnapshot(parsed.machine,
+ parsed.argv.remain[0],
+ common.callback);
+}, usageStr);
55 bin/sdc-deletemachinetag
@@ -0,0 +1,55 @@
+#!/usr/bin/env node
+// -*- mode: js -*-
+// Copyright 2011 Joyent, Inc. All rights reserved.
+
+var path = require('path');
+var url = require('url');
+
+var common = require('../lib/cli_common');
+
+
+
+///--- Globals
+
+var Options = {
+ "account": String,
+ "debug": Boolean,
+ "help": Boolean,
+ "identity": path,
+ "keyId": String,
+ "machine": String,
+ "url": url
+};
+
+var ShortOptions = {
+ "a": ["--account"],
+ "d": ["--debug"],
+ "h": ["--help"],
+ "?": ["--help"],
+ "i": ["--identity"],
+ "k": ["--keyId"],
+ "m": ["--machine"],
+ "u": ["--url"]
+};
+
+var usageStr = common.buildUsageString(Options) + ' tag (use * to delete all)';
+
+
+
+///--- Mainline
+
+common.parseArguments(Options, ShortOptions, function(parsed) {
+ if (!parsed.machine)
+ common.usage(usageStr, 1, 'machine required');
+ if (parsed.argv.remain.length < 1)
+ common.usage(usageStr, 1, 'snapshot required');
+
+ var client = common.newClient(parsed);
+ if (parsed.argv.remain[0] === '*') {
+ client.deleteMachineTags(parsed.machine, common.callback);
+ } else {
+ client.deleteMachineTag(parsed.machine,
+ parsed.argv.remain[0],
+ common.callback);
+ }
+}, usageStr);
40 bin/sdc-describeanalytics
@@ -0,0 +1,40 @@
+#!/usr/bin/env node
+// -*- mode: js -*-
+// Copyright 2011 Joyent, Inc. All rights reserved.
+
+var path = require('path');
+var url = require('url');
+
+var common = require('../lib/cli_common');
+
+
+
+///--- Globals
+
+var Options = {
+ "account": String,
+ "debug": Boolean,
+ "help": Boolean,
+ "identity": path,
+ "keyId": String,
+ "url": url
+};
+
+var ShortOptions = {
+ "a": ["--account"],
+ "d": ["--debug"],
+ "h": ["--help"],
+ "?": ["--help"],
+ "i": ["--identity"],
+ "k": ["--keyId"],
+ "u": ["--url"]
+};
+
+
+
+///--- Mainline
+
+common.parseArguments(Options, ShortOptions, function(parsed) {
+ var client = common.newClient(parsed);
+ client.describeAnalytics(common.callback);
+});
45 bin/sdc-getdataset
@@ -0,0 +1,45 @@
+#!/usr/bin/env node
+// -*- mode: js -*-
+// Copyright 2011 Joyent, Inc. All rights reserved.
+
+var path = require('path');
+var url = require('url');
+
+var common = require('../lib/cli_common');
+
+
+
+///--- Globals
+
+var Options = {
+ "account": String,
+ "debug": Boolean,
+ "help": Boolean,
+ "identity": path,
+ "keyId": String,
+ "url": url
+};
+
+var ShortOptions = {
+ "a": ["--account"],
+ "d": ["--debug"],
+ "h": ["--help"],
+ "?": ["--help"],
+ "i": ["--identity"],
+ "k": ["--keyId"],
+ "u": ["--url"]
+};
+
+var usageStr = common.buildUsageString(Options) + ' dataset';
+
+
+
+///--- Mainline
+
+common.parseArguments(Options, ShortOptions, function(parsed) {
+ if (parsed.argv.remain.length < 1)
+ common.usage(usageStr, 1, 'dataset required');
+
+ var client = common.newClient(parsed);
+ client.getDataset(parsed.argv.remain[0], common.callback);
+}, usageStr);
52 bin/sdc-getinstrumentation
@@ -0,0 +1,52 @@
+#!/usr/bin/env node
+// -*- mode: js -*-
+// Copyright 2011 Joyent, Inc. All rights reserved.
+
+var path = require('path');
+var url = require('url');
+
+var common = require('../lib/cli_common');
+
+
+
+///--- Globals
+
+var Options = {
+ "account": String,
+ "debug": Boolean,
+ "help": Boolean,
+ "identity": path,
+ "keyId": String,
+ "value": Boolean,
+ "url": url
+};
+
+var ShortOptions = {
+ "a": ["--account"],
+ "d": ["--debug"],
+ "h": ["--help"],
+ "?": ["--help"],
+ "i": ["--identity"],
+ "k": ["--keyId"],
+ "u": ["--url"],
+ "v": ["--value"]
+};
+
+var usageStr = common.buildUsageString(Options) + ' instrumentation_id';
+
+
+
+///--- Mainline
+
+common.parseArguments(Options, ShortOptions, function(parsed) {
+ if (parsed.argv.remain.length < 1)
+ common.usage(usageStr, 1, 'instrumentation required');
+
+ var id = parseInt(parsed.argv.remain[0], 10);
+ var client = common.newClient(parsed);
+
+ if (parsed.value)
+ return client.getInstrumentationValue(id, common.callback);
+
+ return client.getInstrumentation(id, common.callback);
+}, usageStr);
45 bin/sdc-getkey
@@ -0,0 +1,45 @@
+#!/usr/bin/env node
+// -*- mode: js -*-
+// Copyright 2011 Joyent, Inc. All rights reserved.
+
+var path = require('path');
+var url = require('url');
+
+var common = require('../lib/cli_common');
+
+
+
+///--- Globals
+
+var Options = {
+ "account": String,
+ "debug": Boolean,
+ "help": Boolean,
+ "identity": path,
+ "keyId": String,
+ "url": url
+};
+
+var ShortOptions = {
+ "a": ["--account"],
+ "d": ["--debug"],
+ "h": ["--help"],
+ "?": ["--help"],
+ "i": ["--identity"],
+ "k": ["--keyId"],
+ "u": ["--url"]
+};
+
+var usageStr = common.buildUsageString(Options) + ' key_name';
+
+
+
+///--- Mainline
+
+common.parseArguments(Options, ShortOptions, function(parsed) {
+ if (parsed.argv.remain.length < 1)
+ common.usage(usageStr, 1, 'key_name required');
+
+ var client = common.newClient(parsed);
+ client.getKey(parsed.argv.remain[0], common.callback);
+}, usageStr);
45 bin/sdc-getmachine
@@ -0,0 +1,45 @@
+#!/usr/bin/env node
+// -*- mode: js -*-
+// Copyright 2011 Joyent, Inc. All rights reserved.
+
+var path = require('path');
+var url = require('url');
+
+var common = require('../lib/cli_common');
+
+
+
+///--- Globals
+
+var Options = {
+ "account": String,
+ "debug": Boolean,
+ "help": Boolean,
+ "identity": path,
+ "keyId": String,
+ "url": url
+};
+
+var ShortOptions = {
+ "a": ["--account"],
+ "d": ["--debug"],
+ "h": ["--help"],
+ "?": ["--help"],
+ "i": ["--identity"],
+ "k": ["--keyId"],
+ "u": ["--url"]
+};
+
+var usageStr = common.buildUsageString(Options) + ' machine(id)';
+
+
+
+///--- Mainline
+
+common.parseArguments(Options, ShortOptions, function(parsed) {
+ if (parsed.argv.remain.length < 1)
+ common.usage(usageStr, 1, 'machine(id) required');
+
+ var client = common.newClient(parsed);
+ client.getMachine(parsed.argv.remain[0], common.callback);
+}, usageStr);
51 bin/sdc-getmachinesnapshot
@@ -0,0 +1,51 @@
+#!/usr/bin/env node
+// -*- mode: js -*-
+// Copyright 2011 Joyent, Inc. All rights reserved.
+
+var path = require('path');
+var url = require('url');
+
+var common = require('../lib/cli_common');
+
+
+
+///--- Globals
+
+var Options = {
+ "account": String,
+ "debug": Boolean,
+ "help": Boolean,
+ "identity": path,
+ "keyId": String,
+ "machine": String,
+ "url": url
+};
+
+var ShortOptions = {
+ "a": ["--account"],
+ "d": ["--debug"],
+ "h": ["--help"],
+ "?": ["--help"],
+ "i": ["--identity"],
+ "k": ["--keyId"],
+ "m": ["--machine"],
+ "u": ["--url"]
+};
+
+var usageStr = common.buildUsageString(Options) + ' snapshot';
+
+
+
+///--- Mainline
+
+common.parseArguments(Options, ShortOptions, function(parsed) {
+ if (!parsed.machine)
+ common.usage(usageStr, 1, 'machine required');
+ if (parsed.argv.remain.length < 1)
+ common.usage(usageStr, 1, 'snapshot required');
+
+ var client = common.newClient(parsed);
+ client.getMachineSnapshot(parsed.machine,
+ parsed.argv.remain[0],
+ common.callback);
+}, usageStr);
58 bin/sdc-getmachinetag
@@ -0,0 +1,58 @@
+#!/usr/bin/env node
+// -*- mode: js -*-
+// Copyright 2011 Joyent, Inc. All rights reserved.
+
+var path = require('path');
+var url = require('url');
+
+var common = require('../lib/cli_common');
+
+
+
+///--- Globals
+
+var Options = {
+ "account": String,
+ "debug": Boolean,
+ "help": Boolean,
+ "identity": path,
+ "keyId": String,
+ "machine": String,
+ "url": url
+};
+
+var ShortOptions = {
+ "a": ["--account"],
+ "d": ["--debug"],
+ "h": ["--help"],
+ "?": ["--help"],
+ "i": ["--identity"],
+ "k": ["--keyId"],
+ "m": ["--machine"],
+ "u": ["--url"]
+};
+
+var usageStr = common.buildUsageString(Options) + ' tag';
+
+
+
+///--- Mainline
+
+common.parseArguments(Options, ShortOptions, function(parsed) {
+ if (!parsed.machine)
+ common.usage(usageStr, 1, 'machine required');
+ if (parsed.argv.remain.length < 1)
+ common.usage(usageStr, 1, 'tag required');
+
+ function callback(err, obj) {
+ if (err) {
+ console.error(JSON.parse(err.message).message);
+ process.exit(3);
+ }
+
+ console.log(obj);
+ }
+
+ var client = common.newClient(parsed);
+ client.getMachineTag(parsed.machine, parsed.argv.remain[0], callback);
+}, usageStr);
45 bin/sdc-getpackage
@@ -0,0 +1,45 @@
+#!/usr/bin/env node
+// -*- mode: js -*-
+// Copyright 2011 Joyent, Inc. All rights reserved.
+
+var path = require('path');
+var url = require('url');
+
+var common = require('../lib/cli_common');
+
+
+
+///--- Globals
+
+var Options = {
+ "account": String,
+ "debug": Boolean,
+ "help": Boolean,
+ "identity": path,
+ "keyId": String,
+ "url": url
+};
+
+var ShortOptions = {
+ "a": ["--account"],
+ "d": ["--debug"],
+ "h": ["--help"],
+ "?": ["--help"],
+ "i": ["--identity"],
+ "k": ["--keyId"],
+ "u": ["--url"]
+};
+
+var usageStr = common.buildUsageString(Options) + ' package';
+
+
+
+///--- Mainline
+
+common.parseArguments(Options, ShortOptions, function(parsed) {
+ if (parsed.argv.remain.length < 1)
+ common.usage(usageStr, 1, 'package required');
+
+ var client = common.newClient(parsed);
+ client.getPackage(parsed.argv.remain[0], common.callback);
+}, usageStr);
40 bin/sdc-listdatacenters
@@ -0,0 +1,40 @@
+#!/usr/bin/env node
+// -*- mode: js -*-
+// Copyright 2011 Joyent, Inc. All rights reserved.
+
+var path = require('path');
+var url = require('url');
+
+var common = require('../lib/cli_common');
+
+
+
+///--- Globals
+
+var Options = {
+ "account": String,
+ "debug": Boolean,
+ "help": Boolean,
+ "identity": path,
+ "keyId": String,
+ "url": url
+};
+
+var ShortOptions = {
+ "a": ["--account"],
+ "d": ["--debug"],
+ "h": ["--help"],
+ "?": ["--help"],
+ "i": ["--identity"],
+ "k": ["--keyId"],
+ "u": ["--url"]
+};
+
+
+
+///--- Mainline
+
+common.parseArguments(Options, ShortOptions, function(parsed) {
+ var client = common.newClient(parsed);
+ client.listDatacenters(common.callback);
+});
40 bin/sdc-listdatasets
@@ -0,0 +1,40 @@
+#!/usr/bin/env node
+// -*- mode: js -*-
+// Copyright 2011 Joyent, Inc. All rights reserved.
+
+var path = require('path');
+var url = require('url');
+
+var common = require('../lib/cli_common');
+
+
+
+///--- Globals
+
+var Options = {
+ "account": String,
+ "debug": Boolean,
+ "help": Boolean,
+ "identity": path,
+ "keyId": String,
+ "url": url
+};
+
+var ShortOptions = {
+ "a": ["--account"],
+ "d": ["--debug"],
+ "h": ["--help"],
+ "?": ["--help"],
+ "i": ["--identity"],
+ "k": ["--keyId"],
+ "u": ["--url"]
+};
+
+
+
+///--- Mainline
+
+common.parseArguments(Options, ShortOptions, function(parsed) {
+ var client = common.newClient(parsed);
+ client.listDatasets(common.callback);
+});
40 bin/sdc-listinstrumentations
@@ -0,0 +1,40 @@
+#!/usr/bin/env node
+// -*- mode: js -*-
+// Copyright 2011 Joyent, Inc. All rights reserved.
+
+var path = require('path');
+var url = require('url');
+
+var common = require('../lib/cli_common');
+
+
+
+///--- Globals
+
+var Options = {
+ "account": String,
+ "debug": Boolean,
+ "help": Boolean,
+ "identity": path,
+ "keyId": String,
+ "url": url
+};
+
+var ShortOptions = {
+ "a": ["--account"],
+ "d": ["--debug"],
+ "h": ["--help"],
+ "?": ["--help"],
+ "i": ["--identity"],
+ "k": ["--keyId"],
+ "u": ["--url"]
+};
+
+
+
+///--- Mainline
+
+common.parseArguments(Options, ShortOptions, function(parsed) {
+ var client = common.newClient(parsed);
+ client.listInstrumentations(common.callback);
+});
40 bin/sdc-listkeys
@@ -0,0 +1,40 @@
+#!/usr/bin/env node
+// -*- mode: js -*-
+// Copyright 2011 Joyent, Inc. All rights reserved.
+
+var path = require('path');
+var url = require('url');
+
+var common = require('../lib/cli_common');
+
+
+
+///--- Globals
+
+var Options = {
+ "account": String,
+ "debug": Boolean,
+ "help": Boolean,
+ "identity": path,
+ "keyId": String,
+ "url": url
+};
+
+var ShortOptions = {
+ "a": ["--account"],
+ "d": ["--debug"],
+ "h": ["--help"],
+ "?": ["--help"],
+ "i": ["--identity"],
+ "k": ["--keyId"],
+ "u": ["--url"]
+};
+
+
+
+///--- Mainline
+
+common.parseArguments(Options, ShortOptions, function(parsed) {
+ var client = common.newClient(parsed);
+ client.listKeys(common.callback);
+});
82 bin/sdc-listmachines
@@ -0,0 +1,82 @@
+#!/usr/bin/env node
+// -*- mode: js -*-
+// Copyright 2011 Joyent, Inc. All rights reserved.
+
+var path = require('path');
+var url = require('url');
+
+var common = require('../lib/cli_common');
+
+
+
+///--- Globals
+
+var Options = {
+ "account": String,
+ "debug": Boolean,
+ "dataset": String,
+ "help": Boolean,
+ "identity": path,
+ "keyId": String,
+ "limit": Number,
+ "memory": Number,
+ "name": String,
+ "offset": Number,
+ "state": String,
+ "tag": [String, Array],
+ "type": String,
+ "tombstone": Number,
+ "url": url
+};
+
+var ShortOptions = {
+ "a": ["--account"],
+ "b": ["--tombstone"],
+ "d": ["--debug"],
+ "e": ["--dataset"],
+ "h": ["--help"],
+ "?": ["--help"],
+ "i": ["--identity"],
+ "k": ["--keyId"],
+ "l": ["--limit"],
+ "m": ["--memory"],
+ "n": ["--name"],
+ "o": ["--offset"],
+ "s": ["--state"],
+ "t": ["--tag"],
+ "y": ["--type"],
+ "u": ["--url"]
+};
+
+
+
+///--- Mainline
+
+common.parseArguments(Options, ShortOptions, function(parsed) {
+
+ var opts = {};
+ var tags = {};
+ if (parsed.dataset) opts.dataset = parsed.dataet;
+ if (parsed.limit) opts.limit = parsed.limit;
+ if (parsed.memory) opts.memory = parsed.memory;
+ if (parsed.name) opts.name = parsed.name;
+ if (parsed.offset) opts.offset = parsed.offset;
+ if (parsed.state) opts.state = parsed.state;
+ if (parsed.tombstone) opts.tombstone = parsed.tombstone;
+ if (parsed.type) opts.type = parsed.type;
+
+ if (parsed.tag) {
+ for (var i = 0; i < parsed.tag.length; i++) {
+ var tmp = parsed.tag[i].split('=');
+ if (!tmp || tmp.length !== 2) {
+ console.error(parsed.tag[i] + ' is an invalid tag; try foo=bar');
+ process.exit(1);
+ }
+ tags[tmp[0]] = tmp[1];
+ }
+ }
+
+ var client = common.newClient(parsed);
+ client.listMachines(opts, tags, common.callback);
+
+});
44 bin/sdc-listmachinesnapshots
@@ -0,0 +1,44 @@
+#!/usr/bin/env node
+// -*- mode: js -*-
+// Copyright 2011 Joyent, Inc. All rights reserved.
+
+var path = require('path');
+var url = require('url');
+
+var common = require('../lib/cli_common');
+
+
+
+///--- Globals
+
+var Options = {
+ "account": String,
+ "debug": Boolean,
+ "help": Boolean,
+ "identity": path,
+ "keyId": String,
+ "url": url
+};
+
+var ShortOptions = {
+ "a": ["--account"],
+ "d": ["--debug"],
+ "h": ["--help"],
+ "?": ["--help"],
+ "i": ["--identity"],
+ "k": ["--keyId"],
+ "u": ["--url"]
+};
+
+var usageStr = common.buildUsageString(Options) + ' machine';
+
+
+///--- Mainline
+
+common.parseArguments(Options, ShortOptions, function(parsed) {
+ if (parsed.argv.remain.length < 1)
+ common.usage(usageStr, 1, 'machine required');
+
+ var client = common.newClient(parsed);
+ client.listMachineSnapshots(parsed.argv.remain[0], common.callback);
+}, usageStr);
44 bin/sdc-listmachinetags
@@ -0,0 +1,44 @@
+#!/usr/bin/env node
+// -*- mode: js -*-
+// Copyright 2011 Joyent, Inc. All rights reserved.
+
+var path = require('path');
+var url = require('url');
+
+var common = require('../lib/cli_common');
+
+
+
+///--- Globals
+
+var Options = {
+ "account": String,
+ "debug": Boolean,
+ "help": Boolean,
+ "identity": path,
+ "keyId": String,
+ "url": url
+};
+
+var ShortOptions = {
+ "a": ["--account"],
+ "d": ["--debug"],
+ "h": ["--help"],
+ "?": ["--help"],
+ "i": ["--identity"],
+ "k": ["--keyId"],
+ "u": ["--url"]
+};
+
+var usageStr = common.buildUsageString(Options) + ' machine';
+
+
+///--- Mainline
+
+common.parseArguments(Options, ShortOptions, function(parsed) {
+ if (parsed.argv.remain.length < 1)
+ common.usage(usageStr, 1, 'machine required');
+
+ var client = common.newClient(parsed);
+ client.listMachineTags(parsed.argv.remain[0], common.callback);
+}, usageStr);
40 bin/sdc-listpackages
@@ -0,0 +1,40 @@
+#!/usr/bin/env node
+// -*- mode: js -*-
+// Copyright 2011 Joyent, Inc. All rights reserved.
+
+var path = require('path');
+var url = require('url');
+
+var common = require('../lib/cli_common');
+
+
+
+///--- Globals
+
+var Options = {
+ "account": String,
+ "debug": Boolean,
+ "help": Boolean,
+ "identity": path,
+ "keyId": String,
+ "url": url
+};
+
+var ShortOptions = {
+ "a": ["--account"],
+ "d": ["--debug"],
+ "h": ["--help"],
+ "?": ["--help"],
+ "i": ["--identity"],
+ "k": ["--keyId"],
+ "u": ["--url"]
+};
+
+
+
+///--- Mainline
+
+common.parseArguments(Options, ShortOptions, function(parsed) {
+ var client = common.newClient(parsed);
+ client.listPackages(common.callback);
+});
45 bin/sdc-rebootmachine
@@ -0,0 +1,45 @@
+#!/usr/bin/env node
+// -*- mode: js -*-
+// Copyright 2011 Joyent, Inc. All rights reserved.
+
+var path = require('path');
+var url = require('url');
+
+var common = require('../lib/cli_common');
+
+
+
+///--- Globals
+
+var Options = {
+ "account": String,
+ "debug": Boolean,
+ "help": Boolean,
+ "identity": path,
+ "keyId": String,
+ "url": url
+};
+
+var ShortOptions = {
+ "a": ["--account"],
+ "d": ["--debug"],
+ "h": ["--help"],
+ "?": ["--help"],
+ "i": ["--identity"],
+ "k": ["--keyId"],
+ "u": ["--url"]
+};
+
+var usageStr = common.buildUsageString(Options);
+usageStr += ' machine';
+
+
+///--- Mainline
+
+common.parseArguments(Options, ShortOptions, function(parsed) {
+ if (parsed.argv.remain.length < 1)
+ common.usage(usageStr, 1, 'machine required');
+
+ var client = common.newClient(parsed);
+ client.rebootMachine(parsed.argv.remain[0], common.callback);
+}, usageStr);
53 bin/sdc-resizemachine
@@ -0,0 +1,53 @@
+#!/usr/bin/env node
+// -*- mode: js -*-
+// Copyright 2011 Joyent, Inc. All rights reserved.
+
+var path = require('path');
+var url = require('url');
+
+var common = require('../lib/cli_common');
+
+
+
+///--- Globals
+
+var Options = {
+ "account": String,
+ "debug": Boolean,
+ "help": Boolean,
+ "identity": path,
+ "keyId": String,
+ "package": String,
+ "url": url
+};
+
+var ShortOptions = {
+ "a": ["--account"],
+ "d": ["--debug"],
+ "h": ["--help"],
+ "?": ["--help"],
+ "i": ["--identity"],
+ "k": ["--keyId"],
+ "p": ["--package"],
+ "u": ["--url"]
+};
+
+var usageStr = common.buildUsageString(Options);
+usageStr += ' machine';
+
+
+///--- Mainline
+
+common.parseArguments(Options, ShortOptions, function(parsed) {
+ if (parsed.argv.remain.length < 1)
+ common.usage(usageStr, 1, 'machine required');
+
+ var opts = {};
+ if (parsed['package'])
+ opts['package'] = parsed['package'];
+
+
+ var client = common.newClient(parsed);
+ return client.resizeMachine(parsed.argv.remain[0], opts, common.callback);
+
+}, usageStr);
194 bin/sdc-setup
@@ -0,0 +1,194 @@
+#!/usr/bin/env node
+// -*- mode: js -*-
+// Copyright 2011 Joyent, Inc. All rights reserved.
+
+var fs = require('fs');
+var path = require('path');
+var url = require('url');
+
+var nopt = require('nopt');
+var restify = require('restify');
+
+var common = require('../lib/cli_common');
+var CloudAPI = require('../lib/index').CloudAPI;
+
+
+
+///--- Globals
+
+var Options = {
+ "debug": Boolean,
+ "help": Boolean
+};
+
+var ShortOptions = {
+ "d": ["--debug"],
+ "h": ["--help"]
+};
+
+var buffer = '';
+var log = restify.log;
+var stdio = process.binding('stdio');
+
+var usageStr = common.buildUsageString(Options);
+usageStr += ' url';
+
+
+///--- Internal Functions
+
+// Totally ripped off from npm. Thanks isaacs@!
+
+function read(def, cb) {
+ var stdin = process.openStdin();
+ var val = '';
+ stdin.resume();
+ stdin.setEncoding('utf8');
+ stdin.on('error', cb)
+ stdin.on('data', function D (chunk) {
+ val += buffer + chunk;
+ buffer = '';
+ val = val.replace(/\r/g, '');
+ if (val.indexOf('\n') !== -1) {
+ if (val !== '\n')
+ val = val.replace(/^\n+/, '');
+ buffer = val.substr(val.indexOf('\n'));
+ val = val.substr(0, val.indexOf('\n'));
+ stdin.pause();
+ stdin.removeListener('data', D);
+ stdin.removeListener('error', cb);
+ val = val.trim() || def;
+ cb(null, val);
+ }
+ });
+}
+
+
+function silentRead(def, cb) {
+ var stdin = process.openStdin();
+ var val = '';
+ stdio.setRawMode(true);
+ stdin.resume();
+ stdin.on('error', cb)
+ stdin.on('data', function D (c) {
+ c = '' + c
+ switch (c) {
+ case '\n':
+ case '\r':
+ case '\r\n':
+ case '\u0004':
+ stdio.setRawMode(false);
+ stdin.removeListener('data', D);
+ stdin.removeListener('error', cb);
+ val = val.trim() || def;
+ process.stdout.write('\n');
+ process.stdout.flush();
+ stdin.pause();
+ return cb(null, val);
+ case '\u0003':
+ case '\0':
+ return cb('cancelled');
+ break;
+ default:
+ val += buffer + c;
+ buffer = '';
+ break;
+ }
+ });
+}
+
+
+function prompt(p, def, silent, cb) {
+ if (!cb) cb = silent, silent = false;
+ if (!cb) cb = def, def = undefined;
+ if (def) p += '('+ (silent ? '<hidden>' : def)+') ';
+ var r = (silent ? silentRead : read).bind(null, def, cb);
+ if (!process.stdout.write(p)) {
+ process.stdout.on('drain', function D () {
+ process.stdout.removeListener('drain', D);
+ r()
+ });
+ } else {
+ r();
+ }
+}
+
+
+
+///--- Mainline
+
+var parsed = nopt(Options, ShortOptions, process.argv, 2);
+if (parsed.help)
+ common.usage(usageStr);
+if (parsed.debug)
+ restify.log.level(restify.LogLevel.Trace);
+if (parsed.argv.remain.length < 1)
+ common.usage(usageStr, 1, 'url required');
+var url = parsed.argv.remain[0];
+
+
+prompt('Username (login): ', process.env.USER, function(err, username) {
+ if (err) {
+ console.error('Unable to read username: ' + err.message);
+ process.exit(5);
+ }
+
+ return prompt('Password: ', null, true, function(err, password) {
+ if (err) {
+ console.error('Unable to read password: ' + err.message);
+ process.exit(5);
+ }
+
+ if (!password || !password.length) {
+ console.error('You did not enter a password.');
+ process.exit(6);
+ }
+
+ var DEF_KEY = process.env.HOME + '/.ssh/id_rsa.pub';
+ return prompt('SSH public key: ', DEF_KEY, function(err, file) {
+ if (err) {
+ console.error('Unable to read key: ' + err.message);
+ process.exit(5);
+ }
+ log.debug('setup: user=%s, pass=%s, key=%s', username, password, file);
+ var key = common.loadKey(file);
+ var client = new CloudAPI({
+ url: url,
+ account: username,
+ noCache: true,
+ username: username,
+ password: password
+ });
+
+ // So that SSH agent support automagically works (if using the CLI),
+ // pick the name to be the same as what SSH Agent will pass in the
+ // comment field (well, the file name, not the full path).
+ var keyName = file.split('/');
+ var opts = {
+ name: keyName[keyName.length - 1].split('.')[0],
+ key: key
+ }
+ client.createKey(opts, function(err, key) {
+ if (err) {
+ if (err.httpCode >= 500) {
+ if (err.details && err.details.body) {
+ try {
+ console.error(JSON.parse(err.details.body).message);
+ } catch(e) {
+ console.error(err.message);
+ }
+ }
+ } else {
+ console.error(err.message);
+ }
+ process.exit(3);
+ }
+
+ console.log('\n\nIf you set these environment variables, your life will be easier:');
+ console.log('export SDC_CLI_URL=' + url);
+ console.log('export SDC_CLI_ACCOUNT=' + username);
+ console.log('export SDC_CLI_KEY_ID=' + key.name);
+ });
+ });
+ });
+});
+
45 bin/sdc-startmachine
@@ -0,0 +1,45 @@
+#!/usr/bin/env node
+// -*- mode: js -*-
+// Copyright 2011 Joyent, Inc. All rights reserved.
+
+var path = require('path');
+var url = require('url');
+
+var common = require('../lib/cli_common');
+
+
+
+///--- Globals
+
+var Options = {
+ "account": String,
+ "debug": Boolean,
+ "help": Boolean,
+ "identity": path,
+ "keyId": String,
+ "url": url
+};
+
+var ShortOptions = {
+ "a": ["--account"],
+ "d": ["--debug"],
+ "h": ["--help"],
+ "?": ["--help"],
+ "i": ["--identity"],
+ "k": ["--keyId"],
+ "u": ["--url"]
+};
+
+var usageStr = common.buildUsageString(Options);
+usageStr += ' machine';
+
+
+///--- Mainline
+
+common.parseArguments(Options, ShortOptions, function(parsed) {
+ if (parsed.argv.remain.length < 1)
+ common.usage(usageStr, 1, 'machine required');
+
+ var client = common.newClient(parsed);
+ client.startMachine(parsed.argv.remain[0], common.callback);
+}, usageStr);
51 bin/sdc-startmachinefromsnapshot
@@ -0,0 +1,51 @@
+#!/usr/bin/env node
+// -*- mode: js -*-
+// Copyright 2011 Joyent, Inc. All rights reserved.
+
+var path = require('path');
+var url = require('url');
+
+var common = require('../lib/cli_common');
+
+
+
+///--- Globals
+
+var Options = {
+ "account": String,
+ "debug": Boolean,
+ "help": Boolean,
+ "identity": path,
+ "keyId": String,
+ "snapshot": String,
+ "url": url
+};
+
+var ShortOptions = {
+ "a": ["--account"],
+ "d": ["--debug"],
+ "h": ["--help"],
+ "?": ["--help"],
+ "i": ["--identity"],
+ "k": ["--keyId"],
+ "n": ["--snapshot"],
+ "u": ["--url"]
+};
+
+var usageStr = common.buildUsageString(Options);
+usageStr += ' machine';
+
+
+///--- Mainline
+
+common.parseArguments(Options, ShortOptions, function(parsed) {
+ if (!parsed.snapshot)
+ common.usage(usageStr, 1, 'snapshot required');
+ if (parsed.argv.remain.length < 1)
+ common.usage(usageStr, 1, 'machine required');
+
+ var client = common.newClient(parsed);
+ client.startMachineFromSnapshot(parsed.argv.remain[0],
+ parsed.snapshot,
+ common.callback);
+}, usageStr);
45 bin/sdc-stopmachine
@@ -0,0 +1,45 @@
+#!/usr/bin/env node
+// -*- mode: js -*-
+// Copyright 2011 Joyent, Inc. All rights reserved.
+
+var path = require('path');
+var url = require('url');
+
+var common = require('../lib/cli_common');
+
+
+
+///--- Globals
+
+var Options = {
+ "account": String,
+ "debug": Boolean,
+ "help": Boolean,
+ "identity": path,
+ "keyId": String,
+ "url": url
+};
+
+var ShortOptions = {
+ "a": ["--account"],
+ "d": ["--debug"],
+ "h": ["--help"],
+ "?": ["--help"],
+ "i": ["--identity"],
+ "k": ["--keyId"],
+ "u": ["--url"]
+};
+
+var usageStr = common.buildUsageString(Options);
+usageStr += ' machine';
+
+
+///--- Mainline
+
+common.parseArguments(Options, ShortOptions, function(parsed) {
+ if (parsed.argv.remain.length < 1)
+ common.usage(usageStr, 1, 'machine required');
+
+ var client = common.newClient(parsed);
+ client.stopMachine(parsed.argv.remain[0], common.callback);
+}, usageStr);
227 lib/cli_common.js
@@ -0,0 +1,227 @@
+// Copyright 2011 Joyent, Inc. All rights reserved.
+
+var assert = require('assert');
+var fs = require('fs');
+var path = require('path');
+var url = require('url');
+
+var nopt = require('nopt');
+var restify = require('restify');
+var SSHAgentClient = require('ssh-agent');
+
+var CloudAPI = require('../lib/index').CloudAPI;
+
+
+path.name = 'path';
+url.name = 'url';
+
+
+
+///--- Globals
+
+var log = restify.log;
+
+
+///--- Internal Functions
+
+function usage(str, code, message) {
+ assert.ok(str);
+
+ var writer = console.log;
+ if (code)
+ writer = console.error;
+
+ if (message)
+ writer(message);
+ writer(path.basename(process.argv[1]) + ' ' + str);
+ process.exit(code || 0);
+}
+
+
+function buildUsageString(options) {
+ assert.ok(options);
+
+ var str = '';
+ for (var k in options) {
+ if (options.hasOwnProperty(k)) {
+ var o = options[k].name ? options[k].name.toLowerCase() : '';
+ str += '[--' + k + ' ' + o + '] ';
+ }
+ }
+ return str;
+}
+
+
+function loadKeyFromAgent(parsed, callback) {
+ assert.ok(parsed);
+ assert.ok(callback);
+
+ try {
+ var agent = new SSHAgentClient();
+ agent.requestIdentities(function(err, keys) {
+ if (err || !keys || !keys.length) {
+ log.debug('No ssh-agent identities found');
+ return callback(null);
+ }
+
+ var path = parsed.identity.split('/');
+ for (var i = 0; i < keys.length; i++) {
+ if (keys[i].type !== 'ssh-rsa')
+ continue;
+
+ var comment = keys[i].comment.split('/');
+ if (path[path.length - 1] === comment[comment.length - 1]) {
+ log.debug('Using ssh-agent identity: ' + keys[i].comment);
+ parsed.signingKey = keys[i];
+ parsed.sshAgent = agent;
+ return callback(parsed);
+ }
+
+ }
+
+ log.debug('No ssh-agent identity suitable: %o', keys);
+ return callback(null);
+ });
+ } catch (e) {
+ log.debug('Unable to load ssh-agent identities: ' + e);
+ return callback(null);
+ }
+}
+
+
+function loadSigningKey(parsed, callback) {
+ assert.ok(parsed);
+ assert.ok(callback);
+
+ fs.readFile(parsed.identity, 'ascii', function(err, file) {
+ if (err) {
+ console.error(err.message);
+ process.exit(2);
+ }
+ parsed.signingKey = file;
+ return callback(parsed);
+ });
+}
+
+
+
+///--- Exported API
+
+module.exports = {
+
+ /**
+ * Common callback for all CLI operations.
+ *
+ * @param {Error} err optional error object.
+ * @param {Object} obj optional response object.
+ */
+ callback: function(err, obj) {
+ if (err) {
+ console.error(err.message);
+ process.exit(3);
+ }
+
+ if (obj)
+ console.log(JSON.stringify(obj, null, 2));
+ },
+
+
+ usage: usage,
+
+
+ buildUsageString: buildUsageString,
+
+
+ parseArguments: function(options, shortOptions, callback, usageStr) {
+ assert.ok(options);
+ assert.ok(shortOptions);
+ assert.ok(callback);
+
+ if (!usageStr)
+ usageStr = buildUsageString(options);
+
+ var parsed = nopt(options, shortOptions, process.argv, 2);
+ if (parsed.help)
+ usage(usageStr);
+
+ if (parsed.debug)
+ restify.log.level(restify.LogLevel.Trace);
+
+ if (!parsed.identity)
+ parsed.identity = process.env.HOME + '/.ssh/id_rsa';
+
+ if (!parsed.keyId) {
+ if (process.env.SDC_CLI_KEY_ID) {
+ parsed.keyId = process.env.SDC_CLI_KEY_ID;
+ } else {
+ parsed.keyId = 'id_rsa';
+ }
+ }
+
+ if (!parsed.account)
+ parsed.account = process.env.SDC_CLI_ACCOUNT;
+ if (!parsed.account) {
+ usage(usageStr, 1,
+ 'Either -a or (env) SDC_CLI_ACCOUNT must be specified');
+ }
+
+ if (!parsed.url)
+ parsed.url = process.env.SDC_CLI_URL;
+ if (!parsed.url) {
+ usage(usageStr, 1,
+ 'Either -a or (env) SDC_CLI_URL must be specified');
+ }
+
+
+ return loadKeyFromAgent(parsed, function(_parsed) {
+
+ if (_parsed) {
+ log.debug('Found private key in SSH-Agent: %s', parsed.keyId);
+ return callback(_parsed);
+ }
+
+ return loadSigningKey(parsed, function(_parsed) {
+ if (!_parsed) {
+ console.error('Unable to load a private key for signing (not found)');
+ process.exit(2);
+ }
+
+ log.debug('Using private key from: %s', parsed.identity);
+ return callback(_parsed);
+ });
+ });
+ },
+
+
+ newClient: function(parsed) {
+ assert.ok(parsed);
+ assert.ok(parsed.keyId);
+ assert.ok(parsed.signingKey);
+
+ try {
+ return new CloudAPI({
+ url: parsed.url,
+ account: parsed.account,
+ noCache: true,
+ logLevel: restify.log.level(),
+ key: parsed.signingKey,
+ keyId: '/' + parsed.account + '/keys/' + parsed.keyId,
+ sshAgent: parsed.sshAgent
+ });
+ } catch (e) {
+ console.error(e.message);
+ process.exit(1);
+ }
+ },
+
+
+ loadKey: function(key) {
+ try {
+ return fs.readFileSync(key, 'ascii');
+ } catch (e) {
+ console.error('Unable to load key ' + key + ': ' + e);
+ process.exit(2);
+ }
+ }
+
+};
1,841 lib/cloudapi.js
1,841 additions, 0 deletions not shown because the diff is too large. Please use a local Git client to view these changes.
11 lib/index.js
@@ -0,0 +1,11 @@
+// Copyright 2011 Joyent, Inc. All rights reserved.
+
+var cloudapi = require('./cloudapi');
+
+module.exports = {
+
+ CloudAPI: cloudapi.CloudAPI,
+
+ createClient: cloudapi.createClient
+
+};
27 lib/utils.js
@@ -0,0 +1,27 @@
+// Copyright 2011 Joyent, Inc. All rights reserved.
+
+var sprintf = require('sprintf').sprintf;
+
+module.exports = {
+
+ /**
+ * Constructs a new HTTP Authorization header with the 'Basic' scheme.
+ *
+ * HTTP defines basic auth to be nothing but:
+ * Authorization: Basic Base64(<user>:<pass>)
+ *
+ * So that's what this gives back (the value for an Authorization header).
+ *
+ * @param {String} username duh.
+ * @param {String} password another duh.
+ * @return {String} value for an HTTP Authorization header.
+ */
+ basicAuth: function(username, password) {
+ if (!username) throw new TypeError('username required');
+ if (!password) throw new TypeError('password required');
+
+ var buffer = new Buffer(username + ':' + password, 'utf8');
+ return 'Basic ' + buffer.toString('base64');
+ }
+
+};
27 package.json
@@ -0,0 +1,27 @@
+{
+ "author": "Joyent, Inc. (http://www.joyent.com)",
+ "name": "smartdc",
+ "description": "Client SDK and CLI for the Joyent SmartDataCenter API",
+ "version": "6.1.0",
+ "homepage": "http://www.joyent.com/software/smartdatacenter",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/joyent/node-smartdc.git"
+ },
+ "main": "lib/index.js",