PUBAPI-1233/PUBAPI-1234 - add support for triton fwrules
and
`triton snapshots`; triton can work with machine snapshots and firewall rules.
This commit is contained in:
parent
e91f8f28da
commit
f3956df8ce
@ -217,10 +217,12 @@ function CLI() {
|
|||||||
'stop',
|
'stop',
|
||||||
'reboot',
|
'reboot',
|
||||||
'ssh',
|
'ssh',
|
||||||
|
'snapshot',
|
||||||
{ group: 'Images, Packages, Networks' },
|
{ group: 'Images, Packages, Networks' },
|
||||||
'image',
|
'image',
|
||||||
'package',
|
'package',
|
||||||
'network',
|
'network',
|
||||||
|
'fwrule',
|
||||||
{ group: 'Other Commands' },
|
{ group: 'Other Commands' },
|
||||||
'info',
|
'info',
|
||||||
'account',
|
'account',
|
||||||
@ -354,6 +356,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');
|
||||||
@ -376,6 +381,9 @@ CLI.prototype.do_package = require('./do_package');
|
|||||||
CLI.prototype.do_networks = require('./do_networks');
|
CLI.prototype.do_networks = require('./do_networks');
|
||||||
CLI.prototype.do_network = require('./do_network');
|
CLI.prototype.do_network = require('./do_network');
|
||||||
|
|
||||||
|
// Snapshots
|
||||||
|
CLI.prototype.do_snapshot = require('./do_snapshot');
|
||||||
|
|
||||||
// Hidden commands
|
// Hidden commands
|
||||||
CLI.prototype.do_cloudapi = require('./do_cloudapi');
|
CLI.prototype.do_cloudapi = require('./do_cloudapi');
|
||||||
CLI.prototype.do_badger = require('./do_badger');
|
CLI.prototype.do_badger = require('./do_badger');
|
||||||
|
397
lib/cloudapi2.js
397
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.enableFirewall =
|
||||||
|
function enableFirewall(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.disableFirewall =
|
||||||
|
function disableFirewall(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;
|
||||||
@ -917,6 +940,378 @@ CloudApi.prototype.machineAudit = function machineAudit(id, cb) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// --- snapshots
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new snapshot for a given machine.
|
||||||
|
*
|
||||||
|
* The machine cannot be a KVM brand.
|
||||||
|
*
|
||||||
|
* 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.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');
|
||||||
|
|
||||||
|
this._request({
|
||||||
|
method: 'POST',
|
||||||
|
path: format('/%s/machines/%s/snapshots', this.account, opts.id),
|
||||||
|
data: opts
|
||||||
|
}, 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,
|
||||||
|
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).
|
||||||
|
*/
|
||||||
|
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/machine/%s/snapshots/%s', this.account, opts.id,
|
||||||
|
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,
|
||||||
|
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.
|
||||||
|
* @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');
|
||||||
|
|
||||||
|
this._request({
|
||||||
|
method: 'POST',
|
||||||
|
path: format('/%s/fwrules', this.account),
|
||||||
|
data: opts
|
||||||
|
}, 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 {String} id (required) The machine 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_FIREWALL_RULE_FIELDS = {
|
||||||
|
enabled: 'boolean',
|
||||||
|
rule: 'string',
|
||||||
|
description: 'string'
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates a Firewall Rule.
|
||||||
|
*
|
||||||
|
* @param {Object} opts object containing:
|
||||||
|
* - {String} id (required) The fwrule id.
|
||||||
|
* - {String} rule (required) the fwrule text.
|
||||||
|
* - {Boolean} enabled (optional) default to false.
|
||||||
|
* @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.optionalBool(opts.description, 'opts.description');
|
||||||
|
assert.func(cb, 'cb');
|
||||||
|
|
||||||
|
this._request({
|
||||||
|
method: 'POST',
|
||||||
|
path: format('/%s/fwrules/%s', this.account, opts.id),
|
||||||
|
data: opts
|
||||||
|
}, function (err, req, res, body) {
|
||||||
|
cb(err, body, res);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable a Firewall Rule.
|
||||||
|
*
|
||||||
|
* @param {String} id (required) The machine id.
|
||||||
|
* @param {Function} callback of the form `function (err, fwrule, res)`
|
||||||
|
*/
|
||||||
|
CloudApi.prototype.enableFirewallRule =
|
||||||
|
function enableFirewallRule(id, cb) {
|
||||||
|
assert.uuid(id, 'id');
|
||||||
|
assert.func(cb, 'cb');
|
||||||
|
|
||||||
|
this._request({
|
||||||
|
method: 'POST',
|
||||||
|
path: format('/%s/fwrules/%s/enable', this.account, id),
|
||||||
|
data: {}
|
||||||
|
}, function (err, req, res, body) {
|
||||||
|
cb(err, body, res);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disable a Firewall Rule.
|
||||||
|
*
|
||||||
|
* @param {String} id (required) The machine id.
|
||||||
|
* @param {Function} callback of the form `function (err, fwrule, res)`
|
||||||
|
*/
|
||||||
|
CloudApi.prototype.disableFirewallRule =
|
||||||
|
function disableFirewallRule(id, cb) {
|
||||||
|
assert.uuid(id, 'id');
|
||||||
|
assert.func(cb, 'cb');
|
||||||
|
|
||||||
|
this._request({
|
||||||
|
method: 'POST',
|
||||||
|
path: format('/%s/fwrules/%s/disable', this.account, id),
|
||||||
|
data: {}
|
||||||
|
}, function (err, req, res, body) {
|
||||||
|
cb(err, body, res);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <http://apidocs.joyent.com/cloudapi/#DeleteUser>
|
||||||
|
*
|
||||||
|
* @param {Object} opts (object)
|
||||||
|
* - {String} id (required) for your firewall.
|
||||||
|
* @param {Function} cb of the form `function (err, res)`
|
||||||
|
*/
|
||||||
|
CloudApi.prototype.deleteFirewallRule =
|
||||||
|
function deleteFirewallRule(opts, cb) {
|
||||||
|
assert.object(opts, 'opts');
|
||||||
|
assert.string(opts.id, 'opts.id');
|
||||||
|
assert.func(cb, 'cb');
|
||||||
|
|
||||||
|
this._request({
|
||||||
|
method: 'DELETE',
|
||||||
|
path: format('/%s/fwrules/%s', this.account, opts.id)
|
||||||
|
}, function (err, req, 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
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
86
lib/do_fwrule/do_create.js
Normal file
86
lib/do_fwrule/do_create.js
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2015 Joyent, Inc.
|
||||||
|
*
|
||||||
|
* `triton 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.enabled, 'opts.enabled');
|
||||||
|
assert.func(cb, 'cb');
|
||||||
|
|
||||||
|
if (opts.help) {
|
||||||
|
this.do_help('help', {}, [subcmd], cb);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.length === 0) {
|
||||||
|
cb(new errors.UsageError('Missing RULE argument'));
|
||||||
|
return;
|
||||||
|
} else if (args.length > 1) {
|
||||||
|
cb(new errors.UsageError('Incorrect number of arguments'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
opts.rule = args[0];
|
||||||
|
|
||||||
|
var cli = this.top;
|
||||||
|
cli.tritonapi.cloudapi.createFirewallRule(opts, function (err, fwrule) {
|
||||||
|
if (err) {
|
||||||
|
cb(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Created firewall rule %s', fwrule.id);
|
||||||
|
|
||||||
|
cb();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
do_create.options = [
|
||||||
|
{
|
||||||
|
names: ['help', 'h'],
|
||||||
|
type: 'bool',
|
||||||
|
help: 'Show this help.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
names: ['json', 'j'],
|
||||||
|
type: 'bool',
|
||||||
|
help: 'JSON stream output.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
names: ['enabled', 'e'],
|
||||||
|
type: 'bool',
|
||||||
|
help: 'If the firewall rule should be enabled upon creation.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
names: ['description', 'd'],
|
||||||
|
type: 'string',
|
||||||
|
help: 'Description of the firewall rule.'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
do_create.help = [
|
||||||
|
'Create a firewall rule.',
|
||||||
|
'',
|
||||||
|
'Usage:',
|
||||||
|
' {{name}} create [<options>] RULE',
|
||||||
|
'',
|
||||||
|
'{{options}}'
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
module.exports = do_create;
|
112
lib/do_fwrule/do_delete.js
Normal file
112
lib/do_fwrule/do_delete.js
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2015 Joyent, Inc.
|
||||||
|
*
|
||||||
|
* `triton snapshot delete ...`
|
||||||
|
*/
|
||||||
|
|
||||||
|
var assert = require('assert-plus');
|
||||||
|
var format = require('util').format;
|
||||||
|
var fs = require('fs');
|
||||||
|
var sshpk = require('sshpk');
|
||||||
|
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.forEachPipeline({
|
||||||
|
inputs: ruleIds,
|
||||||
|
func: function deleteOne(id, nextId) {
|
||||||
|
cli.tritonapi.cloudapi.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 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'));
|
||||||
|
return;
|
||||||
|
} else if (args.length > 1) {
|
||||||
|
cb(new errors.UsageError('Incorrect number of arguments'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var id = args[0];
|
||||||
|
var cli = this.top;
|
||||||
|
|
||||||
|
// XXX add support for shortId
|
||||||
|
cli.tritonapi.cloudapi.disableFirewallRule(id, function onRule(err) {
|
||||||
|
if (err) {
|
||||||
|
cb(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Disabled firewall rule %s', id);
|
||||||
|
|
||||||
|
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',
|
||||||
|
'',
|
||||||
|
'{{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 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'));
|
||||||
|
return;
|
||||||
|
} else if (args.length > 1) {
|
||||||
|
cb(new errors.UsageError('Incorrect number of arguments'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var id = args[0];
|
||||||
|
var cli = this.top;
|
||||||
|
|
||||||
|
// XXX add support for shortId
|
||||||
|
cli.tritonapi.cloudapi.enableFirewallRule(id, function onRule(err) {
|
||||||
|
if (err) {
|
||||||
|
cb(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Enabled firewall rule %s', id);
|
||||||
|
|
||||||
|
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',
|
||||||
|
'',
|
||||||
|
'{{options}}'
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
module.exports = do_enable;
|
78
lib/do_fwrule/do_get.js
Normal file
78
lib/do_fwrule/do_get.js
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* 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) {
|
||||||
|
var errMsg = 'missing FWRULE-ID argument';
|
||||||
|
cb(new errors.UsageError(errMsg));
|
||||||
|
return;
|
||||||
|
} else if (args.length > 1) {
|
||||||
|
cb(new errors.UsageError('Incorrect number of arguments'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var id = args[0];
|
||||||
|
var cli = this.top;
|
||||||
|
|
||||||
|
// XXX add support for shortId
|
||||||
|
cli.tritonapi.cloudapi.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.cloudapi.listFirewallRuleMachines({
|
||||||
|
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.normShortId(rule.id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
tabula(rules, {
|
||||||
|
skipHeader: false,
|
||||||
|
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;
|
189
lib/do_fwrule/do_update.js
Normal file
189
lib/do_fwrule/do_update.js
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
/*
|
||||||
|
* 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_FIREWALL_RULE_FIELDS
|
||||||
|
= require('../cloudapi2').CloudApi.prototype.UPDATE_FIREWALL_RULE_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.pop();
|
||||||
|
|
||||||
|
vasync.pipeline({arg: {}, funcs: [
|
||||||
|
function gatherDataArgs(ctx, next) {
|
||||||
|
if (opts.file) {
|
||||||
|
next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
ctx.data = common.objFromKeyValueArgs(args, {
|
||||||
|
disableDotted: true,
|
||||||
|
typeHintFromKey: UPDATE_FIREWALL_RULE_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);
|
||||||
|
for (var i = 0; i < keys.length; i++) {
|
||||||
|
var key = keys[i];
|
||||||
|
var value = ctx.data[key];
|
||||||
|
var type = UPDATE_FIREWALL_RULE_FIELDS[key];
|
||||||
|
if (!type) {
|
||||||
|
next(new errors.UsageError(format('unknown or ' +
|
||||||
|
'unupdateable field: %s (updateable fields are: %s)',
|
||||||
|
key,
|
||||||
|
Object.keys(UPDATE_FIREWALL_RULE_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 keys = Object.keys(ctx.data);
|
||||||
|
if (keys.length === 0) {
|
||||||
|
console.log('No fields given for firewall rule update');
|
||||||
|
next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.data.id = id;
|
||||||
|
|
||||||
|
tritonapi.cloudapi.updateFirewallRule(ctx.data, function (err) {
|
||||||
|
if (err) {
|
||||||
|
next(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Updated firewall rule %s (fields: %s)', id,
|
||||||
|
keys.join(', '));
|
||||||
|
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
]}, cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
do_update.options = [
|
||||||
|
{
|
||||||
|
names: ['help', 'h'],
|
||||||
|
type: 'bool',
|
||||||
|
help: 'Show this help.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
names: ['file', 'f'],
|
||||||
|
type: 'string',
|
||||||
|
helpArg: '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 [FIELD=VALUE ...] FWRULE-ID',
|
||||||
|
' {{name}} update -f JSON-FILE FWRULE-ID',
|
||||||
|
'',
|
||||||
|
'{{options}}',
|
||||||
|
|
||||||
|
'Updateable fields:',
|
||||||
|
' ' + Object.keys(UPDATE_FIREWALL_RULE_FIELDS).sort().map(function (f) {
|
||||||
|
return f + ' (' + UPDATE_FIREWALL_RULE_FIELDS[f] + ')';
|
||||||
|
}).join('\n '),
|
||||||
|
''
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
do_update.completionArgtypes = ['tritonupdatefwrulefield'];
|
||||||
|
|
||||||
|
module.exports = do_update;
|
56
lib/do_fwrule/index.js
Normal file
56
lib/do_fwrule/index.js
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* 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 FirewallRuleCLI(top) {
|
||||||
|
this.top = top;
|
||||||
|
|
||||||
|
Cmdln.call(this, {
|
||||||
|
name: top.name + ' fwrule',
|
||||||
|
desc: 'Firewall rule commands',
|
||||||
|
helpSubcmds: [
|
||||||
|
'help',
|
||||||
|
{ group: 'Key Resources' },
|
||||||
|
'create',
|
||||||
|
'list',
|
||||||
|
'get',
|
||||||
|
'update',
|
||||||
|
'delete',
|
||||||
|
'enable',
|
||||||
|
'disable',
|
||||||
|
'instances'
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
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;
|
101
lib/do_instance/do_fwrules.js
Normal file
101
lib/do_instance/do_fwrules.js
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* 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 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.normShortId(rule.id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
tabula(rules, {
|
||||||
|
skipHeader: false,
|
||||||
|
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');
|
||||||
|
|
||||||
|
//do_fwrules.aliases = ['fwrules'];
|
||||||
|
|
||||||
|
module.exports = do_fwrules;
|
@ -41,7 +41,8 @@ function InstanceCLI(top) {
|
|||||||
{ group: '' },
|
{ group: '' },
|
||||||
'ssh',
|
'ssh',
|
||||||
'wait',
|
'wait',
|
||||||
'audit'
|
'audit',
|
||||||
|
'fwrules'
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -64,6 +65,7 @@ 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.aliases = ['inst'];
|
InstanceCLI.aliases = ['inst'];
|
||||||
|
|
||||||
|
147
lib/do_snapshot/do_create.js
Normal file
147
lib/do_snapshot/do_create.js
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
/*
|
||||||
|
* 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.cloudapi.createMachineSnapshot(createOpts,
|
||||||
|
function (err, snapshot) {
|
||||||
|
if (err) {
|
||||||
|
next(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Creating snapshot %s', snapshot.name);
|
||||||
|
ctx.name = snapshot.name;
|
||||||
|
|
||||||
|
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: inst,
|
||||||
|
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: 'SNAPSHOT-NAME',
|
||||||
|
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 a machine.',
|
||||||
|
'',
|
||||||
|
'Usage:',
|
||||||
|
' {{name}} create [<options>] INST',
|
||||||
|
'',
|
||||||
|
'{{options}}',
|
||||||
|
'Snapshot do not work for instances of type "kvm".'
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
module.exports = do_create;
|
161
lib/do_snapshot/do_delete.js
Normal file
161
lib/do_snapshot/do_delete.js
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
/*
|
||||||
|
* 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 SNAPSHOT-NAME argument(s)'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var cli = this.top;
|
||||||
|
var inst = args[0];
|
||||||
|
var names = args.slice(1, args.length);
|
||||||
|
|
||||||
|
function wait(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: inst,
|
||||||
|
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.cloudapi.deleteMachineSnapshot({
|
||||||
|
id: inst,
|
||||||
|
name: name
|
||||||
|
}, function (err) {
|
||||||
|
if (err) {
|
||||||
|
nextName(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Deleting snapshot "%s"', name);
|
||||||
|
|
||||||
|
if (opts.wait) {
|
||||||
|
wait(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 a machine.',
|
||||||
|
'',
|
||||||
|
'Usage:',
|
||||||
|
' {{name}} delete [<options>] SNAPSHOT-NAME [SNAPSHOT-NAME...]',
|
||||||
|
'',
|
||||||
|
'{{options}}'
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
do_delete.aliases = ['rm'];
|
||||||
|
|
||||||
|
module.exports = do_delete;
|
81
lib/do_snapshot/do_get.js
Normal file
81
lib/do_snapshot/do_get.js
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
* 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) {
|
||||||
|
var errMsg = 'missing INST and/or SNAPSHOT-NAME arguments';
|
||||||
|
cb(new errors.UsageError(errMsg));
|
||||||
|
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.cloudapi.getMachineSnapshot({
|
||||||
|
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 a machine.',
|
||||||
|
'',
|
||||||
|
'Usage:',
|
||||||
|
' {{name}} get INST SNAPSHOT-NAME',
|
||||||
|
'',
|
||||||
|
'{{options}}'
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
module.exports = do_get;
|
95
lib/do_snapshot/do_list.js
Normal file
95
lib/do_snapshot/do_list.js
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* 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';
|
||||||
|
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 !== 1) {
|
||||||
|
cb(new errors.UsageError('incorrect number of arguments'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var cli = this.top;
|
||||||
|
var machineId = args[0];
|
||||||
|
|
||||||
|
cli.tritonapi.cloudapi.listMachineSnapshots({
|
||||||
|
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: false,
|
||||||
|
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 a machines\'s snapshots.',
|
||||||
|
'',
|
||||||
|
'Usage:',
|
||||||
|
' {{name}} list [<options>]',
|
||||||
|
'',
|
||||||
|
'{{options}}'
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
do_list.aliases = ['ls'];
|
||||||
|
|
||||||
|
module.exports = do_list;
|
48
lib/do_snapshot/index.js
Normal file
48
lib/do_snapshot/index.js
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2015 Joyent, Inc.
|
||||||
|
*
|
||||||
|
* `triton snapshot ...`
|
||||||
|
*/
|
||||||
|
|
||||||
|
var Cmdln = require('cmdln').Cmdln;
|
||||||
|
var util = require('util');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ---- CLI class
|
||||||
|
|
||||||
|
function SnapshotCLI(top) {
|
||||||
|
this.top = top;
|
||||||
|
|
||||||
|
Cmdln.call(this, {
|
||||||
|
name: top.name + ' snapshot',
|
||||||
|
desc: 'Machine snapshot commands',
|
||||||
|
helpSubcmds: [
|
||||||
|
'help',
|
||||||
|
{ group: 'Key Resources' },
|
||||||
|
'create',
|
||||||
|
'list',
|
||||||
|
'get',
|
||||||
|
'delete'
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
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;
|
197
test/integration/cli-fwrules.test.js
Normal file
197
test/integration/cli-fwrules.test.js
Normal file
@ -0,0 +1,197 @@
|
|||||||
|
/*
|
||||||
|
* 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 format = require('util').format;
|
||||||
|
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;
|
||||||
|
|
||||||
|
// --- Tests
|
||||||
|
|
||||||
|
test('triton fwrule', function (tt) {
|
||||||
|
tt.test('setup', function (t) {
|
||||||
|
h.triton('insts -j', function (err, stdout, stderr) {
|
||||||
|
if (h.ifErr(t, err, 'triton insts'))
|
||||||
|
return t.end();
|
||||||
|
|
||||||
|
var rows = stdout.split('\n');
|
||||||
|
INST = JSON.parse(rows[0]).id;
|
||||||
|
t.ok(INST);
|
||||||
|
|
||||||
|
RULE = RULE.replace('$id', INST);
|
||||||
|
RULE2 = RULE2.replace('$id', INST);
|
||||||
|
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
tt.test(' triton fwrule create', function (t) {
|
||||||
|
var cmd = format('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();
|
||||||
|
|
||||||
|
var match = stdout.match('Created firewall rule (.+)');
|
||||||
|
t.ok(match, 'fwrule made');
|
||||||
|
|
||||||
|
ID = match[1];
|
||||||
|
t.ok(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, false, 'fwrule enabled defaults to false');
|
||||||
|
|
||||||
|
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 rule="' + RULE2 + '" ' + ID;
|
||||||
|
|
||||||
|
h.triton(cmd, function (err, stdout, stderr) {
|
||||||
|
if (h.ifErr(t, err, 'triton fwrule disable'))
|
||||||
|
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();
|
||||||
|
|
||||||
|
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 ' + ID, 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();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
103
test/integration/cli-snapshots.test.js
Normal file
103
test/integration/cli-snapshots.test.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 (c) 2016, Joyent, Inc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Integration tests for `triton snapshot ...`
|
||||||
|
*/
|
||||||
|
|
||||||
|
var h = require('./helpers');
|
||||||
|
var test = require('tape');
|
||||||
|
|
||||||
|
// --- Globals
|
||||||
|
|
||||||
|
var SNAP_NAME = 'test-snapshot';
|
||||||
|
var INST;
|
||||||
|
|
||||||
|
// --- Tests
|
||||||
|
|
||||||
|
test('triton snapshot', function (tt) {
|
||||||
|
tt.test('setup', function (t) {
|
||||||
|
h.triton('insts -j', function (err, stdout, stderr) {
|
||||||
|
if (h.ifErr(t, err, 'triton insts'))
|
||||||
|
return t.end();
|
||||||
|
|
||||||
|
var rows = stdout.split('\n');
|
||||||
|
INST = JSON.parse(rows[0]).id;
|
||||||
|
t.ok(INST);
|
||||||
|
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
tt.test(' triton snapshot create', function (t) {
|
||||||
|
var cmd = 'snapshot create -w -n ' + SNAP_NAME + ' ' + INST;
|
||||||
|
|
||||||
|
h.triton(cmd, function (err, stdout, stderr) {
|
||||||
|
if (h.ifErr(t, err, 'triton snapshot create'))
|
||||||
|
return t.end();
|
||||||
|
|
||||||
|
t.ok(stdout.match('Created snapshot "' + SNAP_NAME + '" in \\d+'),
|
||||||
|
'snapshot made');
|
||||||
|
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
tt.test(' triton snapshot get', function (t) {
|
||||||
|
var cmd = 'snapshot get ' + INST + ' ' + SNAP_NAME;
|
||||||
|
|
||||||
|
h.triton(cmd, function (err, stdout, stderr) {
|
||||||
|
if (h.ifErr(t, err, 'triton 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 snapshot list', function (t) {
|
||||||
|
h.triton('snapshot list ' + INST, function (err, stdout, stderr) {
|
||||||
|
if (h.ifErr(t, err, 'triton snapshot list'))
|
||||||
|
return t.end();
|
||||||
|
|
||||||
|
var snaps = stdout.split('\n');
|
||||||
|
t.ok(snaps[0].match(/NAME\s+STATE/));
|
||||||
|
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 snapshot delete', function (t) {
|
||||||
|
var cmd = 'snapshot delete ' + INST + ' ' + SNAP_NAME + ' -w --force';
|
||||||
|
h.triton(cmd, function (err, stdout, stderr) {
|
||||||
|
if (h.ifErr(t, err, 'triton 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();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -43,6 +43,7 @@ var subs = [
|
|||||||
['instance delete', 'instance rm', 'delete', 'rm'],
|
['instance delete', 'instance rm', 'delete', 'rm'],
|
||||||
['instance wait'],
|
['instance wait'],
|
||||||
['instance audit'],
|
['instance audit'],
|
||||||
|
['instance fwrules'],
|
||||||
['ssh'],
|
['ssh'],
|
||||||
['network'],
|
['network'],
|
||||||
['network list', 'networks'],
|
['network list', 'networks'],
|
||||||
@ -58,6 +59,20 @@ var subs = [
|
|||||||
['package', 'pkg'],
|
['package', 'pkg'],
|
||||||
['package get'],
|
['package get'],
|
||||||
['package list', 'packages', 'pkgs'],
|
['package list', 'packages', 'pkgs'],
|
||||||
|
['snapshot'],
|
||||||
|
['snapshot create'],
|
||||||
|
['snapshot list', 'snapshot ls'],
|
||||||
|
['snapshot get'],
|
||||||
|
['snapshot delete', 'snapshot rm'],
|
||||||
|
['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'],
|
||||||
|
Reference in New Issue
Block a user