PUBAPI-1233/PUBAPI-1234 Add firewalls and snapshots to node-triton
triton fwrule ... triton instance snapshot ... Reviewed-By: Trent Mick (with some contributions)
This commit is contained in:
		
							parent
							
								
									a1df6e0fe7
								
							
						
					
					
						commit
						634350018a
					
				@ -1,7 +1,9 @@
 | 
				
			|||||||
# node-triton changelog
 | 
					# node-triton changelog
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## 4.5.3 (not yet released)
 | 
					## 4.6.0 (not yet released)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- PUBAPI-1233 firewalls: `triton fwrule ...`
 | 
				
			||||||
 | 
					- PUBAPI-1234 instance snapshots: `triton inst snapshot ...`
 | 
				
			||||||
- #52 Fix 'triton ssh ...' stdout/stderr to fully flush with node >= 4.x.
 | 
					- #52 Fix 'triton ssh ...' stdout/stderr to fully flush with node >= 4.x.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -13,3 +13,10 @@ function complete_tritonupdateaccountfield {
 | 
				
			|||||||
    candidates="{{UPDATE_ACCOUNT_FIELDS}}"
 | 
					    candidates="{{UPDATE_ACCOUNT_FIELDS}}"
 | 
				
			||||||
    compgen $compgen_opts -W "$candidates" -- "$word"
 | 
					    compgen $compgen_opts -W "$candidates" -- "$word"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function complete_tritonupdatefwrulefield {
 | 
				
			||||||
 | 
					    local word="$1"
 | 
				
			||||||
 | 
					    local candidates
 | 
				
			||||||
 | 
					    candidates="{{UPDATE_FWRULE_FIELDS}}"
 | 
				
			||||||
 | 
					    compgen $compgen_opts -W "$candidates" -- "$word"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -217,10 +217,11 @@ function CLI() {
 | 
				
			|||||||
            'stop',
 | 
					            'stop',
 | 
				
			||||||
            'reboot',
 | 
					            'reboot',
 | 
				
			||||||
            'ssh',
 | 
					            'ssh',
 | 
				
			||||||
            { group: 'Images, Packages, Networks' },
 | 
					            { group: 'Images, Packages, Networks, Firewall Rules' },
 | 
				
			||||||
            'image',
 | 
					            'image',
 | 
				
			||||||
            'package',
 | 
					            'package',
 | 
				
			||||||
            'network',
 | 
					            'network',
 | 
				
			||||||
 | 
					            'fwrule',
 | 
				
			||||||
            { group: 'Other Commands' },
 | 
					            { group: 'Other Commands' },
 | 
				
			||||||
            'info',
 | 
					            'info',
 | 
				
			||||||
            'account',
 | 
					            'account',
 | 
				
			||||||
@ -354,6 +355,9 @@ CLI.prototype.do_info = require('./do_info');
 | 
				
			|||||||
CLI.prototype.do_key = require('./do_key');
 | 
					CLI.prototype.do_key = require('./do_key');
 | 
				
			||||||
CLI.prototype.do_keys = require('./do_keys');
 | 
					CLI.prototype.do_keys = require('./do_keys');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Firewall rules
 | 
				
			||||||
 | 
					CLI.prototype.do_fwrule = require('./do_fwrule');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Images
 | 
					// Images
 | 
				
			||||||
CLI.prototype.do_images = require('./do_images');
 | 
					CLI.prototype.do_images = require('./do_images');
 | 
				
			||||||
CLI.prototype.do_image = require('./do_image');
 | 
					CLI.prototype.do_image = require('./do_image');
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										429
									
								
								lib/cloudapi2.js
									
									
									
									
									
								
							
							
						
						
									
										429
									
								
								lib/cloudapi2.js
									
									
									
									
									
								
							@ -752,7 +752,30 @@ CloudApi.prototype.rebootMachine = function rebootMachine(uuid, callback) {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * internal function for start/stop/reboot
 | 
					 * Enables machine firewall.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param {String} id (required) The machine id.
 | 
				
			||||||
 | 
					 * @param {Function} callback of the form `function (err, machine, res)`
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					CloudApi.prototype.enableMachineFirewall =
 | 
				
			||||||
 | 
					function enableMachineFirewall(uuid, callback) {
 | 
				
			||||||
 | 
					    return this._doMachine('enable_firewall', uuid, callback);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Disables machine firewall.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param {String} id (required) The machine id.
 | 
				
			||||||
 | 
					 * @param {Function} callback of the form `function (err, machine, res)`
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					CloudApi.prototype.disableMachineFirewall =
 | 
				
			||||||
 | 
					function disableMachineFirewall(uuid, callback) {
 | 
				
			||||||
 | 
					    return this._doMachine('disable_firewall', uuid, callback);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * internal function for start/stop/reboot/enable_firewall/disable_firewall
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
CloudApi.prototype._doMachine = function _doMachine(action, uuid, callback) {
 | 
					CloudApi.prototype._doMachine = function _doMachine(action, uuid, callback) {
 | 
				
			||||||
    var self = this;
 | 
					    var self = this;
 | 
				
			||||||
@ -1010,6 +1033,26 @@ CloudApi.prototype.replaceMachineTags = function replaceMachineTags(opts, cb) {
 | 
				
			|||||||
    });
 | 
					    });
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * <http://apidocs.joyent.com/cloudapi/#DeleteMachineTags>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param {Object} opts:
 | 
				
			||||||
 | 
					 *      - @param {UUID} id: The machine UUID. Required.
 | 
				
			||||||
 | 
					 * @param {Function} cb - `function (err, res)`
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					CloudApi.prototype.deleteMachineTags = function deleteMachineTags(opts, cb) {
 | 
				
			||||||
 | 
					    assert.object(opts, 'opts');
 | 
				
			||||||
 | 
					    assert.uuid(opts.id, 'opts.id');
 | 
				
			||||||
 | 
					    assert.func(cb, 'cb');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this._request({
 | 
				
			||||||
 | 
					        method: 'DELETE',
 | 
				
			||||||
 | 
					        path: format('/%s/machines/%s/tags', this.account, opts.id)
 | 
				
			||||||
 | 
					    }, function (err, req, res) {
 | 
				
			||||||
 | 
					        cb(err, res);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * <http://apidocs.joyent.com/cloudapi/#DeleteMachineTag>
 | 
					 * <http://apidocs.joyent.com/cloudapi/#DeleteMachineTag>
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
@ -1034,27 +1077,399 @@ CloudApi.prototype.deleteMachineTag = function deleteMachineTag(opts, cb) {
 | 
				
			|||||||
    });
 | 
					    });
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// --- snapshots
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * <http://apidocs.joyent.com/cloudapi/#DeleteMachineTags>
 | 
					 * Creates a new snapshot for a given machine.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @param {Object} opts:
 | 
					 * The machine cannot be a KVM brand.
 | 
				
			||||||
 *      - @param {UUID} id: The machine UUID. Required.
 | 
					 *
 | 
				
			||||||
 * @param {Function} cb - `function (err, res)`
 | 
					 * Returns a snapshot object.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param {Object} options object containing:
 | 
				
			||||||
 | 
					 *      - {String} id (required) the machine's id.
 | 
				
			||||||
 | 
					 *      - {String} name (optional) name for new snapshot
 | 
				
			||||||
 | 
					 * @param {Function} callback of the form f(err, snapshot, res).
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
CloudApi.prototype.deleteMachineTags = function deleteMachineTags(opts, cb) {
 | 
					CloudApi.prototype.createMachineSnapshot =
 | 
				
			||||||
 | 
					function createMachineSnapshot(opts, cb) {
 | 
				
			||||||
 | 
					    assert.object(opts, 'opts');
 | 
				
			||||||
 | 
					    assert.uuid(opts.id, 'opts.id');
 | 
				
			||||||
 | 
					    assert.optionalString(opts.name, 'opts.name');
 | 
				
			||||||
 | 
					    assert.func(cb, 'cb');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var data = {};
 | 
				
			||||||
 | 
					    if (opts.name)
 | 
				
			||||||
 | 
					        data.name = opts.name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this._request({
 | 
				
			||||||
 | 
					        method: 'POST',
 | 
				
			||||||
 | 
					        path: format('/%s/machines/%s/snapshots', this.account, opts.id),
 | 
				
			||||||
 | 
					        data: data
 | 
				
			||||||
 | 
					    }, function (err, req, res, body) {
 | 
				
			||||||
 | 
					        cb(err, body, res);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Wait for a machine's snapshot to go one of a set of specfic states.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param {Object} options
 | 
				
			||||||
 | 
					 *      - {String} id {required} machine id
 | 
				
			||||||
 | 
					 *      - {String} name (optional) name for new snapshot
 | 
				
			||||||
 | 
					 *      - {Array of String} states - desired state
 | 
				
			||||||
 | 
					 *      - {Number} interval (optional) - time in ms to poll
 | 
				
			||||||
 | 
					 * @param {Function} callback of the form f(err, snapshot, res).
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					CloudApi.prototype.waitForSnapshotStates =
 | 
				
			||||||
 | 
					function waitForSnapshotStates(opts, cb) {
 | 
				
			||||||
 | 
					    var self = this;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert.object(opts, 'opts');
 | 
				
			||||||
 | 
					    assert.uuid(opts.id, 'opts.id');
 | 
				
			||||||
 | 
					    assert.string(opts.name, 'opts.name');
 | 
				
			||||||
 | 
					    assert.arrayOfString(opts.states, 'opts.states');
 | 
				
			||||||
 | 
					    assert.optionalNumber(opts.interval, 'opts.interval');
 | 
				
			||||||
 | 
					    assert.func(cb, 'cb');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var interval = opts.interval || 1000;
 | 
				
			||||||
 | 
					    assert.ok(interval > 0, 'interval must be a positive number');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    poll();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function poll() {
 | 
				
			||||||
 | 
					        self.getMachineSnapshot({
 | 
				
			||||||
 | 
					            id: opts.id,
 | 
				
			||||||
 | 
					            name: opts.name
 | 
				
			||||||
 | 
					        }, function (err, snapshot, res) {
 | 
				
			||||||
 | 
					            if (err) {
 | 
				
			||||||
 | 
					                cb(err, null, res);
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (opts.states.indexOf(snapshot.state) !== -1) {
 | 
				
			||||||
 | 
					                cb(null, snapshot, res);
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            setTimeout(poll, interval);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Lists all snapshots for a given machine.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns a list of snapshot objects.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param {Object} options object containing:
 | 
				
			||||||
 | 
					 *      - {String} id (required) the machine's id.
 | 
				
			||||||
 | 
					 * @param {Function} callback of the form f(err, snapshot, res).
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					CloudApi.prototype.listMachineSnapshots =
 | 
				
			||||||
 | 
					function listMachineSnapshots(opts, cb) {
 | 
				
			||||||
 | 
					    assert.object(opts, 'opts');
 | 
				
			||||||
 | 
					    assert.uuid(opts.id, 'opts.id');
 | 
				
			||||||
 | 
					    assert.func(cb, 'cb');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var endpoint = format('/%s/machines/%s/snapshots', this.account, opts.id);
 | 
				
			||||||
 | 
					    this._passThrough(endpoint, opts, cb);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Get a single snapshot for a given machine.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns a snapshot object.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param {Object} options object containing:
 | 
				
			||||||
 | 
					 *      - {String} id (required) the machine's id.
 | 
				
			||||||
 | 
					 *      - {String} name (required) the snapshot's name.
 | 
				
			||||||
 | 
					 * @param {Function} callback of the form f(err, snapshot, res).
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					CloudApi.prototype.getMachineSnapshot =
 | 
				
			||||||
 | 
					function getMachineSnapshot(opts, cb) {
 | 
				
			||||||
 | 
					    assert.object(opts, 'opts');
 | 
				
			||||||
 | 
					    assert.uuid(opts.id, 'opts.id');
 | 
				
			||||||
 | 
					    assert.string(opts.name, 'opts.name');
 | 
				
			||||||
 | 
					    assert.func(cb, 'cb');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var endpoint = format('/%s/machines/%s/snapshots/%s', this.account, opts.id,
 | 
				
			||||||
 | 
					        encodeURIComponent(opts.name));
 | 
				
			||||||
 | 
					    this._passThrough(endpoint, opts, cb);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Re/boots a machine from a snapshot.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param {Object} options object containing:
 | 
				
			||||||
 | 
					 *      - {String} id (required) the machine's id.
 | 
				
			||||||
 | 
					 *      - {String} name (required) the snapshot's name.
 | 
				
			||||||
 | 
					 * @param {Function} callback of the form f(err, res).
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					CloudApi.prototype.startMachineFromSnapshot =
 | 
				
			||||||
 | 
					function startMachineFromSnapshot(opts, cb) {
 | 
				
			||||||
 | 
					    assert.object(opts, 'opts');
 | 
				
			||||||
 | 
					    assert.uuid(opts.id, 'opts.id');
 | 
				
			||||||
 | 
					    assert.string(opts.name, 'opts.name');
 | 
				
			||||||
 | 
					    assert.func(cb, 'cb');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this._request({
 | 
				
			||||||
 | 
					        method: 'POST',
 | 
				
			||||||
 | 
					        path: format('/%s/machines/%s/snapshots/%s', this.account, opts.id,
 | 
				
			||||||
 | 
					            encodeURIComponent(opts.name)),
 | 
				
			||||||
 | 
					        data: opts
 | 
				
			||||||
 | 
					    }, function (err, req, res, body) {
 | 
				
			||||||
 | 
					        cb(err, body, res);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Deletes a machine snapshot.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param {Object} options object containing:
 | 
				
			||||||
 | 
					 *      - {String} id (required) the machine's id.
 | 
				
			||||||
 | 
					 *      - {String} name (required) the snapshot's name.
 | 
				
			||||||
 | 
					 * @param {Function} callback of the form f(err, res).
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					CloudApi.prototype.deleteMachineSnapshot =
 | 
				
			||||||
 | 
					function deleteMachineSnapshot(opts, cb) {
 | 
				
			||||||
 | 
					    assert.object(opts, 'opts');
 | 
				
			||||||
 | 
					    assert.uuid(opts.id, 'opts.id');
 | 
				
			||||||
 | 
					    assert.string(opts.name, 'opts.name');
 | 
				
			||||||
 | 
					    assert.func(cb, 'cb');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this._request({
 | 
				
			||||||
 | 
					        method: 'DELETE',
 | 
				
			||||||
 | 
					        path: format('/%s/machines/%s/snapshots/%s', this.account, opts.id,
 | 
				
			||||||
 | 
					            encodeURIComponent(opts.name))
 | 
				
			||||||
 | 
					    }, function (err, req, res) {
 | 
				
			||||||
 | 
					        cb(err, res);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// --- firewall rules
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Creates a Firewall Rule.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param {Object} options object containing:
 | 
				
			||||||
 | 
					 *      - {String} rule (required) the fwrule text.
 | 
				
			||||||
 | 
					 *      - {Boolean} enabled (optional) default to false.
 | 
				
			||||||
 | 
					 *      - {String} description (optional)
 | 
				
			||||||
 | 
					 * @param {Function} callback of the form f(err, fwrule, res).
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					CloudApi.prototype.createFirewallRule =
 | 
				
			||||||
 | 
					function createFirewallRule(opts, cb) {
 | 
				
			||||||
 | 
					    assert.object(opts, 'opts');
 | 
				
			||||||
 | 
					    assert.string(opts.rule, 'opts.rule');
 | 
				
			||||||
 | 
					    assert.optionalString(opts.description, 'opts.description');
 | 
				
			||||||
 | 
					    assert.optionalBool(opts.enabled, 'opts.enabled');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var data = {};
 | 
				
			||||||
 | 
					    Object.keys(this.UPDATE_FWRULE_FIELDS).forEach(function (attr) {
 | 
				
			||||||
 | 
					        if (opts[attr] !== undefined)
 | 
				
			||||||
 | 
					            data[attr] = opts[attr];
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this._request({
 | 
				
			||||||
 | 
					        method: 'POST',
 | 
				
			||||||
 | 
					        path: format('/%s/fwrules', this.account),
 | 
				
			||||||
 | 
					        data: data
 | 
				
			||||||
 | 
					    }, function (err, req, res, body) {
 | 
				
			||||||
 | 
					        cb(err, body, res);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Lists all your Firewall Rules.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns an array of objects.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param opts {Object} Options
 | 
				
			||||||
 | 
					 * @param {Function} callback of the form f(err, fwrules, res).
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					CloudApi.prototype.listFirewallRules =
 | 
				
			||||||
 | 
					function listFirewallRules(opts, cb) {
 | 
				
			||||||
 | 
					    assert.object(opts, 'opts');
 | 
				
			||||||
 | 
					    assert.func(cb, 'cb');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var endpoint = format('/%s/fwrules', this.account);
 | 
				
			||||||
 | 
					    this._passThrough(endpoint, opts, cb);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Retrieves a Firewall Rule.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param {UUID} id: The firewall rule id.
 | 
				
			||||||
 | 
					 * @param {Function} callback of the form `function (err, fwrule, res)`
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					CloudApi.prototype.getFirewallRule =
 | 
				
			||||||
 | 
					function getFirewallRule(id, cb) {
 | 
				
			||||||
 | 
					    assert.uuid(id, 'id');
 | 
				
			||||||
 | 
					    assert.func(cb, 'cb');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var endpoint = format('/%s/fwrules/%s', this.account, id);
 | 
				
			||||||
 | 
					    this._request(endpoint, function (err, req, res, body) {
 | 
				
			||||||
 | 
					        cb(err, body, res);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// <updatable account field> -> <expected typeof>
 | 
				
			||||||
 | 
					CloudApi.prototype.UPDATE_FWRULE_FIELDS = {
 | 
				
			||||||
 | 
					    enabled: 'boolean',
 | 
				
			||||||
 | 
					    rule: 'string',
 | 
				
			||||||
 | 
					    description: 'string'
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Updates a Firewall Rule.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Dev Note: That 'rule' is *required* here is lame. Hoping to change that
 | 
				
			||||||
 | 
					 * in cloudapi.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param {Object} opts object containing:
 | 
				
			||||||
 | 
					 *      - {UUID} id: The fwrule id. Required.
 | 
				
			||||||
 | 
					 *      - {String} rule: The fwrule text. Required.
 | 
				
			||||||
 | 
					 *      - {Boolean} enabled: Optional.
 | 
				
			||||||
 | 
					 *      - {String} description: Description of the rule. Optional.
 | 
				
			||||||
 | 
					 * @param {Function} callback of the form `function (err, fwrule, res)`
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					CloudApi.prototype.updateFirewallRule =
 | 
				
			||||||
 | 
					function updateFirewallRule(opts, cb) {
 | 
				
			||||||
 | 
					    assert.object(opts, 'opts');
 | 
				
			||||||
 | 
					    assert.uuid(opts.id, 'opts.id');
 | 
				
			||||||
 | 
					    assert.string(opts.rule, 'opts.rule');
 | 
				
			||||||
 | 
					    assert.optionalBool(opts.enabled, 'opts.enabled');
 | 
				
			||||||
 | 
					    assert.optionalString(opts.description, 'opts.description');
 | 
				
			||||||
 | 
					    assert.func(cb, 'cb');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var data = {};
 | 
				
			||||||
 | 
					    Object.keys(this.UPDATE_FWRULE_FIELDS).forEach(function (attr) {
 | 
				
			||||||
 | 
					        if (opts[attr] !== undefined)
 | 
				
			||||||
 | 
					            data[attr] = opts[attr];
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this._request({
 | 
				
			||||||
 | 
					        method: 'POST',
 | 
				
			||||||
 | 
					        path: format('/%s/fwrules/%s', this.account, opts.id),
 | 
				
			||||||
 | 
					        data: data
 | 
				
			||||||
 | 
					    }, function (err, req, res, body) {
 | 
				
			||||||
 | 
					        cb(err, body, res);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Enable a Firewall Rule.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param {Object} opts
 | 
				
			||||||
 | 
					 *      - {UUID} id: The firewall id. Required.
 | 
				
			||||||
 | 
					 * @param {Function} callback of the form `function (err, fwrule, res)`
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					CloudApi.prototype.enableFirewallRule =
 | 
				
			||||||
 | 
					function enableFirewallRule(opts, cb) {
 | 
				
			||||||
 | 
					    assert.object(opts, 'opts');
 | 
				
			||||||
 | 
					    assert.uuid(opts.id, 'opts.id');
 | 
				
			||||||
 | 
					    assert.func(cb, 'cb');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this._request({
 | 
				
			||||||
 | 
					        method: 'POST',
 | 
				
			||||||
 | 
					        path: format('/%s/fwrules/%s/enable', this.account, opts.id),
 | 
				
			||||||
 | 
					        data: {}
 | 
				
			||||||
 | 
					    }, function (err, req, res, body) {
 | 
				
			||||||
 | 
					        cb(err, body, res);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Disable a Firewall Rule.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param {Object} opts
 | 
				
			||||||
 | 
					 *      - {UUID} id: The firewall id. Required.
 | 
				
			||||||
 | 
					 * @param {Function} callback of the form `function (err, fwrule, res)`
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					CloudApi.prototype.disableFirewallRule =
 | 
				
			||||||
 | 
					function disableFirewallRule(opts, cb) {
 | 
				
			||||||
 | 
					    assert.object(opts, 'opts');
 | 
				
			||||||
 | 
					    assert.uuid(opts.id, 'opts.id');
 | 
				
			||||||
 | 
					    assert.func(cb, 'cb');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this._request({
 | 
				
			||||||
 | 
					        method: 'POST',
 | 
				
			||||||
 | 
					        path: format('/%s/fwrules/%s/disable', this.account, opts.id),
 | 
				
			||||||
 | 
					        data: {}
 | 
				
			||||||
 | 
					    }, function (err, req, res, body) {
 | 
				
			||||||
 | 
					        cb(err, body, res);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Remove a Firewall Rule.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param {Object} opts (object)
 | 
				
			||||||
 | 
					 *      - {UUID} id: The firewall id. Required.
 | 
				
			||||||
 | 
					 * @param {Function} cb of the form `function (err, res)`
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					CloudApi.prototype.deleteFirewallRule =
 | 
				
			||||||
 | 
					function deleteFirewallRule(opts, cb) {
 | 
				
			||||||
    assert.object(opts, 'opts');
 | 
					    assert.object(opts, 'opts');
 | 
				
			||||||
    assert.uuid(opts.id, 'opts.id');
 | 
					    assert.uuid(opts.id, 'opts.id');
 | 
				
			||||||
    assert.func(cb, 'cb');
 | 
					    assert.func(cb, 'cb');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this._request({
 | 
					    this._request({
 | 
				
			||||||
        method: 'DELETE',
 | 
					        method: 'DELETE',
 | 
				
			||||||
        path: format('/%s/machines/%s/tags', this.account, opts.id)
 | 
					        path: format('/%s/fwrules/%s', this.account, opts.id)
 | 
				
			||||||
    }, function (err, req, res) {
 | 
					    }, function (err, req, res) {
 | 
				
			||||||
        cb(err, res);
 | 
					        cb(err, res);
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Lists all the Firewall Rules affecting a given machine.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns an array of firewall objects.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param opts {Object} Options
 | 
				
			||||||
 | 
					 *      - {String} id (required) machine id.
 | 
				
			||||||
 | 
					 * @param {Function} callback of the form f(err, fwrules, res).
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					CloudApi.prototype.listMachineFirewallRules =
 | 
				
			||||||
 | 
					function listMachineFirewallRules(opts, cb) {
 | 
				
			||||||
 | 
					    assert.object(opts, 'opts');
 | 
				
			||||||
 | 
					    assert.uuid(opts.id, 'opts.id');
 | 
				
			||||||
 | 
					    assert.func(cb, 'cb');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var endpoint = format('/%s/machines/%s/fwrules', this.account, opts.id);
 | 
				
			||||||
 | 
					    this._passThrough(endpoint, opts, cb);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Lists all the Machines affected by the given firewall rule.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns an array of machine objects.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param opts {Object} Options
 | 
				
			||||||
 | 
					 *      - {String} id (required) firewall rule.
 | 
				
			||||||
 | 
					 * @param {Function} callback of the form f(err, machines, res).
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					CloudApi.prototype.listFirewallRuleMachines =
 | 
				
			||||||
 | 
					function listFirewallRuleMachines(opts, cb) {
 | 
				
			||||||
 | 
					    assert.object(opts, 'opts');
 | 
				
			||||||
 | 
					    assert.uuid(opts.id, 'opts.id');
 | 
				
			||||||
 | 
					    assert.func(cb, 'cb');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var endpoint = format('/%s/fwrules/%s/machines', this.account, opts.id);
 | 
				
			||||||
 | 
					    this._passThrough(endpoint, opts, cb);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// --- rbac
 | 
					// --- rbac
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 | 
				
			|||||||
@ -314,8 +314,7 @@ function uuidToShortId(s) {
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * Short IDs:
 | 
					 * Short IDs:
 | 
				
			||||||
 * - UUID prefix
 | 
					 * - UUID prefix
 | 
				
			||||||
 * - allow '-' to be elided (to support using containers IDs from
 | 
					 * - allow '-' to be elided (to support using containers IDs from docker)
 | 
				
			||||||
 *   docker)
 | 
					 | 
				
			||||||
 * - support docker ID *longer* than a UUID? The curr implementation does.
 | 
					 * - support docker ID *longer* than a UUID? The curr implementation does.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
function normShortId(s) {
 | 
					function normShortId(s) {
 | 
				
			||||||
 | 
				
			|||||||
@ -13,8 +13,9 @@
 | 
				
			|||||||
var fs = require('fs');
 | 
					var fs = require('fs');
 | 
				
			||||||
var path = require('path');
 | 
					var path = require('path');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var UPDATE_ACCOUNT_FIELDS
 | 
					var CloudApi = require('./cloudapi2').CloudApi;
 | 
				
			||||||
    = require('./cloudapi2').CloudApi.prototype.UPDATE_ACCOUNT_FIELDS;
 | 
					var UPDATE_ACCOUNT_FIELDS = CloudApi.prototype.UPDATE_ACCOUNT_FIELDS;
 | 
				
			||||||
 | 
					var UPDATE_FWRULE_FIELDS = CloudApi.prototype.UPDATE_FWRULE_FIELDS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Replace {{variable}} in `s` with the template data in `d`.
 | 
					// Replace {{variable}} in `s` with the template data in `d`.
 | 
				
			||||||
@ -39,6 +40,8 @@ function do_completion(subcmd, opts, args, cb) {
 | 
				
			|||||||
            'utf8');
 | 
					            'utf8');
 | 
				
			||||||
        var specExtra = renderTemplate(specExtraIn, {
 | 
					        var specExtra = renderTemplate(specExtraIn, {
 | 
				
			||||||
            UPDATE_ACCOUNT_FIELDS: Object.keys(UPDATE_ACCOUNT_FIELDS).sort()
 | 
					            UPDATE_ACCOUNT_FIELDS: Object.keys(UPDATE_ACCOUNT_FIELDS).sort()
 | 
				
			||||||
 | 
					                .map(function (field) { return field + '='; }).join(' '),
 | 
				
			||||||
 | 
					            UPDATE_FWRULE_FIELDS: Object.keys(UPDATE_FWRULE_FIELDS).sort()
 | 
				
			||||||
                .map(function (field) { return field + '='; }).join(' ')
 | 
					                .map(function (field) { return field + '='; }).join(' ')
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
        console.log(this.bashCompletion({specExtra: specExtra}));
 | 
					        console.log(this.bashCompletion({specExtra: specExtra}));
 | 
				
			||||||
@ -61,7 +64,7 @@ do_completion.options = [
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
];
 | 
					];
 | 
				
			||||||
do_completion.help = [
 | 
					do_completion.help = [
 | 
				
			||||||
    'Output bash completion. See help output for installation.',
 | 
					    'Emit bash completion. See help for installation.',
 | 
				
			||||||
    '',
 | 
					    '',
 | 
				
			||||||
    'Installation:',
 | 
					    'Installation:',
 | 
				
			||||||
    '    {{name}} completion > /usr/local/etc/bash_completion.d/{{name}} # Mac',
 | 
					    '    {{name}} completion > /usr/local/etc/bash_completion.d/{{name}} # Mac',
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										99
									
								
								lib/do_fwrule/do_create.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								lib/do_fwrule/do_create.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,99 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 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 2016 Joyent, Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * `triton fwrule create ...`
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var assert = require('assert-plus');
 | 
				
			||||||
 | 
					var format = require('util').format;
 | 
				
			||||||
 | 
					var vasync = require('vasync');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var common = require('../common');
 | 
				
			||||||
 | 
					var errors = require('../errors');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function do_create(subcmd, opts, args, cb) {
 | 
				
			||||||
 | 
					    assert.optionalString(opts.description, 'opts.description');
 | 
				
			||||||
 | 
					    assert.optionalBool(opts.disabled, 'opts.disabled');
 | 
				
			||||||
 | 
					    assert.func(cb, 'cb');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (opts.help) {
 | 
				
			||||||
 | 
					        this.do_help('help', {}, [subcmd], cb);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (args.length === 0) {
 | 
				
			||||||
 | 
					        cb(new errors.UsageError('missing <fwrule> argument'));
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    } else if (args.length > 1) {
 | 
				
			||||||
 | 
					        cb(new errors.UsageError('incorrect number of arguments'));
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var createOpts = {
 | 
				
			||||||
 | 
					        rule: args[0]
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    if (!opts.disabled) {
 | 
				
			||||||
 | 
					        createOpts.enabled = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (opts.description) {
 | 
				
			||||||
 | 
					        createOpts.description = opts.description;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this.top.tritonapi.cloudapi.createFirewallRule(createOpts,
 | 
				
			||||||
 | 
					            function (err, fwrule) {
 | 
				
			||||||
 | 
					        if (err) {
 | 
				
			||||||
 | 
					            cb(err);
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        console.log('Created firewall rule %s%s', fwrule.id,
 | 
				
			||||||
 | 
					            (!fwrule.enabled ? ' (disabled)' : ''));
 | 
				
			||||||
 | 
					        cb();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					do_create.options = [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        names: ['help', 'h'],
 | 
				
			||||||
 | 
					        type: 'bool',
 | 
				
			||||||
 | 
					        help: 'Show this help.'
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        names: ['json', 'j'],
 | 
				
			||||||
 | 
					        type: 'bool',
 | 
				
			||||||
 | 
					        help: 'JSON stream output.'
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        names: ['disabled', 'd'],
 | 
				
			||||||
 | 
					        type: 'bool',
 | 
				
			||||||
 | 
					        help: 'Disable the created firewall rule. By default a created '
 | 
				
			||||||
 | 
					            + 'firewall rule is enabled. Use "triton fwrule enable" '
 | 
				
			||||||
 | 
					            + 'to enable it later.'
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        names: ['description', 'D'],
 | 
				
			||||||
 | 
					        type: 'string',
 | 
				
			||||||
 | 
					        helpArg: '<desc>',
 | 
				
			||||||
 | 
					        help: 'Description of the firewall rule.'
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					do_create.help = [
 | 
				
			||||||
 | 
					    'Create a firewall rule.',
 | 
				
			||||||
 | 
					    '',
 | 
				
			||||||
 | 
					    'Usage:',
 | 
				
			||||||
 | 
					    '    {{name}} create [<options>] <fwrule>',
 | 
				
			||||||
 | 
					    '',
 | 
				
			||||||
 | 
					    '{{options}}'
 | 
				
			||||||
 | 
					].join('\n');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					do_create.helpOpts = {
 | 
				
			||||||
 | 
					    helpCol: 25
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = do_create;
 | 
				
			||||||
							
								
								
									
										110
									
								
								lib/do_fwrule/do_delete.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								lib/do_fwrule/do_delete.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,110 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 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 2016 Joyent, Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * `triton snapshot delete ...`
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var assert = require('assert-plus');
 | 
				
			||||||
 | 
					var format = require('util').format;
 | 
				
			||||||
 | 
					var vasync = require('vasync');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var common = require('../common');
 | 
				
			||||||
 | 
					var errors = require('../errors');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function do_delete(subcmd, opts, args, cb) {
 | 
				
			||||||
 | 
					    assert.func(cb, 'cb');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (opts.help) {
 | 
				
			||||||
 | 
					        this.do_help('help', {}, [subcmd], cb);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (args.length < 1) {
 | 
				
			||||||
 | 
					        cb(new errors.UsageError('missing <fwrule-id> argument(s)'));
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var cli = this.top;
 | 
				
			||||||
 | 
					    var ruleIds = args;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vasync.pipeline({funcs: [
 | 
				
			||||||
 | 
					        function confirm(_, next) {
 | 
				
			||||||
 | 
					            if (opts.force) {
 | 
				
			||||||
 | 
					                return next();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var msg;
 | 
				
			||||||
 | 
					            if (ruleIds.length === 1) {
 | 
				
			||||||
 | 
					                msg = 'Delete firewall rule "' + ruleIds[0] + '"? [y/n] ';
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                msg = format('Delete %d firewall rules (%s)? [y/n] ',
 | 
				
			||||||
 | 
					                    ruleIds.length, ruleIds.join(', '));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            common.promptYesNo({msg: msg}, function (answer) {
 | 
				
			||||||
 | 
					                if (answer !== 'y') {
 | 
				
			||||||
 | 
					                    console.error('Aborting');
 | 
				
			||||||
 | 
					                    next(true); // early abort signal
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    next();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        function deleteThem(_, next) {
 | 
				
			||||||
 | 
					            vasync.forEachParallel({
 | 
				
			||||||
 | 
					                inputs: ruleIds,
 | 
				
			||||||
 | 
					                func: function deleteOne(id, nextId) {
 | 
				
			||||||
 | 
					                    cli.tritonapi.deleteFirewallRule({
 | 
				
			||||||
 | 
					                            id: id
 | 
				
			||||||
 | 
					                    }, function (err) {
 | 
				
			||||||
 | 
					                        if (err) {
 | 
				
			||||||
 | 
					                            nextId(err);
 | 
				
			||||||
 | 
					                            return;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        console.log('Deleted rule %s', id);
 | 
				
			||||||
 | 
					                        nextId();
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }, next);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    ]}, function (err) {
 | 
				
			||||||
 | 
					        if (err === true) {
 | 
				
			||||||
 | 
					            err = null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        cb(err);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					do_delete.options = [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        names: ['help', 'h'],
 | 
				
			||||||
 | 
					        type: 'bool',
 | 
				
			||||||
 | 
					        help: 'Show this help.'
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        names: ['force', 'f'],
 | 
				
			||||||
 | 
					        type: 'bool',
 | 
				
			||||||
 | 
					        help: 'Skip confirmation of delete.'
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					do_delete.help = [
 | 
				
			||||||
 | 
					    'Remove a firewall rule.',
 | 
				
			||||||
 | 
					    '',
 | 
				
			||||||
 | 
					    'Usage:',
 | 
				
			||||||
 | 
					    '    {{name}} delete [<options>] <fwrule-id> [<fwrule-id>...]',
 | 
				
			||||||
 | 
					    '',
 | 
				
			||||||
 | 
					    '{{options}}'
 | 
				
			||||||
 | 
					].join('\n');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					do_delete.aliases = ['rm'];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = do_delete;
 | 
				
			||||||
							
								
								
									
										68
									
								
								lib/do_fwrule/do_disable.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								lib/do_fwrule/do_disable.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,68 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 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 2016 Joyent, Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * `triton fwrule disable ...`
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var assert = require('assert-plus');
 | 
				
			||||||
 | 
					var vasync = require('vasync');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var common = require('../common');
 | 
				
			||||||
 | 
					var errors = require('../errors');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function do_disable(subcmd, opts, args, cb) {
 | 
				
			||||||
 | 
					    assert.func(cb, 'cb');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (opts.help) {
 | 
				
			||||||
 | 
					        this.do_help('help', {}, [subcmd], cb);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (args.length === 0) {
 | 
				
			||||||
 | 
					        cb(new errors.UsageError('Missing <fwrule-id> argument(s)'));
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var cli = this.top;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vasync.forEachParallel({
 | 
				
			||||||
 | 
					        inputs: args,
 | 
				
			||||||
 | 
					        func: function disableOne(id, nextId) {
 | 
				
			||||||
 | 
					            cli.tritonapi.disableFirewallRule({ id: id }, function (err) {
 | 
				
			||||||
 | 
					                if (err) {
 | 
				
			||||||
 | 
					                    nextId(err);
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                console.log('Disabled firewall rule %s', id);
 | 
				
			||||||
 | 
					                nextId();
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }, cb);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					do_disable.options = [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        names: ['help', 'h'],
 | 
				
			||||||
 | 
					        type: 'bool',
 | 
				
			||||||
 | 
					        help: 'Show this help.'
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					do_disable.help = [
 | 
				
			||||||
 | 
					    'Disable a specific firewall rule.',
 | 
				
			||||||
 | 
					    '',
 | 
				
			||||||
 | 
					    'Usage:',
 | 
				
			||||||
 | 
					    '    {{name}} disable <fwrule-id> [<fwrule-id>...]',
 | 
				
			||||||
 | 
					    '',
 | 
				
			||||||
 | 
					    '{{options}}'
 | 
				
			||||||
 | 
					].join('\n');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = do_disable;
 | 
				
			||||||
							
								
								
									
										68
									
								
								lib/do_fwrule/do_enable.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								lib/do_fwrule/do_enable.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,68 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 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 2016 Joyent, Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * `triton fwrule enable ...`
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var assert = require('assert-plus');
 | 
				
			||||||
 | 
					var vasync = require('vasync');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var common = require('../common');
 | 
				
			||||||
 | 
					var errors = require('../errors');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function do_enable(subcmd, opts, args, cb) {
 | 
				
			||||||
 | 
					    assert.func(cb, 'cb');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (opts.help) {
 | 
				
			||||||
 | 
					        this.do_help('help', {}, [subcmd], cb);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (args.length === 0) {
 | 
				
			||||||
 | 
					        cb(new errors.UsageError('Missing <fwrule-id> argument(s)'));
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var cli = this.top;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vasync.forEachParallel({
 | 
				
			||||||
 | 
					        inputs: args,
 | 
				
			||||||
 | 
					        func: function enableOne(id, nextId) {
 | 
				
			||||||
 | 
					            cli.tritonapi.enableFirewallRule({ id: id }, function (err) {
 | 
				
			||||||
 | 
					                if (err) {
 | 
				
			||||||
 | 
					                    nextId(err);
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                console.log('Enabled firewall rule %s', id);
 | 
				
			||||||
 | 
					                nextId();
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }, cb);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					do_enable.options = [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        names: ['help', 'h'],
 | 
				
			||||||
 | 
					        type: 'bool',
 | 
				
			||||||
 | 
					        help: 'Show this help.'
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					do_enable.help = [
 | 
				
			||||||
 | 
					    'Enable a specific firewall rule.',
 | 
				
			||||||
 | 
					    '',
 | 
				
			||||||
 | 
					    'Usage:',
 | 
				
			||||||
 | 
					    '    {{name}} enable <fwrule-id> [<fwrule-id>...]',
 | 
				
			||||||
 | 
					    '',
 | 
				
			||||||
 | 
					    '{{options}}'
 | 
				
			||||||
 | 
					].join('\n');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = do_enable;
 | 
				
			||||||
							
								
								
									
										76
									
								
								lib/do_fwrule/do_get.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								lib/do_fwrule/do_get.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,76 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 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 2016 Joyent, Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * `triton fwrule get ...`
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var assert = require('assert-plus');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var common = require('../common');
 | 
				
			||||||
 | 
					var errors = require('../errors');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function do_get(subcmd, opts, args, cb) {
 | 
				
			||||||
 | 
					    assert.func(cb, 'cb');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (opts.help) {
 | 
				
			||||||
 | 
					        this.do_help('help', {}, [subcmd], cb);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (args.length === 0) {
 | 
				
			||||||
 | 
					        cb(new errors.UsageError('missing <fwrule-id> argument'));
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    } else if (args.length > 1) {
 | 
				
			||||||
 | 
					        cb(new errors.UsageError('incorrect number of arguments'));
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var id = args[0];
 | 
				
			||||||
 | 
					    var cli = this.top;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cli.tritonapi.getFirewallRule(id, function onRule(err, fwrule) {
 | 
				
			||||||
 | 
					        if (err) {
 | 
				
			||||||
 | 
					            cb(err);
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (opts.json) {
 | 
				
			||||||
 | 
					            console.log(JSON.stringify(fwrule));
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            console.log(JSON.stringify(fwrule, null, 4));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        cb();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					do_get.options = [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        names: ['help', 'h'],
 | 
				
			||||||
 | 
					        type: 'bool',
 | 
				
			||||||
 | 
					        help: 'Show this help.'
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        names: ['json', 'j'],
 | 
				
			||||||
 | 
					        type: 'bool',
 | 
				
			||||||
 | 
					        help: 'JSON stream output.'
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					do_get.help = [
 | 
				
			||||||
 | 
					    'Show a specific firewall rule.',
 | 
				
			||||||
 | 
					    '',
 | 
				
			||||||
 | 
					    'Usage:',
 | 
				
			||||||
 | 
					    '    {{name}} get <fwrule-id>',
 | 
				
			||||||
 | 
					    '',
 | 
				
			||||||
 | 
					    '{{options}}'
 | 
				
			||||||
 | 
					].join('\n');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = do_get;
 | 
				
			||||||
							
								
								
									
										162
									
								
								lib/do_fwrule/do_instances.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										162
									
								
								lib/do_fwrule/do_instances.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,162 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 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 2016 Joyent, Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * `triton fwrule instances ...`
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var format = require('util').format;
 | 
				
			||||||
 | 
					var tabula = require('tabula');
 | 
				
			||||||
 | 
					var vasync = require('vasync');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var common = require('../common');
 | 
				
			||||||
 | 
					var errors = require('../errors');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var COLUMNS_DEFAULT = 'shortid,name,img,state,flags,age';
 | 
				
			||||||
 | 
					var COLUMNS_LONG = 'id,name,img,brand,package,state,flags,primaryIp,created';
 | 
				
			||||||
 | 
					var SORT_DEFAULT = 'created';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function do_instances(subcmd, opts, args, cb) {
 | 
				
			||||||
 | 
					    if (opts.help) {
 | 
				
			||||||
 | 
					        this.do_help('help', {}, [subcmd], cb);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (args.length === 0) {
 | 
				
			||||||
 | 
					        cb(new errors.UsageError('missing <fwrule-id> argument'));
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    } else if (args.length > 1) {
 | 
				
			||||||
 | 
					        cb(new errors.UsageError('incorrect number of arguments'));
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var id = args[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var columns = COLUMNS_DEFAULT;
 | 
				
			||||||
 | 
					    if (opts.o) {
 | 
				
			||||||
 | 
					        columns = opts.o;
 | 
				
			||||||
 | 
					    } else if (opts.long) {
 | 
				
			||||||
 | 
					        columns = COLUMNS_LONG;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    columns = columns.split(',');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var sort = opts.s.split(',');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var imgs;
 | 
				
			||||||
 | 
					    var insts;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var tritonapi = this.top.tritonapi;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vasync.parallel({funcs: [
 | 
				
			||||||
 | 
					        function getTheImages(next) {
 | 
				
			||||||
 | 
					            tritonapi.listImages({useCache: true},
 | 
				
			||||||
 | 
					                    function (err, _imgs) {
 | 
				
			||||||
 | 
					                if (err) {
 | 
				
			||||||
 | 
					                    next(err);
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    imgs = _imgs;
 | 
				
			||||||
 | 
					                    next();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        function getTheMachines(next) {
 | 
				
			||||||
 | 
					            tritonapi.listFirewallRuleInstances({
 | 
				
			||||||
 | 
					                id: id
 | 
				
			||||||
 | 
					            }, function (err, _insts) {
 | 
				
			||||||
 | 
					                if (err) {
 | 
				
			||||||
 | 
					                    next(err);
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    insts = _insts;
 | 
				
			||||||
 | 
					                    next();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    ]}, function (err, results) {
 | 
				
			||||||
 | 
					        /*
 | 
				
			||||||
 | 
					         * Error handling: vasync.parallel's `err` is always a MultiError. We
 | 
				
			||||||
 | 
					         * want to prefer the `getTheMachines` err, e.g. if both get a
 | 
				
			||||||
 | 
					         * self-signed cert error.
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        if (err) {
 | 
				
			||||||
 | 
					            err = results.operations[1].err || err;
 | 
				
			||||||
 | 
					            return cb(err);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // map "uuid" => "image_name"
 | 
				
			||||||
 | 
					        var imgmap = {};
 | 
				
			||||||
 | 
					        imgs.forEach(function (img) {
 | 
				
			||||||
 | 
					            imgmap[img.id] = format('%s@%s', img.name, img.version);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Add extra fields for nice output.
 | 
				
			||||||
 | 
					        var now = new Date();
 | 
				
			||||||
 | 
					        insts.forEach(function (inst) {
 | 
				
			||||||
 | 
					            var created = new Date(inst.created);
 | 
				
			||||||
 | 
					            inst.age = common.longAgo(created, now);
 | 
				
			||||||
 | 
					            inst.img = imgmap[inst.image] || common.uuidToShortId(inst.image);
 | 
				
			||||||
 | 
					            inst.shortid = inst.id.split('-', 1)[0];
 | 
				
			||||||
 | 
					            var flags = [];
 | 
				
			||||||
 | 
					            if (inst.docker) flags.push('D');
 | 
				
			||||||
 | 
					            if (inst.firewall_enabled) flags.push('F');
 | 
				
			||||||
 | 
					            if (inst.brand === 'kvm') flags.push('K');
 | 
				
			||||||
 | 
					            inst.flags = flags.length ? flags.join('') : undefined;
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (opts.json) {
 | 
				
			||||||
 | 
					            common.jsonStream(insts);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            tabula(insts, {
 | 
				
			||||||
 | 
					                skipHeader: opts.H,
 | 
				
			||||||
 | 
					                columns: columns,
 | 
				
			||||||
 | 
					                sort: sort,
 | 
				
			||||||
 | 
					                dottedLookup: true
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        cb();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					do_instances.options = [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        names: ['help', 'h'],
 | 
				
			||||||
 | 
					        type: 'bool',
 | 
				
			||||||
 | 
					        help: 'Show this help.'
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					].concat(common.getCliTableOptions({
 | 
				
			||||||
 | 
					    includeLong: true,
 | 
				
			||||||
 | 
					    sortDefault: SORT_DEFAULT
 | 
				
			||||||
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					do_instances.help = [
 | 
				
			||||||
 | 
					    /* BEGIN JSSTYLED */
 | 
				
			||||||
 | 
					    'List instances a firewall rule is applied to.',
 | 
				
			||||||
 | 
					    '',
 | 
				
			||||||
 | 
					    'Usage:',
 | 
				
			||||||
 | 
					    '    {{name}} instances [<options>] <fwrule-id>',
 | 
				
			||||||
 | 
					    '',
 | 
				
			||||||
 | 
					    '{{options}}',
 | 
				
			||||||
 | 
					    '',
 | 
				
			||||||
 | 
					    'Fields (most are self explanatory, "*" indicates a field added client-side',
 | 
				
			||||||
 | 
					    'for convenience):',
 | 
				
			||||||
 | 
					    '    shortid*           A short ID prefix.',
 | 
				
			||||||
 | 
					    '    flags*             Single letter flags summarizing some fields:',
 | 
				
			||||||
 | 
					    '                           "D" docker instance',
 | 
				
			||||||
 | 
					    '                           "F" firewall is enabled',
 | 
				
			||||||
 | 
					    '                           "K" the brand is "kvm"',
 | 
				
			||||||
 | 
					    '    age*               Approximate time since created, e.g. 1y, 2w.',
 | 
				
			||||||
 | 
					    '    img*               The image "name@version", if available, else its',
 | 
				
			||||||
 | 
					    '                       "shortid".'
 | 
				
			||||||
 | 
					    /* END JSSTYLED */
 | 
				
			||||||
 | 
					].join('\n');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					do_instances.aliases = ['insts'];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = do_instances;
 | 
				
			||||||
							
								
								
									
										98
									
								
								lib/do_fwrule/do_list.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								lib/do_fwrule/do_list.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,98 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 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 2016 Joyent, Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * `triton fwrule list ...`
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var assert = require('assert-plus');
 | 
				
			||||||
 | 
					var tabula = require('tabula');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var common = require('../common');
 | 
				
			||||||
 | 
					var errors = require('../errors');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var COLUMNS_DEFAULT = 'shortid,enabled,global,rule';
 | 
				
			||||||
 | 
					var COLUMNS_LONG = 'id,enabled,global,rule,description';
 | 
				
			||||||
 | 
					var SORT_DEFAULT = 'rule';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function do_list(subcmd, opts, args, cb) {
 | 
				
			||||||
 | 
					    assert.func(cb, 'cb');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (opts.help) {
 | 
				
			||||||
 | 
					        this.do_help('help', {}, [subcmd], cb);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (args.length > 0) {
 | 
				
			||||||
 | 
					        cb(new errors.UsageError('incorrect number of arguments'));
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var cli = this.top;
 | 
				
			||||||
 | 
					    cli.tritonapi.cloudapi.listFirewallRules({}, function onRules(err, rules) {
 | 
				
			||||||
 | 
					        if (err) {
 | 
				
			||||||
 | 
					            cb(err);
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (opts.json) {
 | 
				
			||||||
 | 
					            common.jsonStream(rules);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            var columns = COLUMNS_DEFAULT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (opts.o) {
 | 
				
			||||||
 | 
					                columns = opts.o;
 | 
				
			||||||
 | 
					            } else if (opts.long) {
 | 
				
			||||||
 | 
					                columns = COLUMNS_LONG;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            columns = columns.toLowerCase().split(',');
 | 
				
			||||||
 | 
					            var sort = opts.s.toLowerCase().split(',');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (columns.indexOf('shortid') !== -1) {
 | 
				
			||||||
 | 
					                rules.forEach(function (rule) {
 | 
				
			||||||
 | 
					                    rule.shortid = common.uuidToShortId(rule.id);
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            tabula(rules, {
 | 
				
			||||||
 | 
					                skipHeader: opts.H,
 | 
				
			||||||
 | 
					                columns: columns,
 | 
				
			||||||
 | 
					                sort: sort
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        cb();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					do_list.options = [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        names: ['help', 'h'],
 | 
				
			||||||
 | 
					        type: 'bool',
 | 
				
			||||||
 | 
					        help: 'Show this help.'
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					].concat(common.getCliTableOptions({
 | 
				
			||||||
 | 
					    includeLong: true,
 | 
				
			||||||
 | 
					    sortDefault: SORT_DEFAULT
 | 
				
			||||||
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					do_list.help = [
 | 
				
			||||||
 | 
					    'Show all firewall rules.',
 | 
				
			||||||
 | 
					    '',
 | 
				
			||||||
 | 
					    'Usage:',
 | 
				
			||||||
 | 
					    '   {{name}} list [<options>]',
 | 
				
			||||||
 | 
					    '',
 | 
				
			||||||
 | 
					    '{{options}}'
 | 
				
			||||||
 | 
					].join('\n');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					do_list.aliases = ['ls'];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = do_list;
 | 
				
			||||||
							
								
								
									
										190
									
								
								lib/do_fwrule/do_update.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										190
									
								
								lib/do_fwrule/do_update.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,190 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 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 2016 Joyent, Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * `triton fwrule update ...`
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var assert = require('assert-plus');
 | 
				
			||||||
 | 
					var format = require('util').format;
 | 
				
			||||||
 | 
					var fs = require('fs');
 | 
				
			||||||
 | 
					var vasync = require('vasync');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var common = require('../common');
 | 
				
			||||||
 | 
					var errors = require('../errors');
 | 
				
			||||||
 | 
					var UPDATE_FWRULE_FIELDS
 | 
				
			||||||
 | 
					    = require('../cloudapi2').CloudApi.prototype.UPDATE_FWRULE_FIELDS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function do_update(subcmd, opts, args, cb) {
 | 
				
			||||||
 | 
					    if (opts.help) {
 | 
				
			||||||
 | 
					        this.do_help('help', {}, [subcmd], cb);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var log = this.log;
 | 
				
			||||||
 | 
					    var tritonapi = this.top.tritonapi;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (args.length === 0) {
 | 
				
			||||||
 | 
					        cb(new errors.UsageError('missing <fwrule-id> argument'));
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var id = args.shift();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vasync.pipeline({arg: {}, funcs: [
 | 
				
			||||||
 | 
					        function gatherDataArgs(ctx, next) {
 | 
				
			||||||
 | 
					            if (opts.file) {
 | 
				
			||||||
 | 
					                next();
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            try {
 | 
				
			||||||
 | 
					                ctx.data = common.objFromKeyValueArgs(args, {
 | 
				
			||||||
 | 
					                    disableDotted: true,
 | 
				
			||||||
 | 
					                    typeHintFromKey: UPDATE_FWRULE_FIELDS
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            } catch (err) {
 | 
				
			||||||
 | 
					                next(err);
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            next();
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        function gatherDataFile(ctx, next) {
 | 
				
			||||||
 | 
					            if (!opts.file || opts.file === '-') {
 | 
				
			||||||
 | 
					                next();
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var input = fs.readFileSync(opts.file, 'utf8');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            try {
 | 
				
			||||||
 | 
					                ctx.data = JSON.parse(input);
 | 
				
			||||||
 | 
					            } catch (err) {
 | 
				
			||||||
 | 
					                next(new errors.TritonError(format(
 | 
				
			||||||
 | 
					                    'invalid JSON for firewall rule update in "%s": %s',
 | 
				
			||||||
 | 
					                    opts.file, err)));
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            next();
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        function gatherDataStdin(ctx, next) {
 | 
				
			||||||
 | 
					            if (opts.file !== '-') {
 | 
				
			||||||
 | 
					                next();
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var stdin = '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            process.stdin.resume();
 | 
				
			||||||
 | 
					            process.stdin.on('data', function (chunk) {
 | 
				
			||||||
 | 
					                stdin += chunk;
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            process.stdin.on('end', function () {
 | 
				
			||||||
 | 
					                try {
 | 
				
			||||||
 | 
					                    ctx.data = JSON.parse(stdin);
 | 
				
			||||||
 | 
					                } catch (err) {
 | 
				
			||||||
 | 
					                    log.trace({stdin: stdin},
 | 
				
			||||||
 | 
					                        'invalid firewall rule update JSON on stdin');
 | 
				
			||||||
 | 
					                    next(new errors.TritonError(format(
 | 
				
			||||||
 | 
					                        'invalid JSON for firewall rule update on stdin: %s',
 | 
				
			||||||
 | 
					                        err)));
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                next();
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        function validateIt(ctx, next) {
 | 
				
			||||||
 | 
					            var keys = Object.keys(ctx.data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (keys.length === 0) {
 | 
				
			||||||
 | 
					                console.log('No fields given for firewall rule update');
 | 
				
			||||||
 | 
					                next();
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            for (var i = 0; i < keys.length; i++) {
 | 
				
			||||||
 | 
					                var key = keys[i];
 | 
				
			||||||
 | 
					                var value = ctx.data[key];
 | 
				
			||||||
 | 
					                var type = UPDATE_FWRULE_FIELDS[key];
 | 
				
			||||||
 | 
					                if (!type) {
 | 
				
			||||||
 | 
					                    next(new errors.UsageError(format('unknown or ' +
 | 
				
			||||||
 | 
					                        'unupdateable field: %s (updateable fields are: %s)',
 | 
				
			||||||
 | 
					                        key,
 | 
				
			||||||
 | 
					                        Object.keys(UPDATE_FWRULE_FIELDS).sort().join(', '))));
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (typeof (value) !== type) {
 | 
				
			||||||
 | 
					                    next(new errors.UsageError(format('field "%s" must be ' +
 | 
				
			||||||
 | 
					                        'of type "%s", but got a value of type "%s"', key,
 | 
				
			||||||
 | 
					                        type, typeof (value))));
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            next();
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        function updateAway(ctx, next) {
 | 
				
			||||||
 | 
					            var data = ctx.data;
 | 
				
			||||||
 | 
					            data.id = id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            tritonapi.updateFirewallRule(data, function (err) {
 | 
				
			||||||
 | 
					                if (err) {
 | 
				
			||||||
 | 
					                    next(err);
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                delete data.id;
 | 
				
			||||||
 | 
					                console.log('Updated firewall rule %s (fields: %s)', id,
 | 
				
			||||||
 | 
					                            Object.keys(data).join(', '));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                next();
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    ]}, cb);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					do_update.options = [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        names: ['help', 'h'],
 | 
				
			||||||
 | 
					        type: 'bool',
 | 
				
			||||||
 | 
					        help: 'Show this help.'
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        names: ['file', 'f'],
 | 
				
			||||||
 | 
					        type: 'string',
 | 
				
			||||||
 | 
					        helpArg: '<json-file>',
 | 
				
			||||||
 | 
					        help: 'A file holding a JSON file of updates, or "-" to read ' +
 | 
				
			||||||
 | 
					            'JSON from stdin.'
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					do_update.help = [
 | 
				
			||||||
 | 
					    'Update a firewall rule',
 | 
				
			||||||
 | 
					    '',
 | 
				
			||||||
 | 
					    'Usage:',
 | 
				
			||||||
 | 
					    '     {{name}} update <fwrule-id> [FIELD=VALUE ...]',
 | 
				
			||||||
 | 
					    '     {{name}} update -f <json-file> <fwrule-id>',
 | 
				
			||||||
 | 
					    '',
 | 
				
			||||||
 | 
					    '{{options}}',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    'Updateable fields:',
 | 
				
			||||||
 | 
					    '    ' + Object.keys(UPDATE_FWRULE_FIELDS).sort().map(function (f) {
 | 
				
			||||||
 | 
					        return f + ' (' + UPDATE_FWRULE_FIELDS[f] + ')';
 | 
				
			||||||
 | 
					    }).join('\n    '),
 | 
				
			||||||
 | 
					    ''
 | 
				
			||||||
 | 
					].join('\n');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					do_update.completionArgtypes = ['tritonfwrule', 'tritonupdatefwrulefield'];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = do_update;
 | 
				
			||||||
							
								
								
									
										59
									
								
								lib/do_fwrule/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								lib/do_fwrule/index.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,59 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 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 2016 Joyent, Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * `triton fwrule ...`
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var Cmdln = require('cmdln').Cmdln;
 | 
				
			||||||
 | 
					var util = require('util');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ---- CLI class
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function FirewallRuleCLI(top) {
 | 
				
			||||||
 | 
					    this.top = top;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Cmdln.call(this, {
 | 
				
			||||||
 | 
					        name: top.name + ' fwrule',
 | 
				
			||||||
 | 
					        desc: 'List and manage Triton firewall rules.',
 | 
				
			||||||
 | 
					        helpSubcmds: [
 | 
				
			||||||
 | 
					            'help',
 | 
				
			||||||
 | 
					            'list',
 | 
				
			||||||
 | 
					            'get',
 | 
				
			||||||
 | 
					            'create',
 | 
				
			||||||
 | 
					            'update',
 | 
				
			||||||
 | 
					            'delete',
 | 
				
			||||||
 | 
					            { group: '' },
 | 
				
			||||||
 | 
					            'enable',
 | 
				
			||||||
 | 
					            'disable',
 | 
				
			||||||
 | 
					            'instances'
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        helpOpts: {
 | 
				
			||||||
 | 
					            minHelpCol: 23
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					util.inherits(FirewallRuleCLI, Cmdln);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					FirewallRuleCLI.prototype.init = function init(opts, args, cb) {
 | 
				
			||||||
 | 
					    this.log = this.top.log;
 | 
				
			||||||
 | 
					    Cmdln.prototype.init.apply(this, arguments);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					FirewallRuleCLI.prototype.do_list = require('./do_list');
 | 
				
			||||||
 | 
					FirewallRuleCLI.prototype.do_create = require('./do_create');
 | 
				
			||||||
 | 
					FirewallRuleCLI.prototype.do_get = require('./do_get');
 | 
				
			||||||
 | 
					FirewallRuleCLI.prototype.do_update = require('./do_update');
 | 
				
			||||||
 | 
					FirewallRuleCLI.prototype.do_delete = require('./do_delete');
 | 
				
			||||||
 | 
					FirewallRuleCLI.prototype.do_enable = require('./do_enable');
 | 
				
			||||||
 | 
					FirewallRuleCLI.prototype.do_disable = require('./do_disable');
 | 
				
			||||||
 | 
					FirewallRuleCLI.prototype.do_instances = require('./do_instances');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = FirewallRuleCLI;
 | 
				
			||||||
@ -23,7 +23,7 @@ function ImageCLI(top) {
 | 
				
			|||||||
        name: top.name + ' image',
 | 
					        name: top.name + ' image',
 | 
				
			||||||
        /* BEGIN JSSTYLED */
 | 
					        /* BEGIN JSSTYLED */
 | 
				
			||||||
        desc: [
 | 
					        desc: [
 | 
				
			||||||
            'List, get, create and manage Triton images.'
 | 
					            'List and manage Triton images.'
 | 
				
			||||||
        ].join('\n'),
 | 
					        ].join('\n'),
 | 
				
			||||||
        /* END JSSTYLED */
 | 
					        /* END JSSTYLED */
 | 
				
			||||||
        helpOpts: {
 | 
					        helpOpts: {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										103
									
								
								lib/do_instance/do_fwrules.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								lib/do_instance/do_fwrules.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,103 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 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 2016 Joyent, Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * `triton instance fwrules ...`
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var assert = require('assert-plus');
 | 
				
			||||||
 | 
					var tabula = require('tabula');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var common = require('../common');
 | 
				
			||||||
 | 
					var errors = require('../errors');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var COLUMNS_DEFAULT = 'shortid,enabled,global,rule';
 | 
				
			||||||
 | 
					var COLUMNS_LONG = 'id,enabled,global,rule,description';
 | 
				
			||||||
 | 
					var SORT_DEFAULT = 'rule';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function do_fwrules(subcmd, opts, args, cb) {
 | 
				
			||||||
 | 
					    assert.func(cb, 'cb');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (opts.help) {
 | 
				
			||||||
 | 
					        this.do_help('help', {}, [subcmd], cb);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (args.length === 0) {
 | 
				
			||||||
 | 
					        cb(new errors.UsageError('missing <inst> argument'));
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    } else if (args.length > 1) {
 | 
				
			||||||
 | 
					        cb(new errors.UsageError('incorrect number of arguments'));
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var id = args[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var cli = this.top;
 | 
				
			||||||
 | 
					    cli.tritonapi.listInstanceFirewallRules({
 | 
				
			||||||
 | 
					        id: id
 | 
				
			||||||
 | 
					    }, function onRules(err, rules) {
 | 
				
			||||||
 | 
					        if (err) {
 | 
				
			||||||
 | 
					            cb(err);
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (opts.json) {
 | 
				
			||||||
 | 
					            common.jsonStream(rules);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            var columns = COLUMNS_DEFAULT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (opts.o) {
 | 
				
			||||||
 | 
					                columns = opts.o;
 | 
				
			||||||
 | 
					            } else if (opts.long) {
 | 
				
			||||||
 | 
					                columns = COLUMNS_LONG;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            columns = columns.toLowerCase().split(',');
 | 
				
			||||||
 | 
					            var sort = opts.s.toLowerCase().split(',');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (columns.indexOf('shortid') !== -1) {
 | 
				
			||||||
 | 
					                rules.forEach(function (rule) {
 | 
				
			||||||
 | 
					                    rule.shortid = common.normShortId(rule.id);
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            tabula(rules, {
 | 
				
			||||||
 | 
					                skipHeader: opts.H,
 | 
				
			||||||
 | 
					                columns: columns,
 | 
				
			||||||
 | 
					                sort: sort
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        cb();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					do_fwrules.options = [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        names: ['help', 'h'],
 | 
				
			||||||
 | 
					        type: 'bool',
 | 
				
			||||||
 | 
					        help: 'Show this help.'
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					].concat(common.getCliTableOptions({
 | 
				
			||||||
 | 
					    includeLong: true,
 | 
				
			||||||
 | 
					    sortDefault: SORT_DEFAULT
 | 
				
			||||||
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					do_fwrules.help = [
 | 
				
			||||||
 | 
					    'Show firewall rules applied to an instance.',
 | 
				
			||||||
 | 
					    '',
 | 
				
			||||||
 | 
					    'Usage:',
 | 
				
			||||||
 | 
					    '     {{name}} fwrules [<options>] <inst>',
 | 
				
			||||||
 | 
					    '',
 | 
				
			||||||
 | 
					    '{{options}}'
 | 
				
			||||||
 | 
					].join('\n');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = do_fwrules;
 | 
				
			||||||
							
								
								
									
										149
									
								
								lib/do_instance/do_snapshot/do_create.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								lib/do_instance/do_snapshot/do_create.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,149 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 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 2016 Joyent, Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * `triton snapshot create ...`
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var assert = require('assert-plus');
 | 
				
			||||||
 | 
					var format = require('util').format;
 | 
				
			||||||
 | 
					var vasync = require('vasync');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var common = require('../../common');
 | 
				
			||||||
 | 
					var distractions = require('../../distractions');
 | 
				
			||||||
 | 
					var errors = require('../../errors');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function do_create(subcmd, opts, args, cb) {
 | 
				
			||||||
 | 
					    assert.optionalString(opts.name, 'opts.name');
 | 
				
			||||||
 | 
					    assert.func(cb, 'cb');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (opts.help) {
 | 
				
			||||||
 | 
					        this.do_help('help', {}, [subcmd], cb);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (args.length === 0) {
 | 
				
			||||||
 | 
					        cb(new errors.UsageError('missing <inst> argument'));
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    } else if (args.length > 1) {
 | 
				
			||||||
 | 
					        cb(new errors.UsageError('incorrect number of arguments'));
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var inst = args[0];
 | 
				
			||||||
 | 
					    var cli = this.top;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var createOpts = {
 | 
				
			||||||
 | 
					        userId: opts.userId,
 | 
				
			||||||
 | 
					        id: inst
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (opts.name) {
 | 
				
			||||||
 | 
					        createOpts.name = opts.name;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vasync.pipeline({arg: {}, funcs: [
 | 
				
			||||||
 | 
					        function createSnapshot(ctx, next) {
 | 
				
			||||||
 | 
					            ctx.start = Date.now();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            cli.tritonapi.createInstanceSnapshot(createOpts,
 | 
				
			||||||
 | 
					            function (err, snapshot, res) {
 | 
				
			||||||
 | 
					                if (err) {
 | 
				
			||||||
 | 
					                    next(err);
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                console.log('Creating snapshot %s of instance %s',
 | 
				
			||||||
 | 
					                    snapshot.name, createOpts.id);
 | 
				
			||||||
 | 
					                ctx.name = snapshot.name;
 | 
				
			||||||
 | 
					                ctx.instId = res.instId;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                next();
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        function maybeWait(ctx, next) {
 | 
				
			||||||
 | 
					            if (!opts.wait) {
 | 
				
			||||||
 | 
					                return next();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            //  1 'wait': no distraction.
 | 
				
			||||||
 | 
					            // >1 'wait': distraction, pass in the N.
 | 
				
			||||||
 | 
					            var distraction;
 | 
				
			||||||
 | 
					            if (process.stderr.isTTY && opts.wait.length > 1) {
 | 
				
			||||||
 | 
					                distraction = distractions.createDistraction(opts.wait.length);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var cloudapi = cli.tritonapi.cloudapi;
 | 
				
			||||||
 | 
					            var waiter = cloudapi.waitForSnapshotStates.bind(cloudapi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            waiter({
 | 
				
			||||||
 | 
					                id: ctx.instId,
 | 
				
			||||||
 | 
					                name: ctx.name,
 | 
				
			||||||
 | 
					                states: ['created', 'failed']
 | 
				
			||||||
 | 
					            }, function (err, snap) {
 | 
				
			||||||
 | 
					                if (distraction) {
 | 
				
			||||||
 | 
					                    distraction.destroy();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (err) {
 | 
				
			||||||
 | 
					                    return next(err);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (opts.json) {
 | 
				
			||||||
 | 
					                    console.log(JSON.stringify(snap));
 | 
				
			||||||
 | 
					                } else if (snap.state === 'created') {
 | 
				
			||||||
 | 
					                    var duration = Date.now() - ctx.start;
 | 
				
			||||||
 | 
					                    console.log('Created snapshot "%s" in %s', snap.name,
 | 
				
			||||||
 | 
					                                common.humanDurationFromMs(duration));
 | 
				
			||||||
 | 
					                    next();
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    next(new Error(format('Failed to create snapshot "%s"',
 | 
				
			||||||
 | 
					                        snap.name)));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    ]}, cb);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					do_create.options = [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        names: ['help', 'h'],
 | 
				
			||||||
 | 
					        type: 'bool',
 | 
				
			||||||
 | 
					        help: 'Show this help.'
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        names: ['json', 'j'],
 | 
				
			||||||
 | 
					        type: 'bool',
 | 
				
			||||||
 | 
					        help: 'JSON stream output.'
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        names: ['name', 'n'],
 | 
				
			||||||
 | 
					        type: 'string',
 | 
				
			||||||
 | 
					        helpArg: '<snapname>',
 | 
				
			||||||
 | 
					        help: 'An optional name for a snapshot.'
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        names: ['wait', 'w'],
 | 
				
			||||||
 | 
					        type: 'arrayOfBool',
 | 
				
			||||||
 | 
					        help: 'Wait for the creation to complete. Use multiple times for a ' +
 | 
				
			||||||
 | 
					            'spinner.'
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					do_create.help = [
 | 
				
			||||||
 | 
					    'Create a snapshot of an instance.',
 | 
				
			||||||
 | 
					    '',
 | 
				
			||||||
 | 
					    'Usage:',
 | 
				
			||||||
 | 
					    '    {{name}} create [<options>] <inst>',
 | 
				
			||||||
 | 
					    '',
 | 
				
			||||||
 | 
					    '{{options}}',
 | 
				
			||||||
 | 
					    'Snapshot do not work for instances of type "kvm".'
 | 
				
			||||||
 | 
					].join('\n');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = do_create;
 | 
				
			||||||
							
								
								
									
										164
									
								
								lib/do_instance/do_snapshot/do_delete.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								lib/do_instance/do_snapshot/do_delete.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,164 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 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 2016 Joyent, Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * `triton snapshot delete ...`
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var assert = require('assert-plus');
 | 
				
			||||||
 | 
					var format = require('util').format;
 | 
				
			||||||
 | 
					var vasync = require('vasync');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var common = require('../../common');
 | 
				
			||||||
 | 
					var distractions = require('../../distractions');
 | 
				
			||||||
 | 
					var errors = require('../../errors');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function do_delete(subcmd, opts, args, cb) {
 | 
				
			||||||
 | 
					    assert.func(cb, 'cb');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (opts.help) {
 | 
				
			||||||
 | 
					        this.do_help('help', {}, [subcmd], cb);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (args.length < 2) {
 | 
				
			||||||
 | 
					        cb(new errors.UsageError('missing <inst> and <snapname> argument(s)'));
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var cli = this.top;
 | 
				
			||||||
 | 
					    var inst = args[0];
 | 
				
			||||||
 | 
					    var names = args.slice(1, args.length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function wait(instId, name, startTime, next) {
 | 
				
			||||||
 | 
					        //  1 'wait': no distraction.
 | 
				
			||||||
 | 
					        // >1 'wait': distraction, pass in the N.
 | 
				
			||||||
 | 
					        var distraction;
 | 
				
			||||||
 | 
					        if (process.stderr.isTTY && opts.wait.length > 1) {
 | 
				
			||||||
 | 
					            distraction = distractions.createDistraction(opts.wait.length);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var cloudapi = cli.tritonapi.cloudapi;
 | 
				
			||||||
 | 
					        var waiter = cloudapi.waitForSnapshotStates.bind(cloudapi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        waiter({
 | 
				
			||||||
 | 
					            id: instId,
 | 
				
			||||||
 | 
					            name: name,
 | 
				
			||||||
 | 
					            states: ['deleted']
 | 
				
			||||||
 | 
					        }, function (err, snap) {
 | 
				
			||||||
 | 
					            if (distraction) {
 | 
				
			||||||
 | 
					                distraction.destroy();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (err) {
 | 
				
			||||||
 | 
					                return next(err);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (snap.state === 'deleted') {
 | 
				
			||||||
 | 
					                var duration = Date.now() - startTime;
 | 
				
			||||||
 | 
					                var durStr = common.humanDurationFromMs(duration);
 | 
				
			||||||
 | 
					                console.log('Deleted snapshot "%s" in %s', name, durStr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                next();
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                // shouldn't get here, but...
 | 
				
			||||||
 | 
					                next(new Error(format('Failed to delete snapshot "%s"', name)));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vasync.pipeline({funcs: [
 | 
				
			||||||
 | 
					        function confirm(_, next) {
 | 
				
			||||||
 | 
					            if (opts.force) {
 | 
				
			||||||
 | 
					                return next();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var msg;
 | 
				
			||||||
 | 
					            if (names.length === 1) {
 | 
				
			||||||
 | 
					                msg = 'Delete snapshot "' + names[0] + '"? [y/n] ';
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                msg = format('Delete %d snapshots (%s)? [y/n] ',
 | 
				
			||||||
 | 
					                    names.length, names.join(', '));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            common.promptYesNo({msg: msg}, function (answer) {
 | 
				
			||||||
 | 
					                if (answer !== 'y') {
 | 
				
			||||||
 | 
					                    console.error('Aborting');
 | 
				
			||||||
 | 
					                    next(true); // early abort signal
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    next();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        function deleteThem(_, next) {
 | 
				
			||||||
 | 
					            var startTime = Date.now();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            vasync.forEachParallel({
 | 
				
			||||||
 | 
					                inputs: names,
 | 
				
			||||||
 | 
					                func: function deleteOne(name, nextName) {
 | 
				
			||||||
 | 
					                    cli.tritonapi.deleteInstanceSnapshot({
 | 
				
			||||||
 | 
					                        id: inst,
 | 
				
			||||||
 | 
					                        name: name
 | 
				
			||||||
 | 
					                    }, function (err, res) {
 | 
				
			||||||
 | 
					                        if (err) {
 | 
				
			||||||
 | 
					                            nextName(err);
 | 
				
			||||||
 | 
					                            return;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        var instId = res.instId;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        var msg = 'Deleting snapshot "%s" of instance "%s"';
 | 
				
			||||||
 | 
					                        console.log(msg, name, instId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if (opts.wait) {
 | 
				
			||||||
 | 
					                            wait(instId, name, startTime, nextName);
 | 
				
			||||||
 | 
					                        } else {
 | 
				
			||||||
 | 
					                            nextName();
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }, next);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    ]}, function (err) {
 | 
				
			||||||
 | 
					        if (err === true) {
 | 
				
			||||||
 | 
					            err = null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        cb(err);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					do_delete.options = [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        names: ['help', 'h'],
 | 
				
			||||||
 | 
					        type: 'bool',
 | 
				
			||||||
 | 
					        help: 'Show this help.'
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        names: ['force', 'f'],
 | 
				
			||||||
 | 
					        type: 'bool',
 | 
				
			||||||
 | 
					        help: 'Skip confirmation of delete.'
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        names: ['wait', 'w'],
 | 
				
			||||||
 | 
					        type: 'arrayOfBool',
 | 
				
			||||||
 | 
					        help: 'Wait for the deletion to complete. Use multiple times for a ' +
 | 
				
			||||||
 | 
					            'spinner.'
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					do_delete.help = [
 | 
				
			||||||
 | 
					    'Remove a snapshot from an instance.',
 | 
				
			||||||
 | 
					    '',
 | 
				
			||||||
 | 
					    'Usage:',
 | 
				
			||||||
 | 
					    '    {{name}} delete [<options>] <inst> <snapname> [<snapname>...]',
 | 
				
			||||||
 | 
					    '',
 | 
				
			||||||
 | 
					    '{{options}}'
 | 
				
			||||||
 | 
					].join('\n');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					do_delete.aliases = ['rm'];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = do_delete;
 | 
				
			||||||
							
								
								
									
										80
									
								
								lib/do_instance/do_snapshot/do_get.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								lib/do_instance/do_snapshot/do_get.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,80 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 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 2016 Joyent, Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * `triton snapshot get ...`
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var assert = require('assert-plus');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var common = require('../../common');
 | 
				
			||||||
 | 
					var errors = require('../../errors');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function do_get(subcmd, opts, args, cb) {
 | 
				
			||||||
 | 
					    assert.func(cb, 'cb');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (opts.help) {
 | 
				
			||||||
 | 
					        this.do_help('help', {}, [subcmd], cb);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (args.length < 2) {
 | 
				
			||||||
 | 
					        cb(new errors.UsageError('missing <inst> and/or <snapname> arguments'));
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    } else if (args.length > 2) {
 | 
				
			||||||
 | 
					        cb(new errors.UsageError('incorrect number of arguments'));
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var id = args[0];
 | 
				
			||||||
 | 
					    var name = args[1];
 | 
				
			||||||
 | 
					    var cli = this.top;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cli.tritonapi.getInstanceSnapshot({
 | 
				
			||||||
 | 
					        id: id,
 | 
				
			||||||
 | 
					        name: name
 | 
				
			||||||
 | 
					    }, function onSnapshot(err, snapshot) {
 | 
				
			||||||
 | 
					        if (err) {
 | 
				
			||||||
 | 
					            cb(err);
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (opts.json) {
 | 
				
			||||||
 | 
					            console.log(JSON.stringify(snapshot));
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            console.log(JSON.stringify(snapshot, null, 4));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        cb();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					do_get.options = [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        names: ['help', 'h'],
 | 
				
			||||||
 | 
					        type: 'bool',
 | 
				
			||||||
 | 
					        help: 'Show this help.'
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        names: ['json', 'j'],
 | 
				
			||||||
 | 
					        type: 'bool',
 | 
				
			||||||
 | 
					        help: 'JSON stream output.'
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					do_get.help = [
 | 
				
			||||||
 | 
					    'Show a specific snapshot of an instance.',
 | 
				
			||||||
 | 
					    '',
 | 
				
			||||||
 | 
					    'Usage:',
 | 
				
			||||||
 | 
					    '    {{name}} get <inst> <snapname>',
 | 
				
			||||||
 | 
					    '',
 | 
				
			||||||
 | 
					    '{{options}}'
 | 
				
			||||||
 | 
					].join('\n');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = do_get;
 | 
				
			||||||
							
								
								
									
										98
									
								
								lib/do_instance/do_snapshot/do_list.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								lib/do_instance/do_snapshot/do_list.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,98 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 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 2016 Joyent, Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * `triton snapshot list ...`
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var assert = require('assert-plus');
 | 
				
			||||||
 | 
					var tabula = require('tabula');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var common = require('../../common');
 | 
				
			||||||
 | 
					var errors = require('../../errors');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var COLUMNS_DEFAULT = 'name,state,created';
 | 
				
			||||||
 | 
					var SORT_DEFAULT = 'name';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function do_list(subcmd, opts, args, cb) {
 | 
				
			||||||
 | 
					    assert.func(cb, 'cb');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (opts.help) {
 | 
				
			||||||
 | 
					        this.do_help('help', {}, [subcmd], cb);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (args.length === 0) {
 | 
				
			||||||
 | 
					        cb(new errors.UsageError('missing <inst> argument'));
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    } else if (args.length > 1) {
 | 
				
			||||||
 | 
					        cb(new errors.UsageError('incorrect number of arguments'));
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var cli = this.top;
 | 
				
			||||||
 | 
					    var machineId = args[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cli.tritonapi.listInstanceSnapshots({
 | 
				
			||||||
 | 
					        id: machineId
 | 
				
			||||||
 | 
					    }, function onSnapshots(err, snapshots) {
 | 
				
			||||||
 | 
					        if (err) {
 | 
				
			||||||
 | 
					            cb(err);
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (opts.json) {
 | 
				
			||||||
 | 
					            common.jsonStream(snapshots);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            var columns = COLUMNS_DEFAULT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (opts.o) {
 | 
				
			||||||
 | 
					                columns = opts.o;
 | 
				
			||||||
 | 
					            } else if (opts.long) {
 | 
				
			||||||
 | 
					                columns = COLUMNS_DEFAULT;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            columns = columns.split(',');
 | 
				
			||||||
 | 
					            var sort = opts.s.split(',');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            tabula(snapshots, {
 | 
				
			||||||
 | 
					                skipHeader: opts.H,
 | 
				
			||||||
 | 
					                columns: columns,
 | 
				
			||||||
 | 
					                sort: sort
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        cb();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					do_list.options = [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        names: ['help', 'h'],
 | 
				
			||||||
 | 
					        type: 'bool',
 | 
				
			||||||
 | 
					        help: 'Show this help.'
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					].concat(common.getCliTableOptions({
 | 
				
			||||||
 | 
					    includeLong: true,
 | 
				
			||||||
 | 
					    sortDefault: SORT_DEFAULT
 | 
				
			||||||
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					do_list.help = [
 | 
				
			||||||
 | 
					    'Show all of an instance\'s snapshots.',
 | 
				
			||||||
 | 
					    '',
 | 
				
			||||||
 | 
					    'Usage:',
 | 
				
			||||||
 | 
					    '    {{name}} list [<options>] <inst>',
 | 
				
			||||||
 | 
					    '',
 | 
				
			||||||
 | 
					    '{{options}}'
 | 
				
			||||||
 | 
					].join('\n');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					do_list.aliases = ['ls'];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = do_list;
 | 
				
			||||||
							
								
								
									
										49
									
								
								lib/do_instance/do_snapshot/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								lib/do_instance/do_snapshot/index.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,49 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 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 2016 Joyent, Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * `triton snapshot ...`
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var Cmdln = require('cmdln').Cmdln;
 | 
				
			||||||
 | 
					var util = require('util');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ---- CLI class
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function SnapshotCLI(top) {
 | 
				
			||||||
 | 
					    this.top = top.top;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Cmdln.call(this, {
 | 
				
			||||||
 | 
					        name: top.name + ' snapshot',
 | 
				
			||||||
 | 
					        desc: 'List, get, create and delete Triton instance snapshots.',
 | 
				
			||||||
 | 
					        helpSubcmds: [
 | 
				
			||||||
 | 
					            'help',
 | 
				
			||||||
 | 
					            'create',
 | 
				
			||||||
 | 
					            'list',
 | 
				
			||||||
 | 
					            'get',
 | 
				
			||||||
 | 
					            'delete'
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        helpBody: 'Instances can be rolled back to a snapshot using\n' +
 | 
				
			||||||
 | 
					                  '`triton instance start --snapshot=<snapname>`.'
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					util.inherits(SnapshotCLI, Cmdln);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SnapshotCLI.prototype.init = function init(opts, args, cb) {
 | 
				
			||||||
 | 
					    this.log = this.top.log;
 | 
				
			||||||
 | 
					    Cmdln.prototype.init.apply(this, arguments);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SnapshotCLI.prototype.do_create = require('./do_create');
 | 
				
			||||||
 | 
					SnapshotCLI.prototype.do_get = require('./do_get');
 | 
				
			||||||
 | 
					SnapshotCLI.prototype.do_list = require('./do_list');
 | 
				
			||||||
 | 
					SnapshotCLI.prototype.do_delete = require('./do_delete');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = SnapshotCLI;
 | 
				
			||||||
							
								
								
									
										26
									
								
								lib/do_instance/do_snapshots.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								lib/do_instance/do_snapshots.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 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 2016 Joyent, Inc.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * `triton instance snapshots ...` shortcut for
 | 
				
			||||||
 | 
					 * `triton instance snapshot list ...`.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function do_snapshots(subcmd, opts, args, callback) {
 | 
				
			||||||
 | 
					    this.handlerFromSubcmd('snapshot').dispatch({
 | 
				
			||||||
 | 
					        subcmd: 'list',
 | 
				
			||||||
 | 
					        opts: opts,
 | 
				
			||||||
 | 
					        args: args
 | 
				
			||||||
 | 
					    }, callback);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					do_snapshots.help = 'A shortcut for "triton instance snapshot list".';
 | 
				
			||||||
 | 
					do_snapshots.options = require('./do_snapshot/do_list').options;
 | 
				
			||||||
 | 
					do_snapshots.hidden = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = do_snapshots;
 | 
				
			||||||
@ -66,6 +66,14 @@ function gen_do_ACTION(opts) {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    ];
 | 
					    ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (action === 'start') {
 | 
				
			||||||
 | 
					        do_ACTION.options.push({
 | 
				
			||||||
 | 
					            names: ['snapshot'],
 | 
				
			||||||
 | 
					            type: 'string',
 | 
				
			||||||
 | 
					            help: 'Name of snapshot to start machine with.'
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return do_ACTION;
 | 
					    return do_ACTION;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -77,7 +85,8 @@ function _doTheAction(action, subcmd, opts, args, callback) {
 | 
				
			|||||||
    var command, state;
 | 
					    var command, state;
 | 
				
			||||||
    switch (action) {
 | 
					    switch (action) {
 | 
				
			||||||
        case 'start':
 | 
					        case 'start':
 | 
				
			||||||
            command = 'startMachine';
 | 
					            command = opts.snapshot ? 'startMachineFromSnapshot' :
 | 
				
			||||||
 | 
					                                      'startMachine';
 | 
				
			||||||
            state = 'running';
 | 
					            state = 'running';
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case 'stop':
 | 
					        case 'stop':
 | 
				
			||||||
@ -126,7 +135,12 @@ function _doTheAction(action, subcmd, opts, args, callback) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            // called when "uuid" is set
 | 
					            // called when "uuid" is set
 | 
				
			||||||
            function done() {
 | 
					            function done() {
 | 
				
			||||||
                self.top.tritonapi.cloudapi[command](uuid,
 | 
					                var cOpts = uuid;
 | 
				
			||||||
 | 
					                if (command === 'startMachineFromSnapshot') {
 | 
				
			||||||
 | 
					                    cOpts = { id: uuid, name: opts.snapshot };
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                self.top.tritonapi.cloudapi[command](cOpts,
 | 
				
			||||||
                    function (err, body, res) {
 | 
					                    function (err, body, res) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    if (err) {
 | 
					                    if (err) {
 | 
				
			||||||
 | 
				
			|||||||
@ -22,7 +22,7 @@ function InstanceCLI(top) {
 | 
				
			|||||||
        name: top.name + ' instance',
 | 
					        name: top.name + ' instance',
 | 
				
			||||||
        /* BEGIN JSSTYLED */
 | 
					        /* BEGIN JSSTYLED */
 | 
				
			||||||
        desc: [
 | 
					        desc: [
 | 
				
			||||||
            'List, get, create and manage Triton instances.'
 | 
					            'List and manage Triton instances.'
 | 
				
			||||||
        ].join('\n'),
 | 
					        ].join('\n'),
 | 
				
			||||||
        /* END JSSTYLED */
 | 
					        /* END JSSTYLED */
 | 
				
			||||||
        helpOpts: {
 | 
					        helpOpts: {
 | 
				
			||||||
@ -42,6 +42,8 @@ function InstanceCLI(top) {
 | 
				
			|||||||
            'ssh',
 | 
					            'ssh',
 | 
				
			||||||
            'wait',
 | 
					            'wait',
 | 
				
			||||||
            'audit',
 | 
					            'audit',
 | 
				
			||||||
 | 
					            'fwrules',
 | 
				
			||||||
 | 
					            'snapshot',
 | 
				
			||||||
            'tag'
 | 
					            'tag'
 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
@ -65,6 +67,9 @@ InstanceCLI.prototype.do_reboot = require('./do_reboot');
 | 
				
			|||||||
InstanceCLI.prototype.do_ssh = require('./do_ssh');
 | 
					InstanceCLI.prototype.do_ssh = require('./do_ssh');
 | 
				
			||||||
InstanceCLI.prototype.do_wait = require('./do_wait');
 | 
					InstanceCLI.prototype.do_wait = require('./do_wait');
 | 
				
			||||||
InstanceCLI.prototype.do_audit = require('./do_audit');
 | 
					InstanceCLI.prototype.do_audit = require('./do_audit');
 | 
				
			||||||
 | 
					InstanceCLI.prototype.do_fwrules = require('./do_fwrules');
 | 
				
			||||||
 | 
					InstanceCLI.prototype.do_snapshot = require('./do_snapshot');
 | 
				
			||||||
 | 
					InstanceCLI.prototype.do_snapshots = require('./do_snapshots');
 | 
				
			||||||
InstanceCLI.prototype.do_tag = require('./do_tag');
 | 
					InstanceCLI.prototype.do_tag = require('./do_tag');
 | 
				
			||||||
InstanceCLI.prototype.do_tags = require('./do_tags');
 | 
					InstanceCLI.prototype.do_tags = require('./do_tags');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -23,7 +23,7 @@ function NetworkCLI(top) {
 | 
				
			|||||||
        name: top.name + ' network',
 | 
					        name: top.name + ' network',
 | 
				
			||||||
        /* BEGIN JSSTYLED */
 | 
					        /* BEGIN JSSTYLED */
 | 
				
			||||||
        desc: [
 | 
					        desc: [
 | 
				
			||||||
            'List, get, create and update Triton networks.'
 | 
					            'List and manage Triton networks.'
 | 
				
			||||||
        ].join('\n'),
 | 
					        ].join('\n'),
 | 
				
			||||||
        /* END JSSTYLED */
 | 
					        /* END JSSTYLED */
 | 
				
			||||||
        helpOpts: {
 | 
					        helpOpts: {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										465
									
								
								lib/tritonapi.js
									
									
									
									
									
								
							
							
						
						
									
										465
									
								
								lib/tritonapi.js
									
									
									
									
									
								
							@ -86,6 +86,31 @@ function _stepInstId(arg, next) {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * A function appropriate for `vasync.pipeline` funcs that takes a `arg.id`
 | 
				
			||||||
 | 
					 * fwrule shortid or uuid, and determines the fwrule id (setting it
 | 
				
			||||||
 | 
					 * as `arg.fwruleId`).
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * If the fwrule *was* retrieved, that is set as `arg.fwrule`.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					function _stepFwRuleId(arg, next) {
 | 
				
			||||||
 | 
					    assert.object(arg.client, 'arg.client');
 | 
				
			||||||
 | 
					    assert.string(arg.id, 'arg.id');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (common.isUUID(arg.id)) {
 | 
				
			||||||
 | 
					        arg.fwruleId = arg.id;
 | 
				
			||||||
 | 
					        next();
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        arg.client.getFirewallRule(arg.id, function (err, fwrule) {
 | 
				
			||||||
 | 
					            if (err) {
 | 
				
			||||||
 | 
					                next(err);
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                arg.fwruleId = fwrule.id;
 | 
				
			||||||
 | 
					                next();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//---- TritonApi class
 | 
					//---- TritonApi class
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -256,7 +281,7 @@ TritonApi.prototype._cacheGetJson = function _cacheGetJson(key, cb) {
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * @param opts {Object} Optional.
 | 
					 * @param opts {Object} Optional.
 | 
				
			||||||
 *      - useCache {Boolean} Default false. Whether to use Triton's local cache.
 | 
					 *      - useCache {Boolean} Default false. Whether to use Triton's local cache.
 | 
				
			||||||
 *        Note that the *currently* implementation will only use the cache
 | 
					 *        Note that the *current* implementation will only use the cache
 | 
				
			||||||
 *        when there are no filter options.
 | 
					 *        when there are no filter options.
 | 
				
			||||||
 *      - ... all other cloudapi ListImages options per
 | 
					 *      - ... all other cloudapi ListImages options per
 | 
				
			||||||
 *        <https://apidocs.joyent.com/cloudapi/#ListImages>
 | 
					 *        <https://apidocs.joyent.com/cloudapi/#ListImages>
 | 
				
			||||||
@ -735,6 +760,157 @@ TritonApi.prototype.getInstance = function getInstance(opts, cb) {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ---- instance snapshots
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Create a snapshot of an instance.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param {Object} opts
 | 
				
			||||||
 | 
					 *      - {String} id: The instance ID, name, or short ID. Required.
 | 
				
			||||||
 | 
					 *      - {String} name: The name for new snapshot. Optional.
 | 
				
			||||||
 | 
					 * @param {Function} callback `function (err, snapshots, res)`
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					TritonApi.prototype.createInstanceSnapshot =
 | 
				
			||||||
 | 
					function createInstanceSnapshot(opts, cb) {
 | 
				
			||||||
 | 
					    assert.string(opts.id, 'opts.id');
 | 
				
			||||||
 | 
					    assert.optionalString(opts.name, 'opts.name');
 | 
				
			||||||
 | 
					    assert.func(cb, 'cb');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var self = this;
 | 
				
			||||||
 | 
					    var res;
 | 
				
			||||||
 | 
					    var snapshot;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vasync.pipeline({arg: {client: self, id: opts.id}, funcs: [
 | 
				
			||||||
 | 
					        _stepInstId,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        function createSnapshot(arg, next) {
 | 
				
			||||||
 | 
					            self.cloudapi.createMachineSnapshot({
 | 
				
			||||||
 | 
					                id: arg.instId,
 | 
				
			||||||
 | 
					                name: opts.name
 | 
				
			||||||
 | 
					            }, function (err, snap, _res) {
 | 
				
			||||||
 | 
					                res = _res;
 | 
				
			||||||
 | 
					                res.instId = arg.instId; // gross hack, in case caller needs it
 | 
				
			||||||
 | 
					                snapshot = snap;
 | 
				
			||||||
 | 
					                next(err);
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    ]}, function (err) {
 | 
				
			||||||
 | 
					        cb(err, snapshot, res);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * List an instance's snapshots.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param {Object} opts
 | 
				
			||||||
 | 
					 *      - {String} id: The instance ID, name, or short ID. Required.
 | 
				
			||||||
 | 
					 * @param {Function} callback `function (err, snapshots, res)`
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					TritonApi.prototype.listInstanceSnapshots =
 | 
				
			||||||
 | 
					function listInstanceSnapshots(opts, cb) {
 | 
				
			||||||
 | 
					    assert.string(opts.id, 'opts.id');
 | 
				
			||||||
 | 
					    assert.func(cb, 'cb');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var self = this;
 | 
				
			||||||
 | 
					    var res;
 | 
				
			||||||
 | 
					    var snapshots;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vasync.pipeline({arg: {client: self, id: opts.id}, funcs: [
 | 
				
			||||||
 | 
					        _stepInstId,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        function listSnapshots(arg, next) {
 | 
				
			||||||
 | 
					            self.cloudapi.listMachineSnapshots({
 | 
				
			||||||
 | 
					                id: arg.instId,
 | 
				
			||||||
 | 
					                name: opts.name
 | 
				
			||||||
 | 
					            }, function (err, snaps, _res) {
 | 
				
			||||||
 | 
					                res = _res;
 | 
				
			||||||
 | 
					                res.instId = arg.instId; // gross hack, in case caller needs it
 | 
				
			||||||
 | 
					                snapshots = snaps;
 | 
				
			||||||
 | 
					                next(err);
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    ]}, function (err) {
 | 
				
			||||||
 | 
					        cb(err, snapshots, res);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Get an instance's snapshot.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param {Object} opts
 | 
				
			||||||
 | 
					 *      - {String} id: The instance ID, name, or short ID. Required.
 | 
				
			||||||
 | 
					 *      - {String} name: The name of the snapshot. Required.
 | 
				
			||||||
 | 
					 * @param {Function} callback `function (err, snapshot, res)`
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					TritonApi.prototype.getInstanceSnapshot =
 | 
				
			||||||
 | 
					function getInstanceSnapshot(opts, cb) {
 | 
				
			||||||
 | 
					    assert.string(opts.id, 'opts.id');
 | 
				
			||||||
 | 
					    assert.string(opts.name, 'opts.name');
 | 
				
			||||||
 | 
					    assert.func(cb, 'cb');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var self = this;
 | 
				
			||||||
 | 
					    var res;
 | 
				
			||||||
 | 
					    var snapshot;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vasync.pipeline({arg: {client: self, id: opts.id}, funcs: [
 | 
				
			||||||
 | 
					        _stepInstId,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        function getSnapshot(arg, next) {
 | 
				
			||||||
 | 
					            self.cloudapi.getMachineSnapshot({
 | 
				
			||||||
 | 
					                id: arg.instId,
 | 
				
			||||||
 | 
					                name: opts.name
 | 
				
			||||||
 | 
					            }, function (err, _snap, _res) {
 | 
				
			||||||
 | 
					                res = _res;
 | 
				
			||||||
 | 
					                res.instId = arg.instId; // gross hack, in case caller needs it
 | 
				
			||||||
 | 
					                snapshot = _snap;
 | 
				
			||||||
 | 
					                next(err);
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    ]}, function (err) {
 | 
				
			||||||
 | 
					        cb(err, snapshot, res);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Delete an instance's snapshot.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param {Object} opts
 | 
				
			||||||
 | 
					 *      - {String} id: The instance ID, name, or short ID. Required.
 | 
				
			||||||
 | 
					 *      - {String} name: The name of the snapshot. Required.
 | 
				
			||||||
 | 
					 * @param {Function} callback `function (err, res)`
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					TritonApi.prototype.deleteInstanceSnapshot =
 | 
				
			||||||
 | 
					function deleteInstanceSnapshot(opts, cb) {
 | 
				
			||||||
 | 
					    assert.string(opts.id, 'opts.id');
 | 
				
			||||||
 | 
					    assert.string(opts.name, 'opts.name');
 | 
				
			||||||
 | 
					    assert.func(cb, 'cb');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var self = this;
 | 
				
			||||||
 | 
					    var res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vasync.pipeline({arg: {client: self, id: opts.id}, funcs: [
 | 
				
			||||||
 | 
					        _stepInstId,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        function deleteSnapshot(arg, next) {
 | 
				
			||||||
 | 
					            self.cloudapi.deleteMachineSnapshot({
 | 
				
			||||||
 | 
					                id: arg.instId,
 | 
				
			||||||
 | 
					                name: opts.name
 | 
				
			||||||
 | 
					            }, function (err, _res) {
 | 
				
			||||||
 | 
					                res = _res;
 | 
				
			||||||
 | 
					                res.instId = arg.instId; // gross hack, in case caller needs it
 | 
				
			||||||
 | 
					                next(err);
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    ]}, function (err) {
 | 
				
			||||||
 | 
					        cb(err, res);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ---- instance tags
 | 
					// ---- instance tags
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@ -1249,6 +1425,293 @@ function deleteAllInstanceTags(opts, cb) {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ---- Firewall Rules
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Get a firewall rule by ID, or short ID, in that order.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * If there is more than one firewall rule with that short ID, then this errors
 | 
				
			||||||
 | 
					 * out.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					TritonApi.prototype.getFirewallRule = function getFirewallRule(id, cb) {
 | 
				
			||||||
 | 
					    assert.string(id, 'id');
 | 
				
			||||||
 | 
					    assert.func(cb, 'cb');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (common.isUUID(id)) {
 | 
				
			||||||
 | 
					        this.cloudapi.getFirewallRule(id, function (err, fwrule) {
 | 
				
			||||||
 | 
					            if (err) {
 | 
				
			||||||
 | 
					                if (err.restCode === 'ResourceNotFound') {
 | 
				
			||||||
 | 
					                    err = new errors.ResourceNotFoundError(err,
 | 
				
			||||||
 | 
					                        format('firewall rule with id %s was not found', id));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                cb(err);
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                cb(null, fwrule);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        this.cloudapi.listFirewallRules({}, function (err, fwrules) {
 | 
				
			||||||
 | 
					            if (err) {
 | 
				
			||||||
 | 
					                return cb(err);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var shortIdMatches = fwrules.filter(function (fwrule) {
 | 
				
			||||||
 | 
					                return fwrule.id.slice(0, 8) === id;
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (shortIdMatches.length === 1) {
 | 
				
			||||||
 | 
					                cb(null, shortIdMatches[0]);
 | 
				
			||||||
 | 
					            } else if (shortIdMatches.length === 0) {
 | 
				
			||||||
 | 
					                cb(new errors.ResourceNotFoundError(format(
 | 
				
			||||||
 | 
					                    'no firewall rule with short id "%s" was found', id)));
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                cb(new errors.ResourceNotFoundError(
 | 
				
			||||||
 | 
					                    format('"%s" is an ambiguous short id, with multiple ' +
 | 
				
			||||||
 | 
					                           'matching firewall rules', id)));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * List all firewall rules affecting an instance.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param {Object} opts
 | 
				
			||||||
 | 
					 *      - {String} id: The instance ID, name, or short ID. Required.
 | 
				
			||||||
 | 
					 * @param {Function} callback `function (err, instances, res)`
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					TritonApi.prototype.listInstanceFirewallRules =
 | 
				
			||||||
 | 
					function listInstanceFirewallRules(opts, cb) {
 | 
				
			||||||
 | 
					    assert.string(opts.id, 'opts.id');
 | 
				
			||||||
 | 
					    assert.func(cb, 'cb');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var self = this;
 | 
				
			||||||
 | 
					    var res;
 | 
				
			||||||
 | 
					    var fwrules;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vasync.pipeline({arg: {client: self, id: opts.id}, funcs: [
 | 
				
			||||||
 | 
					        _stepInstId,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        function listRules(arg, next) {
 | 
				
			||||||
 | 
					            self.cloudapi.listMachineFirewallRules({
 | 
				
			||||||
 | 
					                id: arg.instId
 | 
				
			||||||
 | 
					            }, function (err, rules, _res) {
 | 
				
			||||||
 | 
					                res = _res;
 | 
				
			||||||
 | 
					                fwrules = rules;
 | 
				
			||||||
 | 
					                next(err);
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    ]}, function (err) {
 | 
				
			||||||
 | 
					        cb(err, fwrules, res);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * List all instances affected by a firewall rule.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param {Object} opts
 | 
				
			||||||
 | 
					 *      - {String} id: The fwrule ID, or short ID. Required.
 | 
				
			||||||
 | 
					 * @param {Function} callback `function (err, instances, res)`
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					TritonApi.prototype.listFirewallRuleInstances =
 | 
				
			||||||
 | 
					function listFirewallRuleInstances(opts, cb) {
 | 
				
			||||||
 | 
					    assert.string(opts.id, 'opts.id');
 | 
				
			||||||
 | 
					    assert.func(cb, 'cb');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var self = this;
 | 
				
			||||||
 | 
					    var res;
 | 
				
			||||||
 | 
					    var instances;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vasync.pipeline({arg: {client: self, id: opts.id}, funcs: [
 | 
				
			||||||
 | 
					        _stepFwRuleId,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        function listInsts(arg, next) {
 | 
				
			||||||
 | 
					            self.cloudapi.listFirewallRuleMachines({
 | 
				
			||||||
 | 
					                id: arg.fwruleId
 | 
				
			||||||
 | 
					            }, function (err, machines, _res) {
 | 
				
			||||||
 | 
					                res = _res;
 | 
				
			||||||
 | 
					                instances = machines;
 | 
				
			||||||
 | 
					                next(err);
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    ]}, function (err) {
 | 
				
			||||||
 | 
					        cb(err, instances, res);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Update a firewall rule.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Dev Note: Currently cloudapi UpdateFirewallRule *requires* the 'rule' field,
 | 
				
			||||||
 | 
					 * which is overkill. `TritonApi.updateFirewallRule` adds sugar by making
 | 
				
			||||||
 | 
					 * 'rule' optional.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param {Object} opts
 | 
				
			||||||
 | 
					 *      - {String} id: The fwrule ID, or short ID. Required.
 | 
				
			||||||
 | 
					 *      - {String} rule: The fwrule text. Optional.
 | 
				
			||||||
 | 
					 *      - {Boolean} enabled: Default to false. Optional.
 | 
				
			||||||
 | 
					 *      - {String} description: Description of the rule. Optional.
 | 
				
			||||||
 | 
					 *      At least one of the fields must be provided.
 | 
				
			||||||
 | 
					 * @param {Function} callback `function (err, fwrule, res)`
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					TritonApi.prototype.updateFirewallRule = function updateFirewallRule(opts, cb) {
 | 
				
			||||||
 | 
					    // TODO: strict opts field validation
 | 
				
			||||||
 | 
					    assert.string(opts.id, 'opts.id');
 | 
				
			||||||
 | 
					    assert.optionalString(opts.rule, 'opts.rule');
 | 
				
			||||||
 | 
					    assert.optionalBool(opts.enabled, 'opts.enabled');
 | 
				
			||||||
 | 
					    assert.optionalString(opts.description, 'opts.description');
 | 
				
			||||||
 | 
					    assert.ok(opts.rule !== undefined || opts.enabled !== undefined ||
 | 
				
			||||||
 | 
					        opts.description !== undefined, 'at least one of opts.rule, '
 | 
				
			||||||
 | 
					        + 'opts.enabled, or opts.description is required');
 | 
				
			||||||
 | 
					    assert.func(cb, 'cb');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var self = this;
 | 
				
			||||||
 | 
					    var res;
 | 
				
			||||||
 | 
					    var updatedFwrule;
 | 
				
			||||||
 | 
					    var updateOpts = common.objCopy(opts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vasync.pipeline({arg: {client: self, id: opts.id}, funcs: [
 | 
				
			||||||
 | 
					        _stepFwRuleId,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /*
 | 
				
			||||||
 | 
					         * CloudAPI currently requires the 'rule' field. We provide sugar here
 | 
				
			||||||
 | 
					         * and fill it in for you.
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        function sugarFillRuleField(arg, next) {
 | 
				
			||||||
 | 
					            if (updateOpts.rule) {
 | 
				
			||||||
 | 
					                next();
 | 
				
			||||||
 | 
					            } else if (arg.fwrule) {
 | 
				
			||||||
 | 
					                updateOpts.rule = arg.fwrule.rule;
 | 
				
			||||||
 | 
					                next();
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                self.getFirewallRule(arg.fwruleId, function (err, fwrule) {
 | 
				
			||||||
 | 
					                    if (err) {
 | 
				
			||||||
 | 
					                        next(err);
 | 
				
			||||||
 | 
					                    } else {
 | 
				
			||||||
 | 
					                        updateOpts.rule = fwrule.rule;
 | 
				
			||||||
 | 
					                        next();
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        function updateRule(arg, next) {
 | 
				
			||||||
 | 
					            updateOpts.id = arg.fwruleId;
 | 
				
			||||||
 | 
					            self.cloudapi.updateFirewallRule(updateOpts,
 | 
				
			||||||
 | 
					                    function (err, fwrule, res_) {
 | 
				
			||||||
 | 
					                res = res_;
 | 
				
			||||||
 | 
					                updatedFwrule = fwrule;
 | 
				
			||||||
 | 
					                next(err);
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    ]}, function (err) {
 | 
				
			||||||
 | 
					        cb(err, updatedFwrule, res);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Enable a firewall rule.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param {Object} opts
 | 
				
			||||||
 | 
					 *      - {String} id: The fwrule ID, or short ID. Required.
 | 
				
			||||||
 | 
					 * @param {Function} callback `function (err, fwrule, res)`
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					TritonApi.prototype.enableFirewallRule = function enableFirewallRule(opts, cb) {
 | 
				
			||||||
 | 
					    assert.string(opts.id, 'opts.id');
 | 
				
			||||||
 | 
					    assert.func(cb, 'cb');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var self = this;
 | 
				
			||||||
 | 
					    var res;
 | 
				
			||||||
 | 
					    var fwrule;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vasync.pipeline({arg: {client: self, id: opts.id}, funcs: [
 | 
				
			||||||
 | 
					        _stepFwRuleId,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        function enableRule(arg, next) {
 | 
				
			||||||
 | 
					            self.cloudapi.enableFirewallRule({
 | 
				
			||||||
 | 
					                id: arg.fwruleId
 | 
				
			||||||
 | 
					            }, function (err, rule, _res) {
 | 
				
			||||||
 | 
					                res = _res;
 | 
				
			||||||
 | 
					                fwrule = rule;
 | 
				
			||||||
 | 
					                next(err);
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    ]}, function (err) {
 | 
				
			||||||
 | 
					        cb(err, fwrule, res);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Disable a firewall rule.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param {Object} opts
 | 
				
			||||||
 | 
					 *      - {String} id: The fwrule ID, or short ID. Required.
 | 
				
			||||||
 | 
					 * @param {Function} callback `function (err, fwrule, res)`
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					TritonApi.prototype.disableFirewallRule =
 | 
				
			||||||
 | 
					function disableFirewallRule(opts, cb) {
 | 
				
			||||||
 | 
					    assert.string(opts.id, 'opts.id');
 | 
				
			||||||
 | 
					    assert.func(cb, 'cb');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var self = this;
 | 
				
			||||||
 | 
					    var res;
 | 
				
			||||||
 | 
					    var fwrule;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vasync.pipeline({arg: {client: self, id: opts.id}, funcs: [
 | 
				
			||||||
 | 
					        _stepFwRuleId,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        function disableRule(arg, next) {
 | 
				
			||||||
 | 
					            self.cloudapi.disableFirewallRule({
 | 
				
			||||||
 | 
					                id: arg.fwruleId
 | 
				
			||||||
 | 
					            }, function (err, rule, _res) {
 | 
				
			||||||
 | 
					                res = _res;
 | 
				
			||||||
 | 
					                fwrule = rule;
 | 
				
			||||||
 | 
					                next(err);
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    ]}, function (err) {
 | 
				
			||||||
 | 
					        cb(err, fwrule, res);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Delete a firewall rule.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param {Object} opts
 | 
				
			||||||
 | 
					 *      - {String} id: The fwrule ID, or short ID. Required.
 | 
				
			||||||
 | 
					 * @param {Function} callback `function (err, res)`
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					TritonApi.prototype.deleteFirewallRule = function deleteFirewallRule(opts, cb) {
 | 
				
			||||||
 | 
					    assert.string(opts.id, 'opts.id');
 | 
				
			||||||
 | 
					    assert.func(cb, 'cb');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var self = this;
 | 
				
			||||||
 | 
					    var res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vasync.pipeline({arg: {client: self, id: opts.id}, funcs: [
 | 
				
			||||||
 | 
					        _stepFwRuleId,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        function deleteRule(arg, next) {
 | 
				
			||||||
 | 
					            self.cloudapi.deleteFirewallRule({
 | 
				
			||||||
 | 
					                id: arg.fwruleId
 | 
				
			||||||
 | 
					            }, function (err, _res) {
 | 
				
			||||||
 | 
					                res = _res;
 | 
				
			||||||
 | 
					                next(err);
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    ]}, function (err) {
 | 
				
			||||||
 | 
					        cb(err, res);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ---- RBAC
 | 
					// ---- RBAC
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,7 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "triton",
 | 
					  "name": "triton",
 | 
				
			||||||
  "description": "Joyent Triton CLI and client (https://www.joyent.com/triton)",
 | 
					  "description": "Joyent Triton CLI and client (https://www.joyent.com/triton)",
 | 
				
			||||||
  "version": "4.5.3",
 | 
					  "version": "4.6.0",
 | 
				
			||||||
  "author": "Joyent (joyent.com)",
 | 
					  "author": "Joyent (joyent.com)",
 | 
				
			||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
    "assert-plus": "0.2.0",
 | 
					    "assert-plus": "0.2.0",
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										261
									
								
								test/integration/cli-fwrules.test.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										261
									
								
								test/integration/cli-fwrules.test.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,261 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 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 (c) 2016, Joyent, Inc.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Integration tests for `triton fwrules ...`
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var h = require('./helpers');
 | 
				
			||||||
 | 
					var f = require('util').format;
 | 
				
			||||||
 | 
					var os = require('os');
 | 
				
			||||||
 | 
					var test = require('tape');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// --- Globals
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var DESC = 'This rule was created by node-triton tests';
 | 
				
			||||||
 | 
					var RULE = 'FROM any TO vm $id ALLOW tcp PORT 80';
 | 
				
			||||||
 | 
					var RULE2 = 'FROM any TO vm $id BLOCK tcp port 25';
 | 
				
			||||||
 | 
					var INST;
 | 
				
			||||||
 | 
					var ID;
 | 
				
			||||||
 | 
					var INST_ALIAS = f('nodetritontest-fwrules-%s', os.hostname());
 | 
				
			||||||
 | 
					var OPTS = {
 | 
				
			||||||
 | 
					    skip: !h.CONFIG.allowWriteActions
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// --- Tests
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if (OPTS.skip) {
 | 
				
			||||||
 | 
					    console.error('** skipping %s tests', __filename);
 | 
				
			||||||
 | 
					    console.error('** set "allowWriteActions" in test config to enable');
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test('triton fwrule', OPTS, function (tt) {
 | 
				
			||||||
 | 
					    h.printConfig(tt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tt.test('  cleanup existing inst with alias ' + INST_ALIAS, function (t) {
 | 
				
			||||||
 | 
					        h.deleteTestInst(t, INST_ALIAS, function (err) {
 | 
				
			||||||
 | 
					            t.ifErr(err);
 | 
				
			||||||
 | 
					            t.end();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tt.test('  setup: triton create', function (t) {
 | 
				
			||||||
 | 
					        h.createTestInst(t, INST_ALIAS, function onInst(err2, instId) {
 | 
				
			||||||
 | 
					            if (h.ifErr(t, err2, 'triton instance create'))
 | 
				
			||||||
 | 
					                return t.end();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            INST = instId;
 | 
				
			||||||
 | 
					            RULE = RULE.replace('$id', INST);
 | 
				
			||||||
 | 
					            RULE2 = RULE2.replace('$id', INST);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            t.end();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tt.test('  triton fwrule create --disabled', function (t) {
 | 
				
			||||||
 | 
					        var cmd = f('fwrule create -d "%s"', RULE);
 | 
				
			||||||
 | 
					        h.triton(cmd, function (err, stdout, stderr) {
 | 
				
			||||||
 | 
					            if (h.ifErr(t, err, 'triton fwrule create --disabled'))
 | 
				
			||||||
 | 
					                return t.end();
 | 
				
			||||||
 | 
					            /* JSSTYLED */
 | 
				
			||||||
 | 
					            var expected = /^Created firewall rule ([a-f0-9-]{36}) \(disabled\)$/m;
 | 
				
			||||||
 | 
					            var match = expected.exec(stdout);
 | 
				
			||||||
 | 
					            t.ok(match, f('stdout matches %s: %j', expected, stdout));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var id = match[1];
 | 
				
			||||||
 | 
					            t.ok(id);
 | 
				
			||||||
 | 
					            ID = id.match(/^(.+?)-/)[1]; // convert to short ID
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            t.end();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tt.test('  triton fwrule get (disabled)', function (t) {
 | 
				
			||||||
 | 
					        var cmd = 'fwrule get ' + ID;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        h.triton(cmd, function (err, stdout, stderr) {
 | 
				
			||||||
 | 
					            if (h.ifErr(t, err, 'triton fwrule get'))
 | 
				
			||||||
 | 
					                return t.end();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var obj = JSON.parse(stdout);
 | 
				
			||||||
 | 
					            t.equal(obj.rule, RULE, 'fwrule rule is correct');
 | 
				
			||||||
 | 
					            t.equal(obj.enabled, false, 'fwrule is disabled');
 | 
				
			||||||
 | 
					            t.end();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tt.test('  triton fwrule create', function (t) {
 | 
				
			||||||
 | 
					        var cmd = f('fwrule create -D "%s" "%s"', DESC, RULE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        h.triton(cmd, function (err, stdout, stderr) {
 | 
				
			||||||
 | 
					            if (h.ifErr(t, err, 'triton fwrule create'))
 | 
				
			||||||
 | 
					                return t.end();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            /* JSSTYLED */
 | 
				
			||||||
 | 
					            var expected = /^Created firewall rule ([a-f0-9-]{36})$/m;
 | 
				
			||||||
 | 
					            var match = expected.exec(stdout);
 | 
				
			||||||
 | 
					            t.ok(match, f('stdout matches %s: %j', expected, stdout));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var id = match[1];
 | 
				
			||||||
 | 
					            t.ok(id);
 | 
				
			||||||
 | 
					            ID = id.match(/^(.+?)-/)[1]; // convert to short ID
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            t.end();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tt.test('  triton fwrule get', function (t) {
 | 
				
			||||||
 | 
					        var cmd = 'fwrule get ' + ID;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        h.triton(cmd, function (err, stdout, stderr) {
 | 
				
			||||||
 | 
					            if (h.ifErr(t, err, 'triton fwrule get'))
 | 
				
			||||||
 | 
					                return t.end();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var obj = JSON.parse(stdout);
 | 
				
			||||||
 | 
					            t.equal(obj.rule, RULE, 'fwrule rule is correct');
 | 
				
			||||||
 | 
					            t.equal(obj.description, DESC, 'fwrule was properly created');
 | 
				
			||||||
 | 
					            t.equal(obj.enabled, true, 'fwrule enabled defaults to true');
 | 
				
			||||||
 | 
					            t.end();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tt.test('  triton fwrule enable', function (t) {
 | 
				
			||||||
 | 
					        var cmd = 'fwrule enable ' + ID;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        h.triton(cmd, function (err, stdout, stderr) {
 | 
				
			||||||
 | 
					            if (h.ifErr(t, err, 'triton fwrule enable'))
 | 
				
			||||||
 | 
					                return t.end();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            t.ok(stdout.match('Enabled firewall rule ' + ID));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            t.end();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tt.test('  triton fwrule disable', function (t) {
 | 
				
			||||||
 | 
					        var cmd = 'fwrule disable ' + ID;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        h.triton(cmd, function (err, stdout, stderr) {
 | 
				
			||||||
 | 
					            if (h.ifErr(t, err, 'triton fwrule disable'))
 | 
				
			||||||
 | 
					                return t.end();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            t.ok(stdout.match('Disabled firewall rule ' + ID));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            t.end();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tt.test('  triton fwrule update', function (t) {
 | 
				
			||||||
 | 
					        var cmd = 'fwrule update ' + ID + ' rule="' + RULE2 + '"';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        h.triton(cmd, function (err, stdout, stderr) {
 | 
				
			||||||
 | 
					            if (h.ifErr(t, err, 'triton fwrule update'))
 | 
				
			||||||
 | 
					                return t.end();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            t.ok(stdout.match('Updated firewall rule ' + ID +
 | 
				
			||||||
 | 
					                 ' \\(fields: rule\\)'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            t.end();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tt.test('  triton fwrule list', function (t) {
 | 
				
			||||||
 | 
					        h.triton('fwrule list -l', function (err, stdout, stderr) {
 | 
				
			||||||
 | 
					            if (h.ifErr(t, err, 'triton fwrule list'))
 | 
				
			||||||
 | 
					                return t.end();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var rules = stdout.split('\n');
 | 
				
			||||||
 | 
					            t.ok(rules[0].match(/ID\s+ENABLED\s+GLOBAL\s+RULE\s+DESCRIPTION/));
 | 
				
			||||||
 | 
					            rules.shift();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            t.ok(rules.length >= 1, 'triton fwrule list expected fwrule num');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var testRules = rules.filter(function (rule) {
 | 
				
			||||||
 | 
					                return rule.match(ID);
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            t.equal(testRules.length, 1, 'triton fwrule list test rule found');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            t.end();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tt.test('  triton fwrule instances', function (t) {
 | 
				
			||||||
 | 
					        h.triton('fwrule instances -l ' + ID, function (err, stdout, stderr) {
 | 
				
			||||||
 | 
					            if (h.ifErr(t, err, 'triton fwrule instances'))
 | 
				
			||||||
 | 
					                return t.end();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var machines = stdout.split('\n').filter(function (machine) {
 | 
				
			||||||
 | 
					                return machine !== '';
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            t.ok(machines[0].match(/ID\s+NAME\s+IMG\s+BRAND/));
 | 
				
			||||||
 | 
					            machines.shift();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (!INST)
 | 
				
			||||||
 | 
					                return t.end();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            t.equal(machines.length, 1, 'triton fwrule instances expected ' +
 | 
				
			||||||
 | 
					                    'num machines');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var testMachines = machines.filter(function (machine) {
 | 
				
			||||||
 | 
					                return machine.match(INST);
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            t.equal(testMachines.length, 1, 'triton fwrule instances test ' +
 | 
				
			||||||
 | 
					                    'machine found');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            t.end();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tt.test('  triton instance fwrules', function (t) {
 | 
				
			||||||
 | 
					        h.triton('instance fwrules -l ' + INST, function (err, stdout, stderr) {
 | 
				
			||||||
 | 
					            if (h.ifErr(t, err, 'triton fwrule list'))
 | 
				
			||||||
 | 
					                return t.end();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var rules = stdout.split('\n');
 | 
				
			||||||
 | 
					            t.ok(rules[0].match(/ID\s+ENABLED\s+GLOBAL\s+RULE\s+DESCRIPTION/));
 | 
				
			||||||
 | 
					            rules.shift();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            t.ok(rules.length >= 1, 'triton fwrule list expected fwrule num');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var testRules = rules.filter(function (rule) {
 | 
				
			||||||
 | 
					                return rule.match(ID);
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            t.equal(testRules.length, 1, 'triton fwrule list test rule found');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            t.end();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tt.test('  triton fwrule delete', function (t) {
 | 
				
			||||||
 | 
					        var cmd = 'fwrule delete ' + ID + ' --force';
 | 
				
			||||||
 | 
					        h.triton(cmd, function (err, stdout, stderr) {
 | 
				
			||||||
 | 
					            if (h.ifErr(t, err, 'triton fwrule delete'))
 | 
				
			||||||
 | 
					                return t.end();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            t.ok(stdout.match('Deleted rule ' + ID + ''), 'rule deleted');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            t.end();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * Use a timeout, because '-w' on delete doesn't have a way to know if the
 | 
				
			||||||
 | 
					     * attempt failed or if it is just taking a really long time.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    tt.test('  cleanup: triton rm INST', {timeout: 10 * 60 * 1000},
 | 
				
			||||||
 | 
					            function (t) {
 | 
				
			||||||
 | 
					        h.deleteTestInst(t, INST_ALIAS, function () {
 | 
				
			||||||
 | 
					            t.end();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
@ -39,32 +39,14 @@ if (opts.skip) {
 | 
				
			|||||||
    console.error('** set "allowWriteActions" in test config to enable');
 | 
					    console.error('** set "allowWriteActions" in test config to enable');
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
test('triton inst tag ...', opts, function (tt) {
 | 
					test('triton inst tag ...', opts, function (tt) {
 | 
				
			||||||
    tt.comment('Test config:');
 | 
					    h.printConfig(tt);
 | 
				
			||||||
    Object.keys(h.CONFIG).forEach(function (key) {
 | 
					 | 
				
			||||||
        var value = h.CONFIG[key];
 | 
					 | 
				
			||||||
        tt.comment(f('- %s: %j', key, value));
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    var inst;
 | 
					    var inst;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    tt.test('  cleanup: rm inst ' + INST_ALIAS + ' if exists', function (t) {
 | 
					    tt.test('  cleanup: rm inst ' + INST_ALIAS + ' if exists', function (t) {
 | 
				
			||||||
        h.triton(['inst', 'get', '-j', INST_ALIAS],
 | 
					        h.deleteTestInst(t, INST_ALIAS, function (err) {
 | 
				
			||||||
                function (err, stdout, stderr) {
 | 
					            t.ifErr(err);
 | 
				
			||||||
            if (err) {
 | 
					            t.end();
 | 
				
			||||||
                if (err.code === 3) {  // `triton` code for ResourceNotFound
 | 
					 | 
				
			||||||
                    t.ok(true, 'no pre-existing alias in the way');
 | 
					 | 
				
			||||||
                    t.end();
 | 
					 | 
				
			||||||
                } else {
 | 
					 | 
				
			||||||
                    t.ifErr(err);
 | 
					 | 
				
			||||||
                    t.end();
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                var oldInst = JSON.parse(stdout);
 | 
					 | 
				
			||||||
                h.safeTriton(t, ['delete', '-w', oldInst.id], function (dErr) {
 | 
					 | 
				
			||||||
                    t.ifError(dErr, 'deleted old inst ' + oldInst.id);
 | 
					 | 
				
			||||||
                    t.end();
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -40,30 +40,12 @@ if (opts.skip) {
 | 
				
			|||||||
    console.error('** set "allowWriteActions" in test config to enable');
 | 
					    console.error('** set "allowWriteActions" in test config to enable');
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
test('triton manage workflow', opts, function (tt) {
 | 
					test('triton manage workflow', opts, function (tt) {
 | 
				
			||||||
    tt.comment('Test config:');
 | 
					    h.printConfig(tt);
 | 
				
			||||||
    Object.keys(h.CONFIG).forEach(function (key) {
 | 
					 | 
				
			||||||
        var value = h.CONFIG[key];
 | 
					 | 
				
			||||||
        tt.comment(f('- %s: %j', key, value));
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    tt.test('  cleanup existing inst with alias ' + INST_ALIAS, function (t) {
 | 
					    tt.test('  cleanup existing inst with alias ' + INST_ALIAS, function (t) {
 | 
				
			||||||
        h.triton(['inst', 'get', '-j', INST_ALIAS],
 | 
					        h.deleteTestInst(t, INST_ALIAS, function (err) {
 | 
				
			||||||
                function (err, stdout, stderr) {
 | 
					            t.ifErr(err);
 | 
				
			||||||
            if (err) {
 | 
					            t.end();
 | 
				
			||||||
                if (err.code === 3) {  // `triton` code for ResourceNotFound
 | 
					 | 
				
			||||||
                    t.ok(true, 'no pre-existing alias in the way');
 | 
					 | 
				
			||||||
                    t.end();
 | 
					 | 
				
			||||||
                } else {
 | 
					 | 
				
			||||||
                    t.ifErr(err, err);
 | 
					 | 
				
			||||||
                    t.end();
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                var inst = JSON.parse(stdout);
 | 
					 | 
				
			||||||
                h.safeTriton(t, ['inst', 'rm', '-w', inst.id], function () {
 | 
					 | 
				
			||||||
                    t.ok(true, 'deleted inst ' + inst.id);
 | 
					 | 
				
			||||||
                    t.end();
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										149
									
								
								test/integration/cli-snapshots.test.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								test/integration/cli-snapshots.test.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,149 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 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 (c) 2016, Joyent, Inc.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Integration tests for `triton instance snapshot ...`
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var h = require('./helpers');
 | 
				
			||||||
 | 
					var f = require('util').format;
 | 
				
			||||||
 | 
					var os = require('os');
 | 
				
			||||||
 | 
					var test = require('tape');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// --- Globals
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var SNAP_NAME = 'test-snapshot';
 | 
				
			||||||
 | 
					var INST_ALIAS = f('nodetritontest-snapshots-%s', os.hostname());
 | 
				
			||||||
 | 
					var INST;
 | 
				
			||||||
 | 
					var OPTS = {
 | 
				
			||||||
 | 
					    skip: !h.CONFIG.allowWriteActions
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// --- Tests
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if (OPTS.skip) {
 | 
				
			||||||
 | 
					    console.error('** skipping %s tests', __filename);
 | 
				
			||||||
 | 
					    console.error('** set "allowWriteActions" in test config to enable');
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test('triton instance snapshot', OPTS, function (tt) {
 | 
				
			||||||
 | 
					    h.printConfig(tt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tt.test('  cleanup existing inst with alias ' + INST_ALIAS, function (t) {
 | 
				
			||||||
 | 
					        h.deleteTestInst(t, INST_ALIAS, function (err) {
 | 
				
			||||||
 | 
					            t.ifErr(err);
 | 
				
			||||||
 | 
					            t.end();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tt.test('  setup: triton instance create', function (t) {
 | 
				
			||||||
 | 
					        h.createTestInst(t, INST_ALIAS, function onInst(err2, instId) {
 | 
				
			||||||
 | 
					            if (h.ifErr(t, err2, 'triton instance create'))
 | 
				
			||||||
 | 
					                return t.end();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            INST = instId.match(/^(.+?)-/)[1]; // convert to short ID
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            t.end();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tt.test('  triton instance snapshot create', function (t) {
 | 
				
			||||||
 | 
					        var cmd = 'instance snapshot create -w -n ' + SNAP_NAME + ' ' + INST;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        h.triton(cmd, function (err, stdout, stderr) {
 | 
				
			||||||
 | 
					            if (h.ifErr(t, err, 'triton instance snapshot create'))
 | 
				
			||||||
 | 
					                return t.end();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            t.ok(stdout.match('Created snapshot "' + SNAP_NAME + '" in \\d+'),
 | 
				
			||||||
 | 
					                 'snapshot made');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            t.end();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tt.test('  triton instance snapshot get', function (t) {
 | 
				
			||||||
 | 
					        var cmd = 'instance snapshot get ' + INST + ' ' + SNAP_NAME;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        h.triton(cmd, function (err, stdout, stderr) {
 | 
				
			||||||
 | 
					            if (h.ifErr(t, err, 'triton instance snapshot get'))
 | 
				
			||||||
 | 
					                return t.end();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var obj = JSON.parse(stdout);
 | 
				
			||||||
 | 
					            t.equal(obj.name, SNAP_NAME, 'snapshot name is correct');
 | 
				
			||||||
 | 
					            t.equal(obj.state, 'created', 'snapshot was properly created');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            t.end();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tt.test('  triton instance snapshot list', function (t) {
 | 
				
			||||||
 | 
					        var cmd = 'instance snapshot list ' + INST;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        h.triton(cmd, function (err, stdout, stderr) {
 | 
				
			||||||
 | 
					            if (h.ifErr(t, err, 'triton instance snapshot list'))
 | 
				
			||||||
 | 
					                return t.end();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var snaps = stdout.split('\n');
 | 
				
			||||||
 | 
					            t.ok(snaps[0].match(/NAME\s+STATE\s+CREATED/));
 | 
				
			||||||
 | 
					            snaps.shift();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            t.ok(snaps.length >= 1, 'triton snap list expected snap num');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var testSnaps = snaps.filter(function (snap) {
 | 
				
			||||||
 | 
					                return snap.match(SNAP_NAME);
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            t.equal(testSnaps.length, 1, 'triton snap list test snap found');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            t.end();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tt.test('  triton instance start --snapshot', function (t) {
 | 
				
			||||||
 | 
					        var cmd = 'instance start ' + INST + ' -w --snapshot=' + SNAP_NAME;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        h.triton(cmd, function (err, stdout, stderr) {
 | 
				
			||||||
 | 
					            if (h.ifErr(t, err, 'triton instance start --snapshot'))
 | 
				
			||||||
 | 
					                return t.end();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            t.ok(stdout.match('Start instance ' + INST));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            t.end();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tt.test('  triton instance snapshot delete', function (t) {
 | 
				
			||||||
 | 
					        var cmd = 'instance snapshot delete  -w --force ' + INST + ' ' +
 | 
				
			||||||
 | 
					                  SNAP_NAME;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        h.triton(cmd, function (err, stdout, stderr) {
 | 
				
			||||||
 | 
					            if (h.ifErr(t, err, 'triton instance snapshot delete'))
 | 
				
			||||||
 | 
					                return t.end();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            t.ok(stdout.match('Deleting snapshot "' + SNAP_NAME + '"',
 | 
				
			||||||
 | 
					                 'deleting snapshot'));
 | 
				
			||||||
 | 
					            t.ok(stdout.match('Deleted snapshot "' + SNAP_NAME + '" in \\d+s',
 | 
				
			||||||
 | 
					                 'deleted snapshot'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            t.end();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * Use a timeout, because '-w' on delete doesn't have a way to know if the
 | 
				
			||||||
 | 
					     * attempt failed or if it is just taking a really long time.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    tt.test('  cleanup: triton instance rm INST', {timeout: 10 * 60 * 1000},
 | 
				
			||||||
 | 
					            function (t) {
 | 
				
			||||||
 | 
					        h.deleteTestInst(t, INST_ALIAS, function () {
 | 
				
			||||||
 | 
					            t.end();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
@ -43,6 +43,12 @@ var subs = [
 | 
				
			|||||||
    ['instance delete', 'instance rm', 'delete', 'rm'],
 | 
					    ['instance delete', 'instance rm', 'delete', 'rm'],
 | 
				
			||||||
    ['instance wait'],
 | 
					    ['instance wait'],
 | 
				
			||||||
    ['instance audit'],
 | 
					    ['instance audit'],
 | 
				
			||||||
 | 
					    ['instance fwrules'],
 | 
				
			||||||
 | 
					    ['instance snapshot'],
 | 
				
			||||||
 | 
					    ['instance snapshot create'],
 | 
				
			||||||
 | 
					    ['instance snapshot list', 'instance snapshot ls', 'instance snapshots'],
 | 
				
			||||||
 | 
					    ['instance snapshot get'],
 | 
				
			||||||
 | 
					    ['instance snapshot delete', 'instance snapshot rm'],
 | 
				
			||||||
    ['ssh'],
 | 
					    ['ssh'],
 | 
				
			||||||
    ['network'],
 | 
					    ['network'],
 | 
				
			||||||
    ['network list', 'networks'],
 | 
					    ['network list', 'networks'],
 | 
				
			||||||
@ -58,6 +64,15 @@ var subs = [
 | 
				
			|||||||
    ['package', 'pkg'],
 | 
					    ['package', 'pkg'],
 | 
				
			||||||
    ['package get'],
 | 
					    ['package get'],
 | 
				
			||||||
    ['package list', 'packages', 'pkgs'],
 | 
					    ['package list', 'packages', 'pkgs'],
 | 
				
			||||||
 | 
					    ['fwrule'],
 | 
				
			||||||
 | 
					    ['fwrule create'],
 | 
				
			||||||
 | 
					    ['fwrule list', 'fwrule ls'],
 | 
				
			||||||
 | 
					    ['fwrule get'],
 | 
				
			||||||
 | 
					    ['fwrule update'],
 | 
				
			||||||
 | 
					    ['fwrule delete', 'fwrule rm'],
 | 
				
			||||||
 | 
					    ['fwrule enable'],
 | 
				
			||||||
 | 
					    ['fwrule disable'],
 | 
				
			||||||
 | 
					    ['fwrule instances', 'fwrule insts'],
 | 
				
			||||||
    ['rbac'],
 | 
					    ['rbac'],
 | 
				
			||||||
    ['rbac info'],
 | 
					    ['rbac info'],
 | 
				
			||||||
    ['rbac apply'],
 | 
					    ['rbac apply'],
 | 
				
			||||||
 | 
				
			|||||||
@ -122,6 +122,8 @@ function triton(args, opts, cb) {
 | 
				
			|||||||
    }, cb);
 | 
					    }, cb);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * `triton ...` wrapper that:
 | 
					 * `triton ...` wrapper that:
 | 
				
			||||||
 * - tests non-error exit
 | 
					 * - tests non-error exit
 | 
				
			||||||
@ -255,6 +257,68 @@ function createClient() {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Create a small test instance.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					function createTestInst(t, name, cb) {
 | 
				
			||||||
 | 
					    getTestPkg(t, function (err, pkgId) {
 | 
				
			||||||
 | 
					        t.ifErr(err);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        getTestImg(t, function (err2, imgId) {
 | 
				
			||||||
 | 
					            t.ifErr(err2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var cmd = f('instance create -w -n %s %s %s', name, imgId, pkgId);
 | 
				
			||||||
 | 
					            triton(cmd, function (err3, stdout) {
 | 
				
			||||||
 | 
					                t.ifErr(err3, 'create test instance');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                var match = stdout.match(/Created .+? \((.+)\)/);
 | 
				
			||||||
 | 
					                var inst = match[1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                cb(null, inst);
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Remove test instance, if exists.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					function deleteTestInst(t, name, cb) {
 | 
				
			||||||
 | 
					    triton(['inst', 'get', '-j', name], function (err, stdout, stderr) {
 | 
				
			||||||
 | 
					        if (err) {
 | 
				
			||||||
 | 
					            if (err.code === 3) {  // `triton` code for ResourceNotFound
 | 
				
			||||||
 | 
					                t.ok(true, 'no pre-existing alias in the way');
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                t.ifErr(err);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return cb();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var oldInst = JSON.parse(stdout);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        safeTriton(t, ['delete', '-w', oldInst.id], function (dErr) {
 | 
				
			||||||
 | 
					            t.ifError(dErr, 'deleted old inst ' + oldInst.id);
 | 
				
			||||||
 | 
					            cb();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Print out a listing of the test config.json values.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					function printConfig(t) {
 | 
				
			||||||
 | 
					    t.comment('Test config:');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Object.keys(CONFIG).forEach(function (key) {
 | 
				
			||||||
 | 
					        var value = CONFIG[key];
 | 
				
			||||||
 | 
					        t.comment(f('- %s: %j', key, value));
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// --- exports
 | 
					// --- exports
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module.exports = {
 | 
					module.exports = {
 | 
				
			||||||
@ -262,9 +326,12 @@ module.exports = {
 | 
				
			|||||||
    triton: triton,
 | 
					    triton: triton,
 | 
				
			||||||
    safeTriton: safeTriton,
 | 
					    safeTriton: safeTriton,
 | 
				
			||||||
    createClient: createClient,
 | 
					    createClient: createClient,
 | 
				
			||||||
 | 
					    createTestInst: createTestInst,
 | 
				
			||||||
 | 
					    deleteTestInst: deleteTestInst,
 | 
				
			||||||
    getTestImg: getTestImg,
 | 
					    getTestImg: getTestImg,
 | 
				
			||||||
    getTestPkg: getTestPkg,
 | 
					    getTestPkg: getTestPkg,
 | 
				
			||||||
    jsonStreamParse: jsonStreamParse,
 | 
					    jsonStreamParse: jsonStreamParse,
 | 
				
			||||||
 | 
					    printConfig: printConfig,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ifErr: testcommon.ifErr
 | 
					    ifErr: testcommon.ifErr
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user