PUBAPI-1266 - add support for instance (en|dis)able-firewall.
This commit is contained in:
parent
e8d1fb578b
commit
fb20159053
@ -3,6 +3,7 @@
|
|||||||
## 4.7.1 (not yet released)
|
## 4.7.1 (not yet released)
|
||||||
|
|
||||||
- #97 `triton profile set -` to set the *last* profile as current.
|
- #97 `triton profile set -` to set the *last* profile as current.
|
||||||
|
- PUBAPI-1266 Added `instance enable-firewall` and `instance disable-firewall`
|
||||||
|
|
||||||
|
|
||||||
## 4.7.0
|
## 4.7.0
|
||||||
|
@ -755,7 +755,7 @@ CloudApi.prototype.rebootMachine = function rebootMachine(uuid, callback) {
|
|||||||
* Enables machine firewall.
|
* Enables machine firewall.
|
||||||
*
|
*
|
||||||
* @param {String} id (required) The machine id.
|
* @param {String} id (required) The machine id.
|
||||||
* @param {Function} callback of the form `function (err, machine, res)`
|
* @param {Function} callback of the form `function (err, null, res)`
|
||||||
*/
|
*/
|
||||||
CloudApi.prototype.enableMachineFirewall =
|
CloudApi.prototype.enableMachineFirewall =
|
||||||
function enableMachineFirewall(uuid, callback) {
|
function enableMachineFirewall(uuid, callback) {
|
||||||
@ -767,7 +767,7 @@ function enableMachineFirewall(uuid, callback) {
|
|||||||
* Disables machine firewall.
|
* Disables machine firewall.
|
||||||
*
|
*
|
||||||
* @param {String} id (required) The machine id.
|
* @param {String} id (required) The machine id.
|
||||||
* @param {Function} callback of the form `function (err, machine, res)`
|
* @param {Function} callback of the form `function (err, null, res)`
|
||||||
*/
|
*/
|
||||||
CloudApi.prototype.disableMachineFirewall =
|
CloudApi.prototype.disableMachineFirewall =
|
||||||
function disableMachineFirewall(uuid, callback) {
|
function disableMachineFirewall(uuid, callback) {
|
||||||
@ -940,6 +940,50 @@ CloudApi.prototype.machineAudit = function machineAudit(id, cb) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait for a machine's firewall to enable or disable.
|
||||||
|
*
|
||||||
|
* @param {Object} options
|
||||||
|
* - {String} id {required} machine id
|
||||||
|
* - {Boolean} state {require} - desired state
|
||||||
|
* - {Number} interval (optional) - time in ms to poll
|
||||||
|
* @param {Function} callback of the form f(err, machine, res).
|
||||||
|
*/
|
||||||
|
CloudApi.prototype.waitForMachineFirewallState =
|
||||||
|
function waitForMachineFirewallState(opts, cb) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
assert.object(opts, 'opts');
|
||||||
|
assert.uuid(opts.id, 'opts.id');
|
||||||
|
assert.bool(opts.state, 'opts.state');
|
||||||
|
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.getMachine({
|
||||||
|
id: opts.id
|
||||||
|
}, function (err, machine, res) {
|
||||||
|
if (err) {
|
||||||
|
cb(err, null, res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts.state === machine.firewall_enabled) {
|
||||||
|
cb(null, machine, res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(poll, interval);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// --- machine tags
|
// --- machine tags
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2120,4 +2164,4 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
CloudApi: CloudApi
|
CloudApi: CloudApi
|
||||||
};
|
};
|
||||||
|
148
lib/do_instance/do_disable_firewall.js
Normal file
148
lib/do_instance/do_disable_firewall.js
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
/*
|
||||||
|
* 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 disable-firewall ...`
|
||||||
|
*/
|
||||||
|
|
||||||
|
var assert = require('assert-plus');
|
||||||
|
var format = require('util').format;
|
||||||
|
var vasync = require('vasync');
|
||||||
|
|
||||||
|
var common = require('../common');
|
||||||
|
var errors = require('../errors');
|
||||||
|
|
||||||
|
|
||||||
|
function do_disable_firewall(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(s)'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var cli = this.top;
|
||||||
|
var insts = args;
|
||||||
|
|
||||||
|
function wait(instId, startTime, next) {
|
||||||
|
var cloudapi = cli.tritonapi.cloudapi;
|
||||||
|
var waiter = cloudapi.waitForMachineFirewallState.bind(cloudapi);
|
||||||
|
|
||||||
|
waiter({
|
||||||
|
id: instId,
|
||||||
|
state: false
|
||||||
|
}, function (err, inst) {
|
||||||
|
if (err) {
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inst.firewall_enabled === false) {
|
||||||
|
var duration = Date.now() - startTime;
|
||||||
|
var durStr = common.humanDurationFromMs(duration);
|
||||||
|
console.log('Disabled firewall for instance "%s" in %s', instId,
|
||||||
|
durStr);
|
||||||
|
next();
|
||||||
|
} else {
|
||||||
|
// shouldn't get here, but...
|
||||||
|
var msg = 'Failed to disable firewall for instance "%s"';
|
||||||
|
next(new Error(format(msg, instId)));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
vasync.pipeline({funcs: [
|
||||||
|
function confirm(_, next) {
|
||||||
|
if (opts.force) {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
|
var msg;
|
||||||
|
if (insts.length === 1) {
|
||||||
|
msg = 'Disable firewall for instance "' + insts[0] +
|
||||||
|
'"? [y/n] ';
|
||||||
|
} else {
|
||||||
|
msg = format('Disable firewalls for %d instances (%s)? [y/n] ',
|
||||||
|
insts.length, insts.join(', '));
|
||||||
|
}
|
||||||
|
|
||||||
|
common.promptYesNo({msg: msg}, function (answer) {
|
||||||
|
if (answer !== 'y') {
|
||||||
|
console.error('Aborting');
|
||||||
|
next(true); // early abort signal
|
||||||
|
} else {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
function disableThem(_, next) {
|
||||||
|
var startTime = Date.now();
|
||||||
|
|
||||||
|
vasync.forEachParallel({
|
||||||
|
inputs: insts,
|
||||||
|
func: function disableOne(instId, nextId) {
|
||||||
|
cli.tritonapi.disableInstanceFirewall({
|
||||||
|
id: instId
|
||||||
|
}, function (err, __, res) {
|
||||||
|
if (err) {
|
||||||
|
nextId(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var msg = 'Disabling firewall for instance "%s"';
|
||||||
|
console.log(msg, res.instId);
|
||||||
|
|
||||||
|
if (opts.wait) {
|
||||||
|
wait(res.instId, startTime, nextId);
|
||||||
|
} else {
|
||||||
|
nextId();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, next);
|
||||||
|
}
|
||||||
|
]}, function (err) {
|
||||||
|
if (err === true) {
|
||||||
|
err = null;
|
||||||
|
}
|
||||||
|
cb(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
do_disable_firewall.options = [
|
||||||
|
{
|
||||||
|
names: ['help', 'h'],
|
||||||
|
type: 'bool',
|
||||||
|
help: 'Show this help.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
names: ['force', 'f'],
|
||||||
|
type: 'bool',
|
||||||
|
help: 'Skip confirmation to enable.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
names: ['wait', 'w'],
|
||||||
|
type: 'bool',
|
||||||
|
help: 'Wait for the firewall to be disabled.'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
do_disable_firewall.help = [
|
||||||
|
'Disable the firewall of one or more instances.',
|
||||||
|
'',
|
||||||
|
'Usage:',
|
||||||
|
' {{name}} disable-firewall [<options>] <inst> [<inst>...]',
|
||||||
|
'',
|
||||||
|
'{{options}}'
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
module.exports = do_disable_firewall;
|
147
lib/do_instance/do_enable_firewall.js
Normal file
147
lib/do_instance/do_enable_firewall.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 instance enable-firewall ...`
|
||||||
|
*/
|
||||||
|
|
||||||
|
var assert = require('assert-plus');
|
||||||
|
var format = require('util').format;
|
||||||
|
var vasync = require('vasync');
|
||||||
|
|
||||||
|
var common = require('../common');
|
||||||
|
var errors = require('../errors');
|
||||||
|
|
||||||
|
|
||||||
|
function do_enable_firewall(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(s)'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var cli = this.top;
|
||||||
|
var insts = args;
|
||||||
|
|
||||||
|
function wait(instId, startTime, next) {
|
||||||
|
var cloudapi = cli.tritonapi.cloudapi;
|
||||||
|
var waiter = cloudapi.waitForMachineFirewallState.bind(cloudapi);
|
||||||
|
|
||||||
|
waiter({
|
||||||
|
id: instId,
|
||||||
|
state: true
|
||||||
|
}, function (err, inst) {
|
||||||
|
if (err) {
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inst.firewall_enabled === true) {
|
||||||
|
var duration = Date.now() - startTime;
|
||||||
|
var durStr = common.humanDurationFromMs(duration);
|
||||||
|
console.log('Enabled firewall for instance "%s" in %s', instId,
|
||||||
|
durStr);
|
||||||
|
next();
|
||||||
|
} else {
|
||||||
|
// shouldn't get here, but...
|
||||||
|
var msg = 'Failed to enable firewall for instance "%s"';
|
||||||
|
next(new Error(format(msg, instId)));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
vasync.pipeline({funcs: [
|
||||||
|
function confirm(_, next) {
|
||||||
|
if (opts.force) {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
|
var msg;
|
||||||
|
if (insts.length === 1) {
|
||||||
|
msg = 'Enable firewall for instance "' + insts[0] + '"? [y/n] ';
|
||||||
|
} else {
|
||||||
|
msg = format('Enable firewalls for %d instances (%s)? [y/n] ',
|
||||||
|
insts.length, insts.join(', '));
|
||||||
|
}
|
||||||
|
|
||||||
|
common.promptYesNo({msg: msg}, function (answer) {
|
||||||
|
if (answer !== 'y') {
|
||||||
|
console.error('Aborting');
|
||||||
|
next(true); // early abort signal
|
||||||
|
} else {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
function enableThem(_, next) {
|
||||||
|
var startTime = Date.now();
|
||||||
|
|
||||||
|
vasync.forEachParallel({
|
||||||
|
inputs: insts,
|
||||||
|
func: function enableOne(instId, nextId) {
|
||||||
|
cli.tritonapi.enableInstanceFirewall({
|
||||||
|
id: instId
|
||||||
|
}, function (err, __, res) {
|
||||||
|
if (err) {
|
||||||
|
nextId(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var msg = 'Enabling firewall for instance "%s"';
|
||||||
|
console.log(msg, res.instId);
|
||||||
|
|
||||||
|
if (opts.wait) {
|
||||||
|
wait(res.instId, startTime, nextId);
|
||||||
|
} else {
|
||||||
|
nextId();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, next);
|
||||||
|
}
|
||||||
|
]}, function (err) {
|
||||||
|
if (err === true) {
|
||||||
|
err = null;
|
||||||
|
}
|
||||||
|
cb(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
do_enable_firewall.options = [
|
||||||
|
{
|
||||||
|
names: ['help', 'h'],
|
||||||
|
type: 'bool',
|
||||||
|
help: 'Show this help.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
names: ['force', 'f'],
|
||||||
|
type: 'bool',
|
||||||
|
help: 'Skip confirmation to enable.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
names: ['wait', 'w'],
|
||||||
|
type: 'bool',
|
||||||
|
help: 'Wait for the firewall to be enabled.'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
do_enable_firewall.help = [
|
||||||
|
'Enable the firewall of one or more instances.',
|
||||||
|
'',
|
||||||
|
'Usage:',
|
||||||
|
' {{name}} enable-firewall [<options>] <inst> [<inst>...]',
|
||||||
|
'',
|
||||||
|
'{{options}}'
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
module.exports = do_enable_firewall;
|
@ -39,6 +39,9 @@ function InstanceCLI(top) {
|
|||||||
'stop',
|
'stop',
|
||||||
'reboot',
|
'reboot',
|
||||||
{ group: '' },
|
{ group: '' },
|
||||||
|
'enable-firewall',
|
||||||
|
'disable-firewall',
|
||||||
|
{ group: '' },
|
||||||
'ssh',
|
'ssh',
|
||||||
'wait',
|
'wait',
|
||||||
'audit',
|
'audit',
|
||||||
@ -64,6 +67,9 @@ InstanceCLI.prototype.do_start = require('./do_start');
|
|||||||
InstanceCLI.prototype.do_stop = require('./do_stop');
|
InstanceCLI.prototype.do_stop = require('./do_stop');
|
||||||
InstanceCLI.prototype.do_reboot = require('./do_reboot');
|
InstanceCLI.prototype.do_reboot = require('./do_reboot');
|
||||||
|
|
||||||
|
InstanceCLI.prototype.do_enable_firewall = require('./do_enable_firewall');
|
||||||
|
InstanceCLI.prototype.do_disable_firewall = require('./do_disable_firewall');
|
||||||
|
|
||||||
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');
|
||||||
|
@ -769,6 +769,72 @@ TritonApi.prototype.getInstance = function getInstance(opts, cb) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// ---- instance firewall
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable the firewall on an instance.
|
||||||
|
*
|
||||||
|
* @param {Object} opts
|
||||||
|
* - {String} id: The instance ID, or short ID. Required.
|
||||||
|
* @param {Function} callback `function (err, null, res)`
|
||||||
|
*/
|
||||||
|
TritonApi.prototype.enableInstanceFirewall =
|
||||||
|
function enableInstanceFirewall(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: [
|
||||||
|
_stepInstId,
|
||||||
|
|
||||||
|
function enableFirewall(arg, next) {
|
||||||
|
self.cloudapi.enableMachineFirewall(arg.instId,
|
||||||
|
function (err, _, _res) {
|
||||||
|
res = _res;
|
||||||
|
res.instId = arg.instId; // gross hack, in case caller needs it
|
||||||
|
next(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
]}, function (err) {
|
||||||
|
cb(err, null, res);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disable the firewall on an instance.
|
||||||
|
*
|
||||||
|
* @param {Object} opts
|
||||||
|
* - {String} id: The instance ID, or short ID. Required.
|
||||||
|
* @param {Function} callback `function (err, null, res)`
|
||||||
|
*/
|
||||||
|
TritonApi.prototype.disableInstanceFirewall =
|
||||||
|
function disableInstanceFirewall(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: [
|
||||||
|
_stepInstId,
|
||||||
|
|
||||||
|
function disableFirewall(arg, next) {
|
||||||
|
self.cloudapi.disableMachineFirewall(arg.instId,
|
||||||
|
function (err, _, _res) {
|
||||||
|
res = _res;
|
||||||
|
res.instId = arg.instId; // gross hack, in case caller needs it
|
||||||
|
next(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
]}, function (err) {
|
||||||
|
cb(err, null, res);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// ---- instance snapshots
|
// ---- instance snapshots
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -248,6 +248,48 @@ test('triton fwrule', OPTS, function (tt) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
tt.test(' triton instance enable-firewall', function (t) {
|
||||||
|
var cmd = 'instance enable-firewall ' + INST + ' -fw';
|
||||||
|
h.triton(cmd, function (err, stdout, stderr) {
|
||||||
|
if (h.ifErr(t, err, 'triton instance enable-firewall'))
|
||||||
|
return t.end();
|
||||||
|
|
||||||
|
t.ok(stdout.match('Enabled firewall for instance "' + INST + '"'),
|
||||||
|
'firewall enabled');
|
||||||
|
|
||||||
|
h.triton('instance get -j ' + INST, function (err2, stdout2) {
|
||||||
|
if (h.ifErr(t, err2, 'triton instance get'))
|
||||||
|
return t.end();
|
||||||
|
|
||||||
|
var inst = JSON.parse(stdout2);
|
||||||
|
t.equal(inst.firewall_enabled, true);
|
||||||
|
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
tt.test(' triton instance disable-firewall', function (t) {
|
||||||
|
var cmd = 'instance disable-firewall ' + INST + ' -fw';
|
||||||
|
h.triton(cmd, function (err, stdout, stderr) {
|
||||||
|
if (h.ifErr(t, err, 'triton instance disable-firewall'))
|
||||||
|
return t.end();
|
||||||
|
|
||||||
|
t.ok(stdout.match('Disabled firewall for instance "' + INST + '"'),
|
||||||
|
'firewall disabled');
|
||||||
|
|
||||||
|
h.triton('instance get -j ' + INST, function (err2, stdout2) {
|
||||||
|
if (h.ifErr(t, err2, 'triton instance get'))
|
||||||
|
return t.end();
|
||||||
|
|
||||||
|
var inst = JSON.parse(stdout2);
|
||||||
|
t.equal(inst.firewall_enabled, false);
|
||||||
|
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Use a timeout, because '-w' on delete doesn't have a way to know if the
|
* 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.
|
* attempt failed or if it is just taking a really long time.
|
||||||
|
@ -41,6 +41,8 @@ var subs = [
|
|||||||
['instance stop', 'stop'],
|
['instance stop', 'stop'],
|
||||||
['instance reboot', 'reboot'],
|
['instance reboot', 'reboot'],
|
||||||
['instance delete', 'instance rm', 'delete', 'rm'],
|
['instance delete', 'instance rm', 'delete', 'rm'],
|
||||||
|
['instance enable-firewall'],
|
||||||
|
['instance disable-firewall'],
|
||||||
['instance wait'],
|
['instance wait'],
|
||||||
['instance audit'],
|
['instance audit'],
|
||||||
['instance fwrules'],
|
['instance fwrules'],
|
||||||
|
Reference in New Issue
Block a user