diff --git a/lib/cli.js b/lib/cli.js index b659650..21a8891 100644 --- a/lib/cli.js +++ b/lib/cli.js @@ -48,13 +48,24 @@ function CLI() { {name: 'version', type: 'bool', help: 'Print version and exit.'}, {names: ['verbose', 'v'], type: 'bool', help: 'Verbose/debug output.'}, - {names: ['profile', 'p'], type: 'string', env: 'SMRT_PROFILE', - helpArg: 'NAME', help: 'SMRT Profile to use.'} + // XXX disable profile selection for now + //{names: ['profile', 'p'], type: 'string', env: 'TRITON_PROFILE', + // helpArg: 'NAME', help: 'Triton client profile to use.'} ], helpOpts: { includeEnv: true, minHelpCol: 23 /* line up with option help */ - } + }, + helpSubcmds: [ + 'help', + { group: 'VMs/Machines/Containers' }, + 'create', + 'vms', + 'vm-audit', + { group: 'Images' }, + 'images', + { group: 'Other', unmatched: true } + ] }); } util.inherits(CLI, Cmdln); @@ -84,240 +95,21 @@ CLI.prototype.init = function (opts, args, callback) { Cmdln.prototype.init.apply(this, arguments); }; -CLI.prototype.do_foo = function do_foo(subcmd, opts, args, callback) { - console.log('XXX', subcmd, opts, args); - - this.triton.cloudapi.getAccount(function (err, body, res) { - console.log('XXX getAccount', err); - console.log('XXX getAccount', body); - callback(); - }); -}; +//CLI.prototype.do_profile = require('./do_profile'); -CLI.prototype.do_profile = require('./do_profile'); +// Images CLI.prototype.do_images = require('./do_images'); - - -CLI.prototype.do_provision = function (subcmd, opts, args, callback) { - if (opts.help) { - this.do_help('help', {}, [subcmd], callback); - return; - } else if (args.length > 1) { - return callback(new Error('too many args: ' + args)); - } - var sdc = this.sdc; - - assert.string(opts.image, '--image '); - assert.string(opts['package'], '--package '); - assert.number(opts.count) - - // XXX - /* - * Should all this move into sdc.createMachine? yes - * - * - lookup image, package, networks from args - * - assign names - * - start provisions (slight stagger, max N at a time) - * - return immediately, or '-w|--wait' - */ - async.series([ - function lookups(next) { - async.parallel([ - //XXX - //sdc.lookup(image) - ]) - }, - function provisions(next) { - - }, - function wait(next) { - next(); - } - ], function (err) { - callback(err); - }); -}; -CLI.prototype.do_provision.options = [ - { - names: ['help', 'h'], - type: 'bool', - help: 'Show this help.' - }, - { - names: ['dc', 'd'], - type: 'string', - helpArg: '', - help: 'The datacenter in which to provision. Required if the current' - + ' profile includes more than one datacenter. Use `sdc profile`' - + ' to list profiles and `sdc dcs` to list available datacenters.' - }, - { - names: ['image', 'i'], - type: 'string', - helpArg: '', - help: 'The machine image with which to provision. Required.' - }, - { - names: ['package', 'p'], - type: 'string', - helpArg: '', - help: 'The package or instance type for the new machine(s). Required.' - }, - { - names: ['name', 'n'], - type: 'string', - helpArg: '', - help: 'A name for the machine. If not specified, a short random name' - + ' will be generated.', - // TODO: for count>1 support '%d' code in name: foo0, foo1, ... - }, - { - names: ['count', 'c'], - type: 'positiveInteger', - 'default': 1, - helpArg: '', - help: 'The number of machines to provision. Default is 1.' - }, -]; -CLI.prototype.do_provision.help = ( - 'Provision a new virtual machine instance.\n' - + 'Alias: create-machine.\n' - + '\n' - + 'Usage:\n' - + ' {{name}} provision \n' - + '\n' - + '{{options}}' -); - - -CLI.prototype.do_machines = function (subcmd, opts, args, callback) { - var self = this; - if (opts.help) { - this.do_help('help', {}, [subcmd], callback); - return; - } else if (args.length > 1) { - return callback(new Error('too many args: ' + args)); - } - - var machines = []; - var errs = []; - var res = this.sdc.listMachines(); - res.on('data', function (dc, dcMachines) { - for (var i = 0; i < dcMachines.length; i++) { - dcMachines[i].dc = dc; - machines.push(dcMachines[i]); - } - }); - res.on('dcError', function (dc, dcErr) { - dcErr.dc = dc; - errs.push(dcErr); - }); - res.on('end', function () { - if (opts.json) { - p(JSON.stringify(machines, null, 4)); - } else { - /* BEGIN JSSTYLED */ - // TODO: get short output down to something like - // 'us-west-1 e91897cf testforyunong2 linux running 2013-11-08' - // 'us-west-1 e91897cf testforyunong2 ubuntu/13.3.0 running 2013-11-08' - /* END JSSTYLED */ - common.tabulate(machines, { - columns: 'dc,id,name,image,state,created', - sort: 'created', - validFields: 'dc,id,name,type,state,image,package,memory,' - + 'disk,created,updated,compute_node,primaryIp' - }); - } - var err; - if (errs.length === 1) { - err = errs[0]; - } else if (errs.length > 1) { - err = new errors.MultiError(errs); - } - callback(err); - }); -}; -CLI.prototype.do_machines.options = [ - { - names: ['help', 'h'], - type: 'bool', - help: 'Show this help.' - }, - { - names: ['json', 'j'], - type: 'bool', - help: 'JSON output.' - } -]; -CLI.prototype.do_machines.help = ( - 'List machines.\n' - + '\n' - + 'Usage:\n' - + ' {{name}} machines [...]\n' - + '\n' - + '{{options}}' -); +// VMs/Containers/Machines +CLI.prototype.do_create = require('./do_create'); +CLI.prototype.do_vms = require('./do_vms'); +CLI.prototype.do_vm_audit = require('./do_vm_audit'); -CLI.prototype.do_machine_audit = function (subcmd, opts, args, callback) { - var self = this; - if (opts.help) { - this.do_help('help', {}, [subcmd], callback); - return; - } else if (args.length > 1) { - //XXX Support multiple machines. - return callback(new Error('too many args: ' + args)); - } - var id = args[0]; - this.sdc.machineAudit({machine: id}, function (err, audit, dc) { - if (err) { - return callback(err); - } - for (var i = 0; i < audit.length; i++) { - audit[i].dc = dc; - } - if (opts.json) { - p(JSON.stringify(audit, null, 4)); - } else { - return callback(new error.InternalError("tabular output for audit NYI")); // XXX - //common.tabulate(audit, { - // columns: 'dc,id,name,state,created', - // sort: 'created', - // validFields: 'dc,id,name,type,state,image,package,memory,' - // + 'disk,created,updated,compute_node,primaryIp' - //}); - } - callback(); - }); -}; -CLI.prototype.do_machine_audit.options = [ - { - names: ['help', 'h'], - type: 'bool', - help: 'Show this help.' - }, - { - names: ['json', 'j'], - type: 'bool', - help: 'JSON output.' - } -]; -CLI.prototype.do_machine_audit.help = ( - 'List machine actions.\n' - + '\n' - + 'Note: On the *client*-side, this adds the "dc" attribute to each\n' - + 'audit record.\n' - + '\n' - + 'Usage:\n' - + ' {{name}} machine-audit \n' - + '\n' - + '{{options}}' -); //---- mainline diff --git a/lib/do_create.js b/lib/do_create.js new file mode 100644 index 0000000..e8b842d --- /dev/null +++ b/lib/do_create.js @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2015 Joyent Inc. All rights reserved. + * + * `triton images ...` + */ + +var format = require('util').format; +var tabula = require('tabula'); + +var errors = require('./errors'); + + +function do_create(subcmd, opts, args, callback) { + if (opts.help) { + this.do_help('help', {}, [subcmd], callback); + return; + } else if (args.length > 1) { + return callback(new Error('too many args: ' + args)); + } + var triton = this.triton; + + // XXX The smarts here should move to Triton class. + + assert.string(opts.image, '--image '); + assert.string(opts['package'], '--package '); + assert.number(opts.count) + + // XXX + /* + * Should all this move into sdc.createMachine? yes + * + * - lookup image, package, networks from args + * - assign names + * - start provisions (slight stagger, max N at a time) + * - return immediately, or '-w|--wait' + */ + async.series([ + function lookups(next) { + async.parallel([ + //XXX + //sdc.lookup(image) + ]) + }, + function provisions(next) { + + }, + function wait(next) { + next(); + } + ], function (err) { + callback(err); + }); +}; +do_create.options = [ + { + names: ['help', 'h'], + type: 'bool', + help: 'Show this help.' + }, + { + names: ['dc', 'd'], + type: 'string', + helpArg: '', + help: 'The datacenter in which to provision. Required if the current' + + ' profile includes more than one datacenter. Use `sdc profile`' + + ' to list profiles and `sdc dcs` to list available datacenters.' + }, + { + names: ['image', 'i'], + type: 'string', + helpArg: '', + help: 'The machine image with which to provision. Required.' + }, + { + names: ['package', 'p'], + type: 'string', + helpArg: '', + help: 'The package or instance type for the new machine(s). Required.' + }, + { + names: ['name', 'n'], + type: 'string', + helpArg: '', + help: 'A name for the machine. If not specified, a short random name' + + ' will be generated.', + // TODO: for count>1 support '%d' code in name: foo0, foo1, ... + }, + { + names: ['count', 'c'], + type: 'positiveInteger', + 'default': 1, + helpArg: '', + help: 'The number of machines to provision. Default is 1.' + }, +]; +do_create.help = ( + 'Create a new VM/container/machine.\n' + + '\n' + + 'Usage:\n' + + ' {{name}} provision \n' + + '\n' + + '{{options}}' +); +do_create.aliases = ['create-vm']; + +module.exports = do_create; \ No newline at end of file diff --git a/lib/do_vm_audit.js b/lib/do_vm_audit.js new file mode 100644 index 0000000..ec5d62b --- /dev/null +++ b/lib/do_vm_audit.js @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2015 Joyent Inc. All rights reserved. + * + * `triton vms ...` + */ + +var format = require('util').format; +var tabula = require('tabula'); + +var errors = require('./errors'); + + +do_vm_audit = function do_vm_audit(subcmd, opts, args, callback) { + var self = this; + if (opts.help) { + this.do_help('help', {}, [subcmd], callback); + return; + } else if (args.length > 1) { + //XXX Support multiple machines. + return callback(new Error('too many args: ' + args)); + } + + var id = args[0]; + this.sdc.machineAudit({machine: id}, function (err, audit, dc) { + if (err) { + return callback(err); + } + for (var i = 0; i < audit.length; i++) { + audit[i].dc = dc; + } + if (opts.json) { + p(JSON.stringify(audit, null, 4)); + } else { + return callback(new error.InternalError("tabular output for audit NYI")); // XXX + //common.tabulate(audit, { + // columns: 'dc,id,name,state,created', + // sort: 'created', + // validFields: 'dc,id,name,type,state,image,package,memory,' + // + 'disk,created,updated,compute_node,primaryIp' + //}); + } + callback(); + }); +}; +do_vm_audit.options = [ + { + names: ['help', 'h'], + type: 'bool', + help: 'Show this help.' + }, + { + names: ['json', 'j'], + type: 'bool', + help: 'JSON output.' + } +]; +do_vm_audit.help = ( + 'List instance actions.\n' + + '\n' + + 'Usage:\n' + + ' {{name}} vm-audit \n' + + '\n' + + '{{options}}' +); + + + +module.exports = do_vm_audit; \ No newline at end of file diff --git a/lib/do_vms.js b/lib/do_vms.js new file mode 100644 index 0000000..e6ab786 --- /dev/null +++ b/lib/do_vms.js @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2015 Joyent Inc. All rights reserved. + * + * `triton vms ...` + */ + +var format = require('util').format; +var tabula = require('tabula'); + +var errors = require('./errors'); + + +do_vms = function do_vms(subcmd, opts, args, callback) { + var self = this; + if (opts.help) { + this.do_help('help', {}, [subcmd], callback); + return; + } else if (args.length > 1) { + return callback(new Error('too many args: ' + args)); + } + + var machines = []; + var errs = []; + var res = this.sdc.listMachines(); + res.on('data', function (dc, dcMachines) { + for (var i = 0; i < dcMachines.length; i++) { + dcMachines[i].dc = dc; + machines.push(dcMachines[i]); + } + }); + res.on('dcError', function (dc, dcErr) { + dcErr.dc = dc; + errs.push(dcErr); + }); + res.on('end', function () { + if (opts.json) { + p(JSON.stringify(machines, null, 4)); + } else { + /* BEGIN JSSTYLED */ + // TODO: get short output down to something like + // 'us-west-1 e91897cf testforyunong2 linux running 2013-11-08' + // 'us-west-1 e91897cf testforyunong2 ubuntu/13.3.0 running 2013-11-08' + /* END JSSTYLED */ + common.tabulate(machines, { + columns: 'dc,id,name,image,state,created', + sort: 'created', + validFields: 'dc,id,name,type,state,image,package,memory,' + + 'disk,created,updated,compute_node,primaryIp' + }); + } + var err; + if (errs.length === 1) { + err = errs[0]; + } else if (errs.length > 1) { + err = new errors.MultiError(errs); + } + callback(err); + }); +}; +do_vms.options = [ + { + names: ['help', 'h'], + type: 'bool', + help: 'Show this help.' + }, + { + names: ['json', 'j'], + type: 'bool', + help: 'JSON output.' + } +]; +do_vms.help = ( + 'List VMs/machines/containers.\n' + + '\n' + + 'Usage:\n' + + ' {{name}} vms [...]\n' + + '\n' + + '{{options}}' +); + + +module.exports = do_vms; \ No newline at end of file