diff --git a/lib/cli.js b/lib/cli.js index e4d5dba..ce88c1e 100644 --- a/lib/cli.js +++ b/lib/cli.js @@ -194,12 +194,6 @@ function CLI() { 'help', 'profiles', 'profile', - { group: 'Other Commands' }, - 'info', - 'account', - 'keys', - 'services', - 'datacenters', { group: 'Instances (aka VMs/Machines/Containers)' }, 'create-instance', 'instances', @@ -211,15 +205,18 @@ function CLI() { 'delete-instance', 'wait-instance', 'ssh', - { group: 'Images' }, + { group: 'Images, Packages, Networks' }, 'images', 'image', - { group: 'Packages' }, - 'packages', 'package', - { group: 'Networks' }, 'networks', - 'network' + 'network', + { group: 'Other Commands' }, + 'info', + 'account', + 'keys', + 'services', + 'datacenters' ], helpBody: [ /* BEGIN JSSTYLED */ diff --git a/lib/do_package.js b/lib/do_package/do_get.js similarity index 83% rename from lib/do_package.js rename to lib/do_package/do_get.js index a7a40df..38d83b9 100644 --- a/lib/do_package.js +++ b/lib/do_package/do_get.js @@ -7,15 +7,15 @@ /* * Copyright 2015 Joyent, Inc. * - * `triton package ...` + * `triton package get ...` */ var format = require('util').format; -var errors = require('./errors'); +var errors = require('../errors'); -function do_package(subcmd, opts, args, callback) { +function do_get(subcmd, opts, args, callback) { if (opts.help) { this.do_help('help', {}, [subcmd], callback); return; @@ -24,7 +24,7 @@ function do_package(subcmd, opts, args, callback) { 'incorrect number of args (%d)', args.length))); } - this.tritonapi.getPackage(args[0], function onRes(err, pkg) { + this.top.tritonapi.getPackage(args[0], function onRes(err, pkg) { if (err) { return callback(err); } @@ -38,7 +38,7 @@ function do_package(subcmd, opts, args, callback) { }); } -do_package.options = [ +do_get.options = [ { names: ['help', 'h'], type: 'bool', @@ -50,7 +50,7 @@ do_package.options = [ help: 'JSON stream output.' } ]; -do_package.help = ( +do_get.help = ( /* BEGIN JSSTYLED */ 'Get a package.\n' + '\n' + @@ -66,6 +66,4 @@ do_package.help = ( /* END JSSTYLED */ ); -do_package.aliases = ['pkg']; - -module.exports = do_package; +module.exports = do_get; diff --git a/lib/do_package/do_list.js b/lib/do_package/do_list.js new file mode 100644 index 0000000..c014827 --- /dev/null +++ b/lib/do_package/do_list.js @@ -0,0 +1,186 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* + * Copyright 2015 Joyent, Inc. + * + * `triton package list ...` + */ + +var tabula = require('tabula'); + +var common = require('../common'); + + +// valid filters to pass to cloudapi.listPackages +var validFilters = [ + 'name', + 'memory', + 'disk', + 'swap', + 'lwps', + 'version', + 'vcpus', + 'group' +]; + +// columns default without -o +var columnsDefault = 'shortid,name,default,memory,swap,disk,vcpus'; + +// columns default with -l +var columnsDefaultLong = 'id,name,default,memory,swap,disk,vcpus'; + +// sort default with -s +var sortDefault = '_groupPlus,memory'; + +function do_list(subcmd, opts, args, callback) { + var i; + if (opts.help) { + this.do_help('help', {}, [subcmd], callback); + return; + } + + var columns = columnsDefault; + if (opts.o) { + columns = opts.o; + } else if (opts.long) { + columns = columnsDefaultLong; + } + columns = columns.split(','); + var rightAligned = {memory: true, disk: true, swap: true, + vcpus: true, lwps: true}; + for (i = 0; i < columns.length; i++) { + if (rightAligned[columns[i]]) { + columns[i] = {lookup: columns[i], align: 'right'}; + } + } + + var sort = opts.s.split(','); + + var listOpts; + try { + listOpts = common.kvToObj(args, validFilters); + } catch (e) { + callback(e); + return; + } + + this.top.tritonapi.cloudapi.listPackages(listOpts, function (err, pkgs) { + if (err) { + callback(err); + return; + } + if (opts.json) { + common.jsonStream(pkgs); + } else { + for (i = 0; i < pkgs.length; i++) { + var pkg = pkgs[i]; + pkg.shortid = pkg.id.split('-', 1)[0]; + + /* + * We take a slightly "smarter" view of "group" for default + * sorting, to accomodate usage in the JPC. More recent + * common usage is for packages to have "foo-*" naming. + * JPC includes package sets of yore *and* recent that don't + * use the "group" field. We secondarily separate those + * on a possible "foo-" prefix. + */ + pkg._groupPlus = (pkg.group || (pkg.name.indexOf('-') === -1 + ? '' : pkg.name.split('-', 1)[0])); + + if (!opts.p) { + pkg.memoryHuman = common.humanSizeFromBytes({ + precision: 1, + narrow: true + }, pkg.memory * 1024 * 1024); + pkg.swapHuman = common.humanSizeFromBytes({ + precision: 1, + narrow: true + }, pkg.swap * 1024 * 1024); + pkg.diskHuman = common.humanSizeFromBytes({ + precision: 1, + narrow: true + }, pkg.disk * 1024 * 1024); + pkg.vcpusHuman = pkg.vcpus === 0 ? '-' : pkg.vcpus; + } + } + if (!opts.p) { + columns = columns.map(function (c) { + switch (c.lookup || c) { + case 'memory': + return {lookup: 'memoryHuman', name: 'MEMORY', + align: 'right'}; + case 'swap': + return {lookup: 'swapHuman', name: 'SWAP', + align: 'right'}; + case 'disk': + return {lookup: 'diskHuman', name: 'DISK', + align: 'right'}; + case 'vcpus': + return {lookup: 'vcpusHuman', name: 'VCPUS', + align: 'right'}; + default: + return c; + } + }); + } + tabula(pkgs, { + skipHeader: opts.H, + columns: columns, + sort: sort + }); + } + callback(); + }); +} + +do_list.options = [ + { + names: ['help', 'h'], + type: 'bool', + help: 'Show this help.' + } +].concat(common.getCliTableOptions({ + includeLong: true, + sortDefault: sortDefault +})).concat([ + { + names: ['p'], + type: 'bool', + help: 'Display numbers in parsable (exact) values.' + } +]); + +do_list.help = [ + /* BEGIN JSSTYLED */ + 'List packgaes.', + '', + 'Usage:', + ' {{name}} packages []', + '', + '{{options}}', + 'Filters:', + ' FIELD=VALUE Field equality filter. Supported fields: ', + ' account, owner, state, name, os, and type.', + ' FIELD=true|false Field boolean filter. Supported fields: public.', + ' FIELD=~SUBSTRING Field substring filter. Supported fields: name', + '', + 'Notes on some fields:', + '- The "memory" (a.k.a. RAM), "swap", and "disk" fields are shown in', + ' more human readable units in tabular output (i.e. if neither "-p" nor', + ' "-j" is specified.', + '- The "vcpus" field is only relevant for KVM instances. It is therefore', + ' typically set to zero for packages not intended for KVM usage. This', + ' zero is shown as "-" in tabular output.', + '', + 'Examples:', + ' {{name}} packages memory=8192 # list packages with 8G RAM' + /* END JSSTYLED */ +].join('\n'); + +do_list.aliases = ['ls']; + +module.exports = do_list; diff --git a/lib/do_package/index.js b/lib/do_package/index.js new file mode 100644 index 0000000..7823a2b --- /dev/null +++ b/lib/do_package/index.js @@ -0,0 +1,52 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* + * Copyright 2015 Joyent, Inc. + * + * `triton package ...` + */ + +var Cmdln = require('cmdln').Cmdln; +var util = require('util'); + + + +// ---- CLI class + +function PackageCLI(top) { + this.top = top; + Cmdln.call(this, { + name: top.name + ' package', + /* BEGIN JSSTYLED */ + desc: [ + 'List and get Triton packages.' + ].join('\n'), + /* END JSSTYLED */ + helpOpts: { + minHelpCol: 24 /* line up with option help */ + }, + helpSubcmds: [ + 'help', + 'list', + 'get' + ] + }); +} +util.inherits(PackageCLI, Cmdln); + +PackageCLI.prototype.init = function init(opts, args, cb) { + this.log = this.top.log; + Cmdln.prototype.init.apply(this, arguments); +}; + +PackageCLI.prototype.do_list = require('./do_list'); +PackageCLI.prototype.do_get = require('./do_get'); + + +PackageCLI.aliases = ['pkg']; + +module.exports = PackageCLI; diff --git a/lib/do_packages.js b/lib/do_packages.js index c20cbde..f4ad952 100644 --- a/lib/do_packages.js +++ b/lib/do_packages.js @@ -7,179 +7,23 @@ /* * Copyright 2015 Joyent, Inc. * - * `triton packages ...` + * `triton packages ...` bwcompat shortcut for `triton packages list ...`. */ -var tabula = require('tabula'); - -var common = require('./common'); - -// valid filters to pass to cloudapi.listPackages -var validFilters = [ - 'name', - 'memory', - 'disk', - 'swap', - 'lwps', - 'version', - 'vcpus', - 'group' -]; - -// columns default without -o -var columnsDefault = 'shortid,name,default,memory,swap,disk,vcpus'; - -// columns default with -l -var columnsDefaultLong = 'id,name,default,memory,swap,disk,vcpus'; - -// sort default with -s -var sortDefault = '_groupPlus,memory'; - function do_packages(subcmd, opts, args, callback) { - var i; - if (opts.help) { - this.do_help('help', {}, [subcmd], callback); - return; - } - - var columns = columnsDefault; - if (opts.o) { - columns = opts.o; - } else if (opts.long) { - columns = columnsDefaultLong; - } - columns = columns.split(','); - var rightAligned = {memory: true, disk: true, swap: true, - vcpus: true, lwps: true}; - for (i = 0; i < columns.length; i++) { - if (rightAligned[columns[i]]) { - columns[i] = {lookup: columns[i], align: 'right'}; - } - } - - var sort = opts.s.split(','); - - var listOpts; - try { - listOpts = common.kvToObj(args, validFilters); - } catch (e) { - callback(e); - return; - } - - this.tritonapi.cloudapi.listPackages(listOpts, function (err, pkgs) { - if (err) { - callback(err); - return; - } - if (opts.json) { - common.jsonStream(pkgs); - } else { - for (i = 0; i < pkgs.length; i++) { - var pkg = pkgs[i]; - pkg.shortid = pkg.id.split('-', 1)[0]; - - /* - * We take a slightly "smarter" view of "group" for default - * sorting, to accomodate usage in the JPC. More recent - * common usage is for packages to have "foo-*" naming. - * JPC includes package sets of yore *and* recent that don't - * use the "group" field. We secondarily separate those - * on a possible "foo-" prefix. - */ - pkg._groupPlus = (pkg.group || (pkg.name.indexOf('-') === -1 - ? '' : pkg.name.split('-', 1)[0])); - - if (!opts.p) { - pkg.memoryHuman = common.humanSizeFromBytes({ - precision: 1, - narrow: true - }, pkg.memory * 1024 * 1024); - pkg.swapHuman = common.humanSizeFromBytes({ - precision: 1, - narrow: true - }, pkg.swap * 1024 * 1024); - pkg.diskHuman = common.humanSizeFromBytes({ - precision: 1, - narrow: true - }, pkg.disk * 1024 * 1024); - pkg.vcpusHuman = pkg.vcpus === 0 ? '-' : pkg.vcpus; - } - } - if (!opts.p) { - columns = columns.map(function (c) { - switch (c.lookup || c) { - case 'memory': - return {lookup: 'memoryHuman', name: 'MEMORY', - align: 'right'}; - case 'swap': - return {lookup: 'swapHuman', name: 'SWAP', - align: 'right'}; - case 'disk': - return {lookup: 'diskHuman', name: 'DISK', - align: 'right'}; - case 'vcpus': - return {lookup: 'vcpusHuman', name: 'VCPUS', - align: 'right'}; - default: - return c; - } - }); - } - tabula(pkgs, { - skipHeader: opts.H, - columns: columns, - sort: sort - }); - } - callback(); - }); + var subcmdArgv = ['node', 'triton', 'package', 'list'].concat(args); + this.dispatch('package', subcmdArgv, callback); } -do_packages.options = [ - { - names: ['help', 'h'], - type: 'bool', - help: 'Show this help.' - } -].concat(common.getCliTableOptions({ - includeLong: true, - sortDefault: sortDefault -})).concat([ - { - names: ['p'], - type: 'bool', - help: 'Display numbers in parsable (exact) values.' - } -]); - do_packages.help = [ - /* BEGIN JSSTYLED */ - 'List packgaes.', + 'A shortcut for "triton package list".', '', 'Usage:', - ' {{name}} packages []', - '', - '{{options}}', - 'Filters:', - ' FIELD=VALUE Field equality filter. Supported fields: ', - ' account, owner, state, name, os, and type.', - ' FIELD=true|false Field boolean filter. Supported fields: public.', - ' FIELD=~SUBSTRING Field substring filter. Supported fields: name', - '', - 'Notes on some fields:', - '- The "memory" (a.k.a. RAM), "swap", and "disk" fields are shown in', - ' more human readable units in tabular output (i.e. if neither "-p" nor', - ' "-j" is specified.', - '- The "vcpus" field is only relevant for KVM instances. It is therefore', - ' typically set to zero for packages not intended for KVM usage. This', - ' zero is shown as "-" in tabular output.', - '', - 'Examples:', - ' {{name}} packages memory=8192 # list packages with 8G RAM' - /* END JSSTYLED */ + ' {{name}} packages ...' ].join('\n'); do_packages.aliases = ['pkgs']; +do_packages.hidden = true; + module.exports = do_packages; diff --git a/test/integration/cli-manage-workflow.test.js b/test/integration/cli-manage-workflow.test.js index 3e07c77..a76832e 100644 --- a/test/integration/cli-manage-workflow.test.js +++ b/test/integration/cli-manage-workflow.test.js @@ -129,7 +129,7 @@ test('triton manage workflow', opts, function (tt) { return; } - h.safeTriton(t, ['pkgs', '-j'], function (stdout) { + h.safeTriton(t, ['pkg', 'list', '-j'], function (stdout) { var pkgs = _jsonStreamParse(stdout); // Smallest RAM first. tabula.sortArrayOfObjects(pkgs, ['memory']);