Add '-d,--data DATA' option to triton cloudapi ...
Also fix '-H,--header' option to `triton cloudapi`. It never worked.
This commit is contained in:
parent
6e44318f00
commit
d25df7c011
@ -43,6 +43,7 @@ var vasync = require('vasync');
|
|||||||
var auth = require('smartdc-auth');
|
var auth = require('smartdc-auth');
|
||||||
|
|
||||||
var bunyannoop = require('./bunyannoop');
|
var bunyannoop = require('./bunyannoop');
|
||||||
|
var common = require('./common');
|
||||||
var errors = require('./errors');
|
var errors = require('./errors');
|
||||||
var SaferJsonClient = require('./SaferJsonClient');
|
var SaferJsonClient = require('./SaferJsonClient');
|
||||||
|
|
||||||
@ -199,21 +200,24 @@ CloudApi.prototype._path = function _path(subpath /* , qparams, ... */) {
|
|||||||
/**
|
/**
|
||||||
* Cloud API request wrapper - modeled after http.request
|
* Cloud API request wrapper - modeled after http.request
|
||||||
*
|
*
|
||||||
* @param {Object|String} options - object or string for endpoint
|
* @param {Object|String} opts - object or string for endpoint
|
||||||
* - {String} path - URL endpoint to hit
|
* - {String} path - URL endpoint to hit
|
||||||
* - {String} method - HTTP(s) request method
|
* - {String} method - HTTP(s) request method
|
||||||
* - {Object} data - data to be passed
|
* - {Object} data - data to be passed
|
||||||
* @param {Function} callback passed via the restify client
|
* - {Object} headers - optional additional request headers
|
||||||
|
* @param {Function} cb passed via the restify client
|
||||||
*/
|
*/
|
||||||
CloudApi.prototype._request = function _request(options, callback) {
|
CloudApi.prototype._request = function _request(opts, cb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
if (typeof (options) === 'string')
|
if (typeof (opts) === 'string')
|
||||||
options = {path: options};
|
opts = {path: opts};
|
||||||
assert.object(options, 'options');
|
assert.object(opts, 'opts');
|
||||||
assert.func(callback, 'callback');
|
assert.optionalObject(opts.data, 'opts.data');
|
||||||
assert.optionalObject(options.data, 'options.data');
|
assert.optionalString(opts.method, 'opts.method');
|
||||||
|
assert.optionalObject(opts.headers, 'opts.headers');
|
||||||
|
assert.func(cb, 'cb');
|
||||||
|
|
||||||
var method = (options.method || 'GET').toLowerCase();
|
var method = (opts.method || 'GET').toLowerCase();
|
||||||
assert.ok(['get', 'post', 'put', 'delete', 'head'].indexOf(method) >= 0,
|
assert.ok(['get', 'post', 'put', 'delete', 'head'].indexOf(method) >= 0,
|
||||||
'invalid method given');
|
'invalid method given');
|
||||||
switch (method) {
|
switch (method) {
|
||||||
@ -226,17 +230,20 @@ CloudApi.prototype._request = function _request(options, callback) {
|
|||||||
|
|
||||||
self._getAuthHeaders(function (err, headers) {
|
self._getAuthHeaders(function (err, headers) {
|
||||||
if (err) {
|
if (err) {
|
||||||
callback(err);
|
cb(err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var opts = {
|
if (opts.headers) {
|
||||||
path: options.path,
|
common.objMerge(headers, opts.headers);
|
||||||
|
}
|
||||||
|
var reqOpts = {
|
||||||
|
path: opts.path,
|
||||||
headers: headers
|
headers: headers
|
||||||
};
|
};
|
||||||
if (options.data)
|
if (opts.data)
|
||||||
self.client[method](opts, options.data, callback);
|
self.client[method](reqOpts, opts.data, cb);
|
||||||
else
|
else
|
||||||
self.client[method](opts, callback);
|
self.client[method](reqOpts, cb);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -46,6 +46,32 @@ function deepObjCopy(obj) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Merge given objects into the given `target` object. Last one wins.
|
||||||
|
* The `target` is modified in place.
|
||||||
|
*
|
||||||
|
* var foo = {bar: 32};
|
||||||
|
* objMerge(foo, {bar: 42}, {bling: 'blam'});
|
||||||
|
*
|
||||||
|
* Adapted from tunnel-agent `mergeOptions`.
|
||||||
|
*/
|
||||||
|
function objMerge(target) {
|
||||||
|
for (var i = 1, len = arguments.length; i < len; ++i) {
|
||||||
|
var overrides = arguments[i];
|
||||||
|
if (typeof (overrides) === 'object') {
|
||||||
|
var keys = Object.keys(overrides);
|
||||||
|
for (var j = 0, keyLen = keys.length; j < keyLen; ++j) {
|
||||||
|
var k = keys[j];
|
||||||
|
if (overrides[k] !== undefined) {
|
||||||
|
target[k] = overrides[k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function zeroPad(n, width) {
|
function zeroPad(n, width) {
|
||||||
var s = String(n);
|
var s = String(n);
|
||||||
assert.number(width, 'width');
|
assert.number(width, 'width');
|
||||||
@ -852,6 +878,7 @@ function tildeSync(s) {
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
objCopy: objCopy,
|
objCopy: objCopy,
|
||||||
deepObjCopy: deepObjCopy,
|
deepObjCopy: deepObjCopy,
|
||||||
|
objMerge: objMerge,
|
||||||
zeroPad: zeroPad,
|
zeroPad: zeroPad,
|
||||||
boolFromString: boolFromString,
|
boolFromString: boolFromString,
|
||||||
jsonStream: jsonStream,
|
jsonStream: jsonStream,
|
||||||
|
@ -12,6 +12,9 @@
|
|||||||
|
|
||||||
var http = require('http');
|
var http = require('http');
|
||||||
|
|
||||||
|
var errors = require('./errors');
|
||||||
|
|
||||||
|
|
||||||
function do_cloudapi(subcmd, opts, args, callback) {
|
function do_cloudapi(subcmd, opts, args, callback) {
|
||||||
if (opts.help) {
|
if (opts.help) {
|
||||||
this.do_help('help', {}, [subcmd], callback);
|
this.do_help('help', {}, [subcmd], callback);
|
||||||
@ -21,34 +24,50 @@ function do_cloudapi(subcmd, opts, args, callback) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var path = args[0];
|
// Get `reqOpts` from given options.
|
||||||
|
var method = opts.method;
|
||||||
var reqopts = {
|
if (!method) {
|
||||||
method: opts.method.toLowerCase(),
|
if (opts.data) {
|
||||||
|
method = 'PUT';
|
||||||
|
} else {
|
||||||
|
method = 'GET';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var reqOpts = {
|
||||||
|
method: method.toLowerCase(),
|
||||||
headers: {},
|
headers: {},
|
||||||
path: path
|
path: args[0]
|
||||||
};
|
};
|
||||||
|
if (opts.header) {
|
||||||
// parse -H headers
|
for (var i = 0; i < opts.header.length; i++) {
|
||||||
for (var i = 0; i < opts.header.length; i++) {
|
var raw = opts.header[i];
|
||||||
var raw = opts.header[i];
|
var j = raw.indexOf(':');
|
||||||
var j = raw.indexOf(':');
|
if (j < 0) {
|
||||||
if (j < 0) {
|
callback(new errors.TritonError(
|
||||||
callback(new Error('failed to parse header: ' + raw));
|
'failed to parse header: ' + raw));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var header = raw.substr(0, j);
|
||||||
|
var value = raw.substr(j + 1).trimLeft();
|
||||||
|
reqOpts.headers[header] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (opts.data) {
|
||||||
|
try {
|
||||||
|
reqOpts.data = JSON.parse(opts.data);
|
||||||
|
} catch (parseErr) {
|
||||||
|
callback(new errors.TritonError(parseErr,
|
||||||
|
'given <data> is not valid JSON: ' + parseErr.message));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var header = raw.substr(0, j);
|
|
||||||
var value = raw.substr(j + 1).leftTrim();
|
|
||||||
|
|
||||||
reqopts.headers[header] = value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.tritonapi.cloudapi._request(reqopts, function (err, req, res, body) {
|
this.tritonapi.cloudapi._request(reqOpts, function (err, req, res, body) {
|
||||||
if (err) {
|
if (err) {
|
||||||
callback(err);
|
callback(err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (opts.headers || reqopts.method === 'head') {
|
if (opts.headers || reqOpts.method === 'head') {
|
||||||
console.error('%s/%s %d %s',
|
console.error('%s/%s %d %s',
|
||||||
req.connection.encrypted ? 'HTTPS' : 'HTTP',
|
req.connection.encrypted ? 'HTTPS' : 'HTTP',
|
||||||
res.httpVersion,
|
res.httpVersion,
|
||||||
@ -60,7 +79,7 @@ function do_cloudapi(subcmd, opts, args, callback) {
|
|||||||
console.error();
|
console.error();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reqopts.method !== 'head')
|
if (reqOpts.method !== 'head')
|
||||||
console.log(JSON.stringify(body, null, 4));
|
console.log(JSON.stringify(body, null, 4));
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
@ -75,26 +94,33 @@ do_cloudapi.options = [
|
|||||||
{
|
{
|
||||||
names: ['method', 'X'],
|
names: ['method', 'X'],
|
||||||
type: 'string',
|
type: 'string',
|
||||||
default: 'GET',
|
helpArg: '<method>',
|
||||||
help: 'Request method to use. Default is "GET".'
|
help: 'Request method to use. Default is "GET".'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
names: ['header', 'H'],
|
names: ['header', 'H'],
|
||||||
type: 'arrayOfString',
|
type: 'arrayOfString',
|
||||||
default: [],
|
helpArg: '<header>',
|
||||||
help: 'Headers to send with request.'
|
help: 'Headers to send with request.'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
names: ['headers', 'i'],
|
names: ['headers', 'i'],
|
||||||
type: 'bool',
|
type: 'bool',
|
||||||
help: 'Print response headers to stderr.'
|
help: 'Print response headers to stderr.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
names: ['data', 'd'],
|
||||||
|
type: 'string',
|
||||||
|
helpArg: '<data>',
|
||||||
|
help: 'Add POST data. This must be valid JSON.'
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
do_cloudapi.help = (
|
do_cloudapi.help = (
|
||||||
'Raw cloudapi request.\n'
|
'Raw cloudapi request.\n'
|
||||||
+ '\n'
|
+ '\n'
|
||||||
+ 'Usage:\n'
|
+ 'Usage:\n'
|
||||||
+ ' {{name}} cloudapi [-X method] [-H header=value] <endpoint>\n'
|
+ ' {{name}} cloudapi [-X <method>] [-H <header=value>] \\\n'
|
||||||
|
+ ' [-d <data>] <endpoint>\n'
|
||||||
+ '\n'
|
+ '\n'
|
||||||
+ '{{options}}'
|
+ '{{options}}'
|
||||||
);
|
);
|
||||||
|
Reference in New Issue
Block a user