TRITON-401 Add support for fabric vlans and networks to node-triton
Reviewed by: Trent Mick <trent.mick@joyent.com> Reviewed by: Julien Gilli <julien.gilli@joyent.com> Reviewed by: Pedro P. Candel <pedro@joyent.com> Approved by: Pedro P. Candel <pedro@joyent.com>
This commit is contained in:
parent
f100c4dbb5
commit
0bc11c1e33
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,3 +3,4 @@
|
|||||||
/test/*.json
|
/test/*.json
|
||||||
/npm-debug.log
|
/npm-debug.log
|
||||||
/triton-*.tgz
|
/triton-*.tgz
|
||||||
|
*.swp
|
||||||
|
@ -6,6 +6,8 @@ Known issues:
|
|||||||
|
|
||||||
## not yet released
|
## not yet released
|
||||||
|
|
||||||
|
- [TRITON-401] Add `triton network` and `triton vlan` commands, for
|
||||||
|
creating/changing/removing network fabrics and VLANs.
|
||||||
- [TRITON-524] Add `triton inst get --credentials ...` option to match
|
- [TRITON-524] Add `triton inst get --credentials ...` option to match
|
||||||
`triton inst list --credentials ...` for including generated credentials
|
`triton inst list --credentials ...` for including generated credentials
|
||||||
in instance metadata.
|
in instance metadata.
|
||||||
|
@ -210,6 +210,7 @@ function CLI() {
|
|||||||
'package',
|
'package',
|
||||||
'network',
|
'network',
|
||||||
'fwrule',
|
'fwrule',
|
||||||
|
'vlan',
|
||||||
{ group: 'Other Commands' },
|
{ group: 'Other Commands' },
|
||||||
'info',
|
'info',
|
||||||
'account',
|
'account',
|
||||||
@ -705,6 +706,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');
|
||||||
|
|
||||||
|
// VLANs
|
||||||
|
CLI.prototype.do_vlan = require('./do_vlan');
|
||||||
|
|
||||||
// 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');
|
||||||
|
264
lib/cloudapi2.js
264
lib/cloudapi2.js
@ -357,6 +357,48 @@ CloudApi.prototype.ping = function ping(opts, cb) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// ---- config
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get config object for the current user.
|
||||||
|
*
|
||||||
|
* @param {Object} opts
|
||||||
|
* @param {Function} cb of the form `function (err, config, res)`
|
||||||
|
*/
|
||||||
|
CloudApi.prototype.getConfig = function getConfig(opts, cb) {
|
||||||
|
assert.object(opts, 'opts');
|
||||||
|
assert.func(cb, 'cb');
|
||||||
|
|
||||||
|
var endpoint = this._path(format('/%s/config', this.account));
|
||||||
|
this._request(endpoint, function (err, req, res, body) {
|
||||||
|
cb(err, body, res);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set config object for the current user.
|
||||||
|
*
|
||||||
|
* @param {Object} opts
|
||||||
|
* - {String} default_network: network fabric docker containers are
|
||||||
|
* provisioned on. Optional.
|
||||||
|
* @param {Function} cb of the form `function (err, config, res)`
|
||||||
|
*/
|
||||||
|
CloudApi.prototype.updateConfig = function updateConfig(opts, cb) {
|
||||||
|
assert.object(opts, 'opts');
|
||||||
|
assert.optionalUuid(opts.default_network, 'opts.default_network');
|
||||||
|
assert.func(cb, 'cb');
|
||||||
|
|
||||||
|
this._request({
|
||||||
|
method: 'PUT',
|
||||||
|
path: format('/%s/config', this.account),
|
||||||
|
data: opts
|
||||||
|
}, function (err, req, res, body) {
|
||||||
|
cb(err, body, res);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// ---- networks
|
// ---- networks
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -458,6 +500,228 @@ CloudApi.prototype.UPDATE_NETWORK_IP_FIELDS = {
|
|||||||
reserved: 'boolean'
|
reserved: 'boolean'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// --- Fabric VLANs
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a network on a fabric (specifically: a fabric VLAN).
|
||||||
|
*
|
||||||
|
* @param {Object} options object containing:
|
||||||
|
* - {Integer} vlan_id (required) VLAN's id, between 0-4095.
|
||||||
|
* - {String} name (required) A name to identify the network.
|
||||||
|
* - {String} subnet (required) CIDR description of the network.
|
||||||
|
* - {String} provision_start_ip (required) First assignable IP addr.
|
||||||
|
* - {String} provision_end_ip (required) Last assignable IP addr.
|
||||||
|
* - {String} gateway (optional) Gateway IP address.
|
||||||
|
* - {String} resolvers (optional) Static routes for hosts on network.
|
||||||
|
* - {String} description (optional)
|
||||||
|
* - {Boolean} internet_nat (optional) Whether to provision an Internet
|
||||||
|
* NAT on the gateway address (default: true).
|
||||||
|
* @param {Function} callback of the form f(err, vlan, res).
|
||||||
|
*/
|
||||||
|
CloudApi.prototype.createFabricNetwork =
|
||||||
|
function createFabricNetwork(opts, cb) {
|
||||||
|
assert.object(opts, 'opts');
|
||||||
|
assert.number(opts.vlan_id, 'opts.vlan_id');
|
||||||
|
assert.string(opts.name, 'opts.name');
|
||||||
|
assert.string(opts.subnet, 'opts.subnet');
|
||||||
|
assert.string(opts.provision_start_ip, 'opts.provision_start_ip');
|
||||||
|
assert.string(opts.provision_end_ip, 'opts.provision_end_ip');
|
||||||
|
assert.optionalString(opts.gateway, 'opts.gateway');
|
||||||
|
assert.optionalString(opts.resolvers, 'opts.resolvers');
|
||||||
|
assert.optionalString(opts.routes, 'opts.routes');
|
||||||
|
assert.optionalBool(opts.internet_nat, 'opts.internet_nat');
|
||||||
|
|
||||||
|
var data = common.objCopy(opts);
|
||||||
|
var vlanId = data.vlan_id;
|
||||||
|
delete data.vlan_id;
|
||||||
|
|
||||||
|
this._request({
|
||||||
|
method: 'POST',
|
||||||
|
path: format('/%s/fabrics/default/vlans/%d/networks', this.account,
|
||||||
|
vlanId),
|
||||||
|
data: data
|
||||||
|
}, function reqCb(err, req, res, body) {
|
||||||
|
cb(err, body, res);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lists all networks on a VLAN.
|
||||||
|
*
|
||||||
|
* Returns an array of objects.
|
||||||
|
*
|
||||||
|
* @param {Object} options object containing:
|
||||||
|
* - {Integer} vlan_id (required) VLAN's id, between 0-4095.
|
||||||
|
* @param {Function} callback of the form f(err, networks, res).
|
||||||
|
*/
|
||||||
|
CloudApi.prototype.listFabricNetworks =
|
||||||
|
function listFabricNetworks(opts, cb) {
|
||||||
|
assert.object(opts, 'opts');
|
||||||
|
assert.number(opts.vlan_id, 'opts.vlan_id');
|
||||||
|
assert.func(cb, 'cb');
|
||||||
|
|
||||||
|
var endpoint = format('/%s/fabrics/default/vlans/%d/networks',
|
||||||
|
this.account, opts.vlan_id);
|
||||||
|
this._passThrough(endpoint, opts, cb);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a fabric network
|
||||||
|
*
|
||||||
|
* @param {Object} opts (object)
|
||||||
|
* - {String} id: The network id. Required.
|
||||||
|
* - {Integer} vlan_id: The VLAN id. Required.
|
||||||
|
* @param {Function} cb of the form `function (err, res)`
|
||||||
|
*/
|
||||||
|
CloudApi.prototype.deleteFabricNetwork =
|
||||||
|
function deleteFabricNetwork(opts, cb) {
|
||||||
|
assert.object(opts, 'opts');
|
||||||
|
assert.uuid(opts.id, 'opts.id');
|
||||||
|
assert.number(opts.vlan_id, 'opts.vlan_id');
|
||||||
|
assert.func(cb, 'cb');
|
||||||
|
|
||||||
|
this._request({
|
||||||
|
method: 'DELETE',
|
||||||
|
path: format('/%s/fabrics/default/vlans/%d/networks/%s', this.account,
|
||||||
|
opts.vlan_id, opts.id)
|
||||||
|
}, function (err, req, res) {
|
||||||
|
cb(err, res);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a VLAN on a fabric.
|
||||||
|
*
|
||||||
|
* @param {Object} options object containing:
|
||||||
|
* - {Integer} vlan_id (required) VLAN's id, between 0-4095.
|
||||||
|
* - {String} name (required) A name to identify the VLAN.
|
||||||
|
* - {String} description (optional)
|
||||||
|
* @param {Function} callback of the form f(err, vlan, res).
|
||||||
|
*/
|
||||||
|
CloudApi.prototype.createFabricVlan =
|
||||||
|
function createFabricVlan(opts, cb) {
|
||||||
|
assert.object(opts, 'opts');
|
||||||
|
assert.number(opts.vlan_id, 'opts.vlan_id');
|
||||||
|
assert.string(opts.name, 'opts.name');
|
||||||
|
assert.optionalString(opts.description, 'opts.description');
|
||||||
|
|
||||||
|
var data = {
|
||||||
|
vlan_id: opts.vlan_id
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.keys(this.UPDATE_VLAN_FIELDS).forEach(function (attr) {
|
||||||
|
if (opts[attr] !== undefined)
|
||||||
|
data[attr] = opts[attr];
|
||||||
|
});
|
||||||
|
|
||||||
|
this._request({
|
||||||
|
method: 'POST',
|
||||||
|
path: format('/%s/fabrics/default/vlans', this.account),
|
||||||
|
data: data
|
||||||
|
}, function reqCb(err, req, res, body) {
|
||||||
|
cb(err, body, res);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lists all the VLANs.
|
||||||
|
*
|
||||||
|
* Returns an array of objects.
|
||||||
|
*
|
||||||
|
* @param opts {Object} Options
|
||||||
|
* @param {Function} callback of the form f(err, vlans, res).
|
||||||
|
*/
|
||||||
|
CloudApi.prototype.listFabricVlans =
|
||||||
|
function listFabricVlans(opts, cb) {
|
||||||
|
assert.object(opts, 'opts');
|
||||||
|
assert.func(cb, 'cb');
|
||||||
|
|
||||||
|
var endpoint = format('/%s/fabrics/default/vlans', this.account);
|
||||||
|
this._passThrough(endpoint, opts, cb);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a VLAN.
|
||||||
|
*
|
||||||
|
* @param {Integer} id: The VLAN id.
|
||||||
|
* @param {Function} callback of the form `function (err, vlan, res)`
|
||||||
|
*/
|
||||||
|
CloudApi.prototype.getFabricVlan =
|
||||||
|
function getFabricVlan(opts, cb) {
|
||||||
|
assert.object(opts, 'opts');
|
||||||
|
assert.number(opts.vlan_id, 'opts.vlan_id');
|
||||||
|
assert.func(cb, 'cb');
|
||||||
|
|
||||||
|
var endpoint = format('/%s/fabrics/default/vlans/%d', this.account,
|
||||||
|
opts.vlan_id);
|
||||||
|
this._request(endpoint, function (err, req, res, body) {
|
||||||
|
cb(err, body, res);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// <updatable account field> -> <expected typeof>
|
||||||
|
CloudApi.prototype.UPDATE_VLAN_FIELDS = {
|
||||||
|
name: 'string',
|
||||||
|
description: 'string'
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates a VLAN.
|
||||||
|
*
|
||||||
|
* @param {Object} opts object containing:
|
||||||
|
* - {Integer} id: The VLAN id. Required.
|
||||||
|
* - {String} name: The VLAN name. Optional.
|
||||||
|
* - {String} description: Description of the VLAN. Optional.
|
||||||
|
* @param {Function} callback of the form `function (err, vlan, res)`
|
||||||
|
*/
|
||||||
|
CloudApi.prototype.updateFabricVlan =
|
||||||
|
function updateFabricVlan(opts, cb) {
|
||||||
|
assert.object(opts, 'opts');
|
||||||
|
assert.number(opts.vlan_id, 'opts.vlan_id');
|
||||||
|
assert.optionalString(opts.rule, 'opts.name');
|
||||||
|
assert.optionalString(opts.description, 'opts.description');
|
||||||
|
assert.func(cb, 'cb');
|
||||||
|
|
||||||
|
var data = {};
|
||||||
|
Object.keys(this.UPDATE_VLAN_FIELDS).forEach(function (attr) {
|
||||||
|
if (opts[attr] !== undefined)
|
||||||
|
data[attr] = opts[attr];
|
||||||
|
});
|
||||||
|
|
||||||
|
var vlanId = opts.vlan_id;
|
||||||
|
|
||||||
|
this._request({
|
||||||
|
method: 'POST',
|
||||||
|
path: format('/%s/fabrics/default/vlans/%d', this.account, vlanId),
|
||||||
|
data: data
|
||||||
|
}, function onReq(err, req, res, body) {
|
||||||
|
cb(err, body, res);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a VLAN.
|
||||||
|
*
|
||||||
|
* @param {Object} opts (object)
|
||||||
|
* - {Integer} vlan_id: The vlan id. Required.
|
||||||
|
* @param {Function} cb of the form `function (err, res)`
|
||||||
|
*/
|
||||||
|
CloudApi.prototype.deleteFabricVlan =
|
||||||
|
function deleteFabricVlan(opts, cb) {
|
||||||
|
assert.object(opts, 'opts');
|
||||||
|
assert.number(opts.vlan_id, 'opts.vlan_id');
|
||||||
|
assert.func(cb, 'cb');
|
||||||
|
|
||||||
|
this._request({
|
||||||
|
method: 'DELETE',
|
||||||
|
path: format('/%s/fabrics/default/vlans/%d', this.account, opts.vlan_id)
|
||||||
|
}, function onReq(err, req, res) {
|
||||||
|
cb(err, res);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// ---- datacenters
|
// ---- datacenters
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
187
lib/do_network/do_create.js
Normal file
187
lib/do_network/do_create.js
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
/*
|
||||||
|
* 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 2018 Joyent, Inc.
|
||||||
|
*
|
||||||
|
* `triton network create ...`
|
||||||
|
*/
|
||||||
|
|
||||||
|
var assert = require('assert-plus');
|
||||||
|
var format = require('util').format;
|
||||||
|
var jsprim = require('jsprim');
|
||||||
|
|
||||||
|
var common = require('../common');
|
||||||
|
var errors = require('../errors');
|
||||||
|
|
||||||
|
|
||||||
|
var OPTIONAL_OPTS = ['description', 'gateway', 'resolvers', 'routes'];
|
||||||
|
|
||||||
|
|
||||||
|
function do_create(subcmd, opts, args, cb) {
|
||||||
|
assert.optionalString(opts.name, 'opts.name');
|
||||||
|
assert.optionalString(opts.subnet, 'opts.subnet');
|
||||||
|
assert.optionalString(opts.start_ip, 'opts.start_ip');
|
||||||
|
assert.optionalString(opts.end_ip, 'opts.end_ip');
|
||||||
|
assert.optionalString(opts.description, 'opts.description');
|
||||||
|
assert.optionalString(opts.gateway, 'opts.gateway');
|
||||||
|
assert.optionalString(opts.resolvers, 'opts.resolvers');
|
||||||
|
assert.optionalString(opts.routes, 'opts.routes');
|
||||||
|
assert.optionalBool(opts.no_nat, 'opts.no_nat');
|
||||||
|
assert.optionalBool(opts.json, 'opts.json');
|
||||||
|
assert.optionalBool(opts.help, 'opts.help');
|
||||||
|
assert.func(cb, 'cb');
|
||||||
|
|
||||||
|
if (opts.help) {
|
||||||
|
this.do_help('help', {}, [subcmd], cb);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (args.length === 0) {
|
||||||
|
cb(new errors.UsageError('missing VLAN argument'));
|
||||||
|
return;
|
||||||
|
} else if (args.length > 1) {
|
||||||
|
cb(new errors.UsageError('incorrect number of arguments'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var vlanId = jsprim.parseInteger(args[0], { allowSign: false });
|
||||||
|
if (typeof (vlanId) !== 'number') {
|
||||||
|
cb(new errors.UsageError('VLAN must be an integer'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var createOpts = {
|
||||||
|
vlan_id: vlanId,
|
||||||
|
name: opts.name,
|
||||||
|
subnet: opts.subnet,
|
||||||
|
provision_start_ip: opts.start_ip,
|
||||||
|
provision_end_ip: opts.end_ip
|
||||||
|
};
|
||||||
|
|
||||||
|
if (opts.no_nat) {
|
||||||
|
createOpts.internet_nat = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
OPTIONAL_OPTS.forEach(function (attr) {
|
||||||
|
if (opts[attr]) {
|
||||||
|
createOpts[attr] = opts[attr];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var cli = this.top;
|
||||||
|
|
||||||
|
common.cliSetupTritonApi({cli: cli}, function onSetup(setupErr) {
|
||||||
|
if (setupErr) {
|
||||||
|
cb(setupErr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var cloudapi = cli.tritonapi.cloudapi;
|
||||||
|
|
||||||
|
cloudapi.createFabricNetwork(createOpts, function onCreate(err, net) {
|
||||||
|
if (err) {
|
||||||
|
cb(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts.json) {
|
||||||
|
console.log(JSON.stringify(net));
|
||||||
|
} else {
|
||||||
|
console.log('Created network %s (%s)', net.name, net.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
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: 'NAME',
|
||||||
|
help: 'Name of the NETWORK.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
names: ['description', 'D'],
|
||||||
|
type: 'string',
|
||||||
|
helpArg: 'DESC',
|
||||||
|
help: 'Description of the NETWORK.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
names: ['subnet'],
|
||||||
|
type: 'string',
|
||||||
|
helpArg: 'SUBNET',
|
||||||
|
help: 'A CIDR string describing the NETWORK.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
names: ['start_ip'],
|
||||||
|
type: 'string',
|
||||||
|
helpArg: 'START_IP',
|
||||||
|
help: 'First assignable IP address on NETWORK.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
names: ['end_ip'],
|
||||||
|
type: 'string',
|
||||||
|
helpArg: 'END_IP',
|
||||||
|
help: 'Last assignable IP address on NETWORK.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
names: ['gateway'],
|
||||||
|
type: 'string',
|
||||||
|
helpArg: 'GATEWAY',
|
||||||
|
help: 'Gateway IP address.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
names: ['resolvers'],
|
||||||
|
type: 'string',
|
||||||
|
helpArg: 'RESOLVERS',
|
||||||
|
help: 'Resolver IP addresses.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
names: ['routes'],
|
||||||
|
type: 'string',
|
||||||
|
helpArg: 'ROUTES',
|
||||||
|
help: 'Static routes for hosts on NETWORK.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
names: ['no_nat'],
|
||||||
|
type: 'bool',
|
||||||
|
helpArg: 'NO_NAT',
|
||||||
|
help: 'Disable creation of an Internet NAT zone on GATEWAY.'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
do_create.synopses = ['{{name}} {{cmd}} [OPTIONS] VLAN'];
|
||||||
|
|
||||||
|
do_create.help = [
|
||||||
|
'Create a network on a VLAN.',
|
||||||
|
'',
|
||||||
|
'{{usage}}',
|
||||||
|
'',
|
||||||
|
'{{options}}',
|
||||||
|
'',
|
||||||
|
'Example:',
|
||||||
|
' triton network create -n accounting --subnet=192.168.0.0/24',
|
||||||
|
' --start_ip=192.168.0.1 --end_ip=192.168.0.254 2'
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
do_create.helpOpts = {
|
||||||
|
helpCol: 25
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = do_create;
|
85
lib/do_network/do_delete.js
Normal file
85
lib/do_network/do_delete.js
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* 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 2017 Joyent, Inc.
|
||||||
|
*
|
||||||
|
* `triton network delete ...`
|
||||||
|
*/
|
||||||
|
|
||||||
|
var assert = require('assert-plus');
|
||||||
|
var format = require('util').format;
|
||||||
|
var vasync = require('vasync');
|
||||||
|
|
||||||
|
var common = require('../common');
|
||||||
|
var errors = require('../errors');
|
||||||
|
|
||||||
|
|
||||||
|
function do_delete(subcmd, opts, args, cb) {
|
||||||
|
assert.func(cb, 'cb');
|
||||||
|
|
||||||
|
if (opts.help) {
|
||||||
|
this.do_help('help', {}, [subcmd], cb);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.length < 1) {
|
||||||
|
cb(new errors.UsageError('missing NETWORK argument(s)'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var cli = this.top;
|
||||||
|
var networks = args;
|
||||||
|
|
||||||
|
common.cliSetupTritonApi({cli: cli}, function onSetup(setupErr) {
|
||||||
|
if (setupErr) {
|
||||||
|
cb(setupErr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
vasync.forEachParallel({
|
||||||
|
inputs: networks,
|
||||||
|
func: function deleteOne(id, next) {
|
||||||
|
cli.tritonapi.deleteFabricNetwork({ id: id },
|
||||||
|
function onDelete(err) {
|
||||||
|
if (err) {
|
||||||
|
next(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Deleted network %s', id);
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, cb);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
do_delete.options = [
|
||||||
|
{
|
||||||
|
names: ['help', 'h'],
|
||||||
|
type: 'bool',
|
||||||
|
help: 'Show this help.'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
do_delete.synopses = ['{{name}} {{cmd}} NETWORK [NETWORK ...]'];
|
||||||
|
|
||||||
|
do_delete.help = [
|
||||||
|
'Remove a fabric network.',
|
||||||
|
'',
|
||||||
|
'{{usage}}',
|
||||||
|
'',
|
||||||
|
'{{options}}',
|
||||||
|
'Where NETWORK is a network id (full UUID), name, or short id.'
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
do_delete.aliases = ['rm'];
|
||||||
|
|
||||||
|
do_delete.completionArgtypes = ['tritonnetwork'];
|
||||||
|
|
||||||
|
module.exports = do_delete;
|
78
lib/do_network/do_get_default.js
Normal file
78
lib/do_network/do_get_default.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 2017 Joyent, Inc.
|
||||||
|
*
|
||||||
|
* `triton network get-default ...`
|
||||||
|
*/
|
||||||
|
|
||||||
|
var assert = require('assert-plus');
|
||||||
|
var vasync = require('vasync');
|
||||||
|
|
||||||
|
var common = require('../common');
|
||||||
|
var errors = require('../errors');
|
||||||
|
|
||||||
|
|
||||||
|
function do_get_default(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;
|
||||||
|
|
||||||
|
common.cliSetupTritonApi({cli: cli}, function onSetup(setupErr) {
|
||||||
|
if (setupErr) {
|
||||||
|
cb(setupErr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cli.tritonapi.cloudapi.getConfig({}, function getConf(err, conf) {
|
||||||
|
if (err) {
|
||||||
|
cb(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var defaultNetwork = conf.default_network;
|
||||||
|
|
||||||
|
if (!defaultNetwork) {
|
||||||
|
cb('default network not found');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cli.handlerFromSubcmd('network').dispatch({
|
||||||
|
subcmd: 'get',
|
||||||
|
opts: opts,
|
||||||
|
args: [defaultNetwork]
|
||||||
|
}, cb);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
do_get_default.options = require('./do_get').options;
|
||||||
|
|
||||||
|
do_get_default.synopses = ['{{name}} {{cmd}}'];
|
||||||
|
|
||||||
|
do_get_default.help = [
|
||||||
|
'Get default network.',
|
||||||
|
'',
|
||||||
|
'{{usage}}',
|
||||||
|
'',
|
||||||
|
'{{options}}'
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
do_get_default.completionArgtypes = ['tritonnetwork'];
|
||||||
|
|
||||||
|
module.exports = do_get_default;
|
@ -66,14 +66,23 @@ function do_list(subcmd, opts, args, callback) {
|
|||||||
common.cliSetupTritonApi,
|
common.cliSetupTritonApi,
|
||||||
|
|
||||||
function searchNetworks(arg, next) {
|
function searchNetworks(arg, next) {
|
||||||
self.top.tritonapi.cloudapi.listNetworks(function (err, networks) {
|
// since this command is also used by do_vlan/do_networks.js
|
||||||
|
if (opts.vlan_id) {
|
||||||
|
self.top.tritonapi.listFabricNetworks({
|
||||||
|
vlan_id: opts.vlan_id
|
||||||
|
}, listedNetworks);
|
||||||
|
} else {
|
||||||
|
self.top.tritonapi.cloudapi.listNetworks({}, listedNetworks);
|
||||||
|
}
|
||||||
|
|
||||||
|
function listedNetworks(err, networks) {
|
||||||
if (err) {
|
if (err) {
|
||||||
next(err);
|
next(err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
arg.networks = networks;
|
arg.networks = networks;
|
||||||
next();
|
next();
|
||||||
});
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
function filterNetworks(arg, next) {
|
function filterNetworks(arg, next) {
|
||||||
|
92
lib/do_network/do_set_default.js
Normal file
92
lib/do_network/do_set_default.js
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
* 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 2017 Joyent, Inc.
|
||||||
|
*
|
||||||
|
* `triton network set-default ...`
|
||||||
|
*/
|
||||||
|
|
||||||
|
var assert = require('assert-plus');
|
||||||
|
var vasync = require('vasync');
|
||||||
|
|
||||||
|
var common = require('../common');
|
||||||
|
var errors = require('../errors');
|
||||||
|
|
||||||
|
|
||||||
|
function do_set_default(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 NETWORK argument'));
|
||||||
|
return;
|
||||||
|
} else if (args.length > 1) {
|
||||||
|
cb(new errors.UsageError('incorrect number of arguments'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var cli = this.top;
|
||||||
|
|
||||||
|
common.cliSetupTritonApi({cli: cli}, function onSetup(setupErr) {
|
||||||
|
if (setupErr) {
|
||||||
|
cb(setupErr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cli.tritonapi.getNetwork(args[0], function onNetwork(err, net) {
|
||||||
|
if (err) {
|
||||||
|
cb(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var params = {
|
||||||
|
default_network: net.id
|
||||||
|
};
|
||||||
|
|
||||||
|
var cloudapi = cli.tritonapi.cloudapi;
|
||||||
|
|
||||||
|
cloudapi.updateConfig(params, function onUpdate(err2) {
|
||||||
|
if (err2) {
|
||||||
|
cb(err2);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Set network %s (%s) as default.', net.name,
|
||||||
|
net.id);
|
||||||
|
cb();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
do_set_default.options = [
|
||||||
|
{
|
||||||
|
names: ['help', 'h'],
|
||||||
|
type: 'bool',
|
||||||
|
help: 'Show this help.'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
do_set_default.synopses = ['{{name}} {{cmd}} NETWORK'];
|
||||||
|
|
||||||
|
do_set_default.help = [
|
||||||
|
'Set default network.',
|
||||||
|
'',
|
||||||
|
'{{usage}}',
|
||||||
|
'',
|
||||||
|
'{{options}}',
|
||||||
|
'Where NETWORK is a network id (full UUID), name, or short id.'
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
do_set_default.completionArgtypes = ['tritonnetwork'];
|
||||||
|
|
||||||
|
module.exports = do_set_default;
|
@ -33,7 +33,11 @@ function NetworkCLI(top) {
|
|||||||
'help',
|
'help',
|
||||||
'list',
|
'list',
|
||||||
'get',
|
'get',
|
||||||
'ip'
|
'ip',
|
||||||
|
'create',
|
||||||
|
'delete',
|
||||||
|
'get-default',
|
||||||
|
'set-default'
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -47,6 +51,10 @@ NetworkCLI.prototype.init = function init(opts, args, cb) {
|
|||||||
NetworkCLI.prototype.do_list = require('./do_list');
|
NetworkCLI.prototype.do_list = require('./do_list');
|
||||||
NetworkCLI.prototype.do_get = require('./do_get');
|
NetworkCLI.prototype.do_get = require('./do_get');
|
||||||
NetworkCLI.prototype.do_ip = require('./do_ip');
|
NetworkCLI.prototype.do_ip = require('./do_ip');
|
||||||
|
NetworkCLI.prototype.do_create = require('./do_create');
|
||||||
|
NetworkCLI.prototype.do_delete = require('./do_delete');
|
||||||
|
NetworkCLI.prototype.do_get_default = require('./do_get_default');
|
||||||
|
NetworkCLI.prototype.do_set_default = require('./do_set_default');
|
||||||
|
|
||||||
|
|
||||||
module.exports = NetworkCLI;
|
module.exports = NetworkCLI;
|
||||||
|
123
lib/do_vlan/do_create.js
Normal file
123
lib/do_vlan/do_create.js
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
/*
|
||||||
|
* 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 2017 Joyent, Inc.
|
||||||
|
*
|
||||||
|
* `triton vlan 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.name, 'opts.name');
|
||||||
|
assert.optionalString(opts.description, 'opts.description');
|
||||||
|
assert.optionalBool(opts.json, 'opts.json');
|
||||||
|
assert.optionalBool(opts.help, 'opts.help');
|
||||||
|
assert.func(cb, 'cb');
|
||||||
|
|
||||||
|
if (opts.help) {
|
||||||
|
this.do_help('help', {}, [subcmd], cb);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (args.length === 0) {
|
||||||
|
cb(new errors.UsageError('missing VLAN argument'));
|
||||||
|
return;
|
||||||
|
} else if (args.length > 1) {
|
||||||
|
cb(new errors.UsageError('incorrect number of arguments'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var createOpts = {
|
||||||
|
vlan_id: +args[0]
|
||||||
|
};
|
||||||
|
if (opts.name) {
|
||||||
|
createOpts.name = opts.name;
|
||||||
|
}
|
||||||
|
if (opts.description) {
|
||||||
|
createOpts.description = opts.description;
|
||||||
|
}
|
||||||
|
|
||||||
|
var cli = this.top;
|
||||||
|
|
||||||
|
common.cliSetupTritonApi({cli: cli}, function onSetup(setupErr) {
|
||||||
|
if (setupErr) {
|
||||||
|
cb(setupErr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var cloudapi = cli.tritonapi.cloudapi;
|
||||||
|
cloudapi.createFabricVlan(createOpts, function onCreate(err, vlan) {
|
||||||
|
if (err) {
|
||||||
|
cb(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts.json) {
|
||||||
|
console.log(JSON.stringify(vlan));
|
||||||
|
} else {
|
||||||
|
if (vlan.name) {
|
||||||
|
console.log('Created vlan %s (%d)', vlan.name,
|
||||||
|
vlan.vlan_id);
|
||||||
|
} else {
|
||||||
|
console.log('Created vlan %d', vlan.vlan_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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: 'NAME',
|
||||||
|
help: 'Name of the VLAN.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
names: ['description', 'D'],
|
||||||
|
type: 'string',
|
||||||
|
helpArg: 'DESC',
|
||||||
|
help: 'Description of the VLAN.'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
do_create.synopses = ['{{name}} {{cmd}} [OPTIONS] VLAN'];
|
||||||
|
|
||||||
|
do_create.help = [
|
||||||
|
'Create a VLAN.',
|
||||||
|
'',
|
||||||
|
'{{usage}}',
|
||||||
|
'',
|
||||||
|
'{{options}}',
|
||||||
|
'Example:',
|
||||||
|
' triton vlan create -n "dmz" -D "Demilitarized zone" 73'
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
do_create.helpOpts = {
|
||||||
|
helpCol: 25
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = do_create;
|
85
lib/do_vlan/do_delete.js
Normal file
85
lib/do_vlan/do_delete.js
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* 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 2017 Joyent, Inc.
|
||||||
|
*
|
||||||
|
* `triton vlan delete ...`
|
||||||
|
*/
|
||||||
|
|
||||||
|
var assert = require('assert-plus');
|
||||||
|
var format = require('util').format;
|
||||||
|
var vasync = require('vasync');
|
||||||
|
|
||||||
|
var common = require('../common');
|
||||||
|
var errors = require('../errors');
|
||||||
|
|
||||||
|
|
||||||
|
function do_delete(subcmd, opts, args, cb) {
|
||||||
|
assert.func(cb, 'cb');
|
||||||
|
|
||||||
|
if (opts.help) {
|
||||||
|
this.do_help('help', {}, [subcmd], cb);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.length < 1) {
|
||||||
|
cb(new errors.UsageError('missing VLAN argument(s)'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var cli = this.top;
|
||||||
|
var vlanIds = args;
|
||||||
|
|
||||||
|
common.cliSetupTritonApi({cli: cli}, function onSetup(setupErr) {
|
||||||
|
if (setupErr) {
|
||||||
|
cb(setupErr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
vasync.forEachParallel({
|
||||||
|
inputs: vlanIds,
|
||||||
|
func: function deleteOne(id, next) {
|
||||||
|
cli.tritonapi.deleteFabricVlan({ vlan_id: id },
|
||||||
|
function onDelete(err) {
|
||||||
|
if (err) {
|
||||||
|
next(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Deleted vlan %s', id);
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, cb);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
do_delete.options = [
|
||||||
|
{
|
||||||
|
names: ['help', 'h'],
|
||||||
|
type: 'bool',
|
||||||
|
help: 'Show this help.'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
do_delete.synopses = ['{{name}} {{cmd}} VLAN [VLAN ...]'];
|
||||||
|
|
||||||
|
do_delete.help = [
|
||||||
|
'Remove a VLAN.',
|
||||||
|
'',
|
||||||
|
'{{usage}}',
|
||||||
|
'',
|
||||||
|
'{{options}}',
|
||||||
|
'Where VLAN is a VLAN id or name.'
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
do_delete.aliases = ['rm'];
|
||||||
|
|
||||||
|
do_delete.completionArgtypes = ['tritonvlan'];
|
||||||
|
|
||||||
|
module.exports = do_delete;
|
88
lib/do_vlan/do_get.js
Normal file
88
lib/do_vlan/do_get.js
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* 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 2017 Joyent, Inc.
|
||||||
|
*
|
||||||
|
* `triton vlan get ...`
|
||||||
|
*/
|
||||||
|
|
||||||
|
var assert = require('assert-plus');
|
||||||
|
|
||||||
|
var common = require('../common');
|
||||||
|
var errors = require('../errors');
|
||||||
|
|
||||||
|
|
||||||
|
function do_get(subcmd, opts, args, cb) {
|
||||||
|
assert.func(cb, 'cb');
|
||||||
|
|
||||||
|
if (opts.help) {
|
||||||
|
this.do_help('help', {}, [subcmd], cb);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.length === 0) {
|
||||||
|
cb(new errors.UsageError('missing VLAN argument'));
|
||||||
|
return;
|
||||||
|
} else if (args.length > 1) {
|
||||||
|
cb(new errors.UsageError('incorrect number of arguments'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var id = args[0];
|
||||||
|
var cli = this.top;
|
||||||
|
|
||||||
|
common.cliSetupTritonApi({cli: cli}, function onSetup(setupErr) {
|
||||||
|
if (setupErr) {
|
||||||
|
cb(setupErr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cli.tritonapi.getFabricVlan(id, function onGet(err, vlan) {
|
||||||
|
if (err) {
|
||||||
|
cb(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts.json) {
|
||||||
|
console.log(JSON.stringify(vlan));
|
||||||
|
} else {
|
||||||
|
console.log(JSON.stringify(vlan, 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.synopses = ['{{name}} {{cmd}} VLAN'];
|
||||||
|
|
||||||
|
do_get.help = [
|
||||||
|
'Show a specific VLAN.',
|
||||||
|
'',
|
||||||
|
'{{usage}}',
|
||||||
|
'',
|
||||||
|
'{{options}}',
|
||||||
|
'Where VLAN is a VLAN id or name.'
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
do_get.completionArgtypes = ['tritonvlan', 'none'];
|
||||||
|
|
||||||
|
module.exports = do_get;
|
123
lib/do_vlan/do_list.js
Normal file
123
lib/do_vlan/do_list.js
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
/*
|
||||||
|
* 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 2018 Joyent, Inc.
|
||||||
|
*
|
||||||
|
* `triton vlan list ...`
|
||||||
|
*/
|
||||||
|
|
||||||
|
var assert = require('assert-plus');
|
||||||
|
var tabula = require('tabula');
|
||||||
|
|
||||||
|
var common = require('../common');
|
||||||
|
var errors = require('../errors');
|
||||||
|
|
||||||
|
|
||||||
|
var COLUMNS_DEFAULT = 'vlan_id,name,description';
|
||||||
|
var SORT_DEFAULT = 'vlan_id';
|
||||||
|
var VALID_FILTERS = ['vlan_id', 'name', 'description'];
|
||||||
|
|
||||||
|
|
||||||
|
function do_list(subcmd, opts, args, cb) {
|
||||||
|
assert.object(opts, 'opts');
|
||||||
|
assert.array(args, 'args');
|
||||||
|
assert.func(cb, 'cb');
|
||||||
|
|
||||||
|
if (opts.help) {
|
||||||
|
this.do_help('help', {}, [subcmd], cb);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
var filters = common.objFromKeyValueArgs(args, {
|
||||||
|
validKeys: VALID_FILTERS,
|
||||||
|
disableDotted: true
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
cb(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filters.vlan_id !== undefined) {
|
||||||
|
filters.vlan_id = +filters.vlan_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
var cli = this.top;
|
||||||
|
|
||||||
|
common.cliSetupTritonApi({cli: cli}, function onSetup(setupErr) {
|
||||||
|
if (setupErr) {
|
||||||
|
cb(setupErr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var cloudapi = cli.tritonapi.cloudapi;
|
||||||
|
cloudapi.listFabricVlans({}, function onList(err, vlans) {
|
||||||
|
if (err) {
|
||||||
|
cb(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// do filtering
|
||||||
|
Object.keys(filters).forEach(function doFilter(key) {
|
||||||
|
var val = filters[key];
|
||||||
|
vlans = vlans.filter(function (vlan) {
|
||||||
|
return vlan[key] === val;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (opts.json) {
|
||||||
|
common.jsonStream(vlans);
|
||||||
|
} else {
|
||||||
|
var columns = COLUMNS_DEFAULT;
|
||||||
|
|
||||||
|
if (opts.o) {
|
||||||
|
columns = opts.o;
|
||||||
|
}
|
||||||
|
|
||||||
|
columns = columns.split(',');
|
||||||
|
var sort = opts.s.split(',');
|
||||||
|
|
||||||
|
tabula(vlans, {
|
||||||
|
skipHeader: opts.H,
|
||||||
|
columns: columns,
|
||||||
|
sort: sort
|
||||||
|
});
|
||||||
|
}
|
||||||
|
cb();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
do_list.options = [
|
||||||
|
{
|
||||||
|
names: ['help', 'h'],
|
||||||
|
type: 'bool',
|
||||||
|
help: 'Show this help.'
|
||||||
|
}
|
||||||
|
].concat(common.getCliTableOptions({
|
||||||
|
sortDefault: SORT_DEFAULT
|
||||||
|
}));
|
||||||
|
|
||||||
|
do_list.synopses = ['{{name}} {{cmd}} [OPTIONS] [FILTERS]'];
|
||||||
|
|
||||||
|
do_list.help = [
|
||||||
|
'List VLANs.',
|
||||||
|
'',
|
||||||
|
'{{usage}}',
|
||||||
|
'',
|
||||||
|
'Filters:',
|
||||||
|
' FIELD=<integer> Number filter. Supported fields: vlan_id',
|
||||||
|
' FIELD=<string> String filter. Supported fields: name, description',
|
||||||
|
'',
|
||||||
|
'{{options}}',
|
||||||
|
'Filters are applied client-side (i.e. done by the triton command itself).'
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
do_list.aliases = ['ls'];
|
||||||
|
|
||||||
|
module.exports = do_list;
|
52
lib/do_vlan/do_networks.js
Normal file
52
lib/do_vlan/do_networks.js
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2017 Joyent, Inc.
|
||||||
|
*
|
||||||
|
* `triton vlan networks ...`
|
||||||
|
*/
|
||||||
|
|
||||||
|
var errors = require('../errors');
|
||||||
|
|
||||||
|
|
||||||
|
function do_networks(subcmd, opts, args, cb) {
|
||||||
|
if (opts.help) {
|
||||||
|
this.do_help('help', {}, [subcmd], cb);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.length === 0) {
|
||||||
|
cb(new errors.UsageError('missing VLAN argument'));
|
||||||
|
return;
|
||||||
|
} else if (args.length > 1) {
|
||||||
|
cb(new errors.UsageError('incorrect number of arguments'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
opts.vlan_id = args[0];
|
||||||
|
|
||||||
|
this.top.handlerFromSubcmd('network').dispatch({
|
||||||
|
subcmd: 'list',
|
||||||
|
opts: opts,
|
||||||
|
args: []
|
||||||
|
}, cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
do_networks.synopses = ['{{name}} {{cmd}} [OPTIONS] VLAN'];
|
||||||
|
|
||||||
|
do_networks.help = [
|
||||||
|
'Show all networks on a VLAN.',
|
||||||
|
'',
|
||||||
|
'{{usage}}',
|
||||||
|
'',
|
||||||
|
'{{options}}',
|
||||||
|
'Where VLAN is a VLAN id or name.'
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
do_networks.options = require('../do_network/do_list').options;
|
||||||
|
|
||||||
|
module.exports = do_networks;
|
201
lib/do_vlan/do_update.js
Normal file
201
lib/do_vlan/do_update.js
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
/*
|
||||||
|
* 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 2018 Joyent, Inc.
|
||||||
|
*
|
||||||
|
* `triton vlan 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_VLAN_FIELDS
|
||||||
|
= require('../cloudapi2').CloudApi.prototype.UPDATE_VLAN_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 VLAN argument'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var id = args.shift();
|
||||||
|
|
||||||
|
vasync.pipeline({arg: {}, funcs: [
|
||||||
|
function gatherDataArgs(ctx, next) {
|
||||||
|
if (opts.file) {
|
||||||
|
next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
ctx.data = common.objFromKeyValueArgs(args, {
|
||||||
|
disableDotted: true,
|
||||||
|
typeHintFromKey: UPDATE_VLAN_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 vlan 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('error', console.error);
|
||||||
|
|
||||||
|
process.stdin.on('end', function () {
|
||||||
|
try {
|
||||||
|
ctx.data = JSON.parse(stdin);
|
||||||
|
} catch (err) {
|
||||||
|
log.trace({stdin: stdin},
|
||||||
|
'invalid VLAN update JSON on stdin');
|
||||||
|
next(new errors.TritonError(format(
|
||||||
|
'invalid JSON for VLAN update on stdin: %s',
|
||||||
|
err)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
function validateIt(ctx, next) {
|
||||||
|
assert.object(ctx.data, 'ctx.data');
|
||||||
|
|
||||||
|
var keys = Object.keys(ctx.data);
|
||||||
|
|
||||||
|
if (keys.length === 0) {
|
||||||
|
console.log('No fields given for VLAN update');
|
||||||
|
next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < keys.length; i++) {
|
||||||
|
var key = keys[i];
|
||||||
|
var value = ctx.data[key];
|
||||||
|
var type = UPDATE_VLAN_FIELDS[key];
|
||||||
|
if (!type) {
|
||||||
|
next(new errors.UsageError(format('unknown or ' +
|
||||||
|
'unupdateable field: %s (updateable fields are: %s)',
|
||||||
|
key,
|
||||||
|
Object.keys(UPDATE_VLAN_FIELDS).sort().join(', '))));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof (value) !== type) {
|
||||||
|
next(new errors.UsageError(format('field "%s" must be ' +
|
||||||
|
'of type "%s", but got a value of type "%s"', key,
|
||||||
|
type, typeof (value))));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
},
|
||||||
|
|
||||||
|
function updateAway(ctx, next) {
|
||||||
|
var data = ctx.data;
|
||||||
|
data.vlan_id = id;
|
||||||
|
|
||||||
|
tritonapi.updateFabricVlan(data, function onUpdate(err) {
|
||||||
|
if (err) {
|
||||||
|
next(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete data.vlan_id;
|
||||||
|
console.log('Updated vlan %s (fields: %s)', id,
|
||||||
|
Object.keys(data).join(', '));
|
||||||
|
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
]}, cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
do_update.options = [
|
||||||
|
{
|
||||||
|
names: ['help', 'h'],
|
||||||
|
type: 'bool',
|
||||||
|
help: 'Show this help.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
names: ['file', 'f'],
|
||||||
|
type: 'string',
|
||||||
|
helpArg: 'JSON-FILE',
|
||||||
|
help: 'A file holding a JSON file of updates, or "-" to read ' +
|
||||||
|
'JSON from stdin.'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
do_update.synopses = [
|
||||||
|
'{{name}} {{cmd}} VLAN [FIELD=VALUE ...]',
|
||||||
|
'{{name}} {{cmd}} -f JSON-FILE VLAN'
|
||||||
|
];
|
||||||
|
|
||||||
|
do_update.help = [
|
||||||
|
'Update a VLAN.',
|
||||||
|
'',
|
||||||
|
'{{usage}}',
|
||||||
|
'',
|
||||||
|
'{{options}}',
|
||||||
|
|
||||||
|
'Updateable fields:',
|
||||||
|
' ' + Object.keys(UPDATE_VLAN_FIELDS).sort().map(function (f) {
|
||||||
|
return f + ' (' + UPDATE_VLAN_FIELDS[f] + ')';
|
||||||
|
}).join(', '),
|
||||||
|
'',
|
||||||
|
'Where VLAN is a VLAN id or name.'
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
do_update.completionArgtypes = ['tritonvlan', 'tritonupdatevlanfield'];
|
||||||
|
|
||||||
|
module.exports = do_update;
|
55
lib/do_vlan/index.js
Normal file
55
lib/do_vlan/index.js
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* 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 2017 Joyent, Inc.
|
||||||
|
*
|
||||||
|
* `triton vlan ...`
|
||||||
|
*/
|
||||||
|
|
||||||
|
var Cmdln = require('cmdln').Cmdln;
|
||||||
|
var util = require('util');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ---- CLI class
|
||||||
|
|
||||||
|
function VlanCLI(top) {
|
||||||
|
this.top = top;
|
||||||
|
|
||||||
|
Cmdln.call(this, {
|
||||||
|
name: top.name + ' vlan',
|
||||||
|
desc: 'List and manage Triton fabric VLANs.',
|
||||||
|
helpSubcmds: [
|
||||||
|
'help',
|
||||||
|
'list',
|
||||||
|
'get',
|
||||||
|
'create',
|
||||||
|
'update',
|
||||||
|
'delete',
|
||||||
|
{ group: '' },
|
||||||
|
'networks'
|
||||||
|
],
|
||||||
|
helpOpts: {
|
||||||
|
minHelpCol: 23
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
util.inherits(VlanCLI, Cmdln);
|
||||||
|
|
||||||
|
VlanCLI.prototype.init = function init(opts, args, cb) {
|
||||||
|
this.log = this.top.log;
|
||||||
|
Cmdln.prototype.init.apply(this, arguments);
|
||||||
|
};
|
||||||
|
|
||||||
|
VlanCLI.prototype.do_list = require('./do_list');
|
||||||
|
VlanCLI.prototype.do_create = require('./do_create');
|
||||||
|
VlanCLI.prototype.do_get = require('./do_get');
|
||||||
|
VlanCLI.prototype.do_update = require('./do_update');
|
||||||
|
VlanCLI.prototype.do_delete = require('./do_delete');
|
||||||
|
VlanCLI.prototype.do_networks = require('./do_networks');
|
||||||
|
|
||||||
|
module.exports = VlanCLI;
|
264
lib/tritonapi.js
264
lib/tritonapi.js
@ -282,7 +282,9 @@ function _stepFwRuleId(arg, next) {
|
|||||||
* and determines the network id (setting it as `arg.netId`).
|
* and determines the network id (setting it as `arg.netId`).
|
||||||
*/
|
*/
|
||||||
function _stepNetId(arg, next) {
|
function _stepNetId(arg, next) {
|
||||||
|
assert.object(arg, 'arg');
|
||||||
assert.object(arg.client, 'arg.client');
|
assert.object(arg.client, 'arg.client');
|
||||||
|
assert.func(next, 'next');
|
||||||
|
|
||||||
var id = arg.network || arg.id;
|
var id = arg.network || arg.id;
|
||||||
assert.string(id, 'arg.network || arg.id');
|
assert.string(id, 'arg.network || arg.id');
|
||||||
@ -291,7 +293,7 @@ function _stepNetId(arg, next) {
|
|||||||
arg.netId = id;
|
arg.netId = id;
|
||||||
next();
|
next();
|
||||||
} else {
|
} else {
|
||||||
arg.client.getNetwork(id, function (err, net) {
|
arg.client.getNetwork(id, function onGet(err, net) {
|
||||||
if (err) {
|
if (err) {
|
||||||
next(err);
|
next(err);
|
||||||
} else {
|
} else {
|
||||||
@ -302,6 +304,98 @@ function _stepNetId(arg, next) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A function appropriate for `vasync.pipeline` funcs that takes a `arg.id` and
|
||||||
|
* optionally a `arg.vlan_id`, where `arg.id` is a network name, shortid or
|
||||||
|
* uuid, and `arg.vlan_id` is a VLAN's id or name. Sets the network id as
|
||||||
|
* `arg.netId` and the VLAN id as `arg.vlanId`.
|
||||||
|
*/
|
||||||
|
function _stepFabricNetId(arg, next) {
|
||||||
|
assert.object(arg, 'arg');
|
||||||
|
assert.object(arg.client, 'arg.client');
|
||||||
|
assert.string(arg.id, 'arg.id');
|
||||||
|
assert.func(next, 'next');
|
||||||
|
|
||||||
|
var id = arg.id;
|
||||||
|
var vlanId = arg.vlan_id;
|
||||||
|
var vlanIdType = typeof (vlanId);
|
||||||
|
|
||||||
|
if (common.isUUID(id) && vlanIdType === 'number') {
|
||||||
|
arg.netId = id;
|
||||||
|
arg.vlanId = vlanId;
|
||||||
|
|
||||||
|
next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
arg.client.getNetwork(id, function onGetNetwork(err, net) {
|
||||||
|
if (err) {
|
||||||
|
next(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vlanIdType === 'number') {
|
||||||
|
assert.equal(net.vlan_id, vlanId, 'VLAN belongs to network');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vlanIdType === 'number' || vlanIdType === 'undefined') {
|
||||||
|
arg.netId = net.id;
|
||||||
|
arg.vlanId = net.vlan_id;
|
||||||
|
|
||||||
|
next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// at this point the only type left we support are strings
|
||||||
|
assert.string(vlanId, 'arg.vlan_id');
|
||||||
|
|
||||||
|
arg.client.getFabricVlan(vlanId, function onGetFabric(err2, vlan) {
|
||||||
|
if (err2) {
|
||||||
|
next(err2);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.equal(net.vlan_id, vlan.vlan_id, 'VLAN belongs to network');
|
||||||
|
arg.netId = net.id;
|
||||||
|
arg.vlanId = net.vlan_id;
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A function appropriate for `vasync.pipeline` funcs that takes a
|
||||||
|
* `arg.vlan_id`, where that is either a VLAN's id or name. Sets the
|
||||||
|
* VLAN id as `arg.vlanId`.
|
||||||
|
*/
|
||||||
|
function _stepFabricVlanId(arg, next) {
|
||||||
|
assert.object(arg, 'arg');
|
||||||
|
assert.object(arg.client, 'arg.client');
|
||||||
|
assert.ok(typeof (arg.vlan_id) === 'string' ||
|
||||||
|
typeof (arg.vlan_id) === 'number', 'arg.vlan_id');
|
||||||
|
assert.func(next, 'next');
|
||||||
|
|
||||||
|
var vlanId = arg.vlan_id;
|
||||||
|
|
||||||
|
if (typeof (vlanId) === 'number') {
|
||||||
|
arg.vlanId = vlanId;
|
||||||
|
next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
arg.client.getFabricVlan(vlanId, function onGet(err, vlan) {
|
||||||
|
if (err) {
|
||||||
|
next(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
arg.vlanId = vlan.vlan_id;
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//---- TritonApi class
|
//---- TritonApi class
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -934,7 +1028,7 @@ TritonApi.prototype.getNetwork = function getNetwork(name, cb) {
|
|||||||
assert.func(cb, 'cb');
|
assert.func(cb, 'cb');
|
||||||
|
|
||||||
if (common.isUUID(name)) {
|
if (common.isUUID(name)) {
|
||||||
this.cloudapi.getNetwork(name, function (err, net) {
|
this.cloudapi.getNetwork(name, function onGet(err, net) {
|
||||||
if (err) {
|
if (err) {
|
||||||
if (err.restCode === 'ResourceNotFound') {
|
if (err.restCode === 'ResourceNotFound') {
|
||||||
// Wrap with *our* ResourceNotFound for exitStatus=3.
|
// Wrap with *our* ResourceNotFound for exitStatus=3.
|
||||||
@ -947,7 +1041,7 @@ TritonApi.prototype.getNetwork = function getNetwork(name, cb) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.cloudapi.listNetworks(function (err, nets) {
|
this.cloudapi.listNetworks({}, function onList(err, nets) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return cb(err);
|
return cb(err);
|
||||||
}
|
}
|
||||||
@ -984,6 +1078,72 @@ TritonApi.prototype.getNetwork = function getNetwork(name, cb) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List all fabric networks on a VLAN. Takes a network's VLAN ID or name as an
|
||||||
|
* argument.
|
||||||
|
*/
|
||||||
|
TritonApi.prototype.listFabricNetworks =
|
||||||
|
function listFabricNetworks(opts, cb) {
|
||||||
|
assert.object(opts, 'opts');
|
||||||
|
assert.ok(typeof (opts.vlan_id) === 'string' ||
|
||||||
|
typeof (opts.vlan_id) === 'number', 'opts.vlan_id');
|
||||||
|
assert.func(cb, 'cb');
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
var networks;
|
||||||
|
|
||||||
|
vasync.pipeline({
|
||||||
|
arg: {client: self, vlan_id: opts.vlan_id}, funcs: [
|
||||||
|
_stepFabricVlanId,
|
||||||
|
|
||||||
|
function listNetworks(arg, next) {
|
||||||
|
self.cloudapi.listFabricNetworks({
|
||||||
|
vlan_id: arg.vlanId
|
||||||
|
}, function listCb(err, nets) {
|
||||||
|
if (err) {
|
||||||
|
next(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
networks = nets;
|
||||||
|
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
]}, function (err) {
|
||||||
|
cb(err, networks);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a fabric network by ID, exact name, or short ID, in that order.
|
||||||
|
* Can accept a network's VLAN ID or name as an optional argument.
|
||||||
|
*
|
||||||
|
* If the name is ambiguous, then this errors out.
|
||||||
|
*/
|
||||||
|
TritonApi.prototype.deleteFabricNetwork =
|
||||||
|
function deleteFabricNetwork(opts, cb) {
|
||||||
|
assert.object(opts, 'opts');
|
||||||
|
assert.string(opts.id, 'opts.id');
|
||||||
|
assert.func(cb, 'cb');
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
vasync.pipeline({
|
||||||
|
arg: {client: self, id: opts.id, vlan_id: opts.vlan_id},
|
||||||
|
funcs: [
|
||||||
|
_stepFabricNetId,
|
||||||
|
|
||||||
|
function deleteNetwork(arg, next) {
|
||||||
|
self.cloudapi.deleteFabricNetwork({
|
||||||
|
id: arg.netId, vlan_id: arg.vlanId
|
||||||
|
}, next);
|
||||||
|
}
|
||||||
|
]}, cb);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List a network's IPs.
|
* List a network's IPs.
|
||||||
*
|
*
|
||||||
@ -2137,14 +2297,15 @@ function deleteAllInstanceTags(opts, cb) {
|
|||||||
*/
|
*/
|
||||||
TritonApi.prototype.addNic =
|
TritonApi.prototype.addNic =
|
||||||
function addNic(opts, cb) {
|
function addNic(opts, cb) {
|
||||||
|
assert.object(opts, 'opts');
|
||||||
assert.string(opts.id, 'opts.id');
|
assert.string(opts.id, 'opts.id');
|
||||||
assert.ok(opts.network, 'opts.network');
|
assert.ok(opts.network, 'opts.network');
|
||||||
assert.func(cb, 'cb');
|
assert.func(cb, 'cb');
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
|
var nic;
|
||||||
var pipeline = [];
|
var pipeline = [];
|
||||||
var res;
|
var res;
|
||||||
var nic;
|
|
||||||
|
|
||||||
switch (typeof (opts.network)) {
|
switch (typeof (opts.network)) {
|
||||||
case 'string':
|
case 'string':
|
||||||
@ -2198,8 +2359,8 @@ function listNics(opts, cb) {
|
|||||||
assert.func(cb, 'cb');
|
assert.func(cb, 'cb');
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
var res;
|
|
||||||
var nics;
|
var nics;
|
||||||
|
var res;
|
||||||
|
|
||||||
vasync.pipeline({arg: {client: self, id: opts.id}, funcs: [
|
vasync.pipeline({arg: {client: self, id: opts.id}, funcs: [
|
||||||
_stepInstId,
|
_stepInstId,
|
||||||
@ -2207,7 +2368,7 @@ function listNics(opts, cb) {
|
|||||||
function list(arg, next) {
|
function list(arg, next) {
|
||||||
self.cloudapi.listNics({
|
self.cloudapi.listNics({
|
||||||
id: arg.instId
|
id: arg.instId
|
||||||
}, function (err, _nics, _res) {
|
}, function onList(err, _nics, _res) {
|
||||||
res = _res;
|
res = _res;
|
||||||
res.instId = arg.instId; // gross hack, in case caller needs it
|
res.instId = arg.instId; // gross hack, in case caller needs it
|
||||||
nics = _nics;
|
nics = _nics;
|
||||||
@ -2245,7 +2406,7 @@ function getNic(opts, cb) {
|
|||||||
self.cloudapi.getNic({
|
self.cloudapi.getNic({
|
||||||
id: arg.instId,
|
id: arg.instId,
|
||||||
mac: arg.mac
|
mac: arg.mac
|
||||||
}, function (err, _nic, _res) {
|
}, function onGet(err, _nic, _res) {
|
||||||
res = _res;
|
res = _res;
|
||||||
res.instId = arg.instId; // gross hack, in case caller needs it
|
res.instId = arg.instId; // gross hack, in case caller needs it
|
||||||
nic = _nic;
|
nic = _nic;
|
||||||
@ -2283,7 +2444,7 @@ function removeNic(opts, cb) {
|
|||||||
self.cloudapi.removeNic({
|
self.cloudapi.removeNic({
|
||||||
id: arg.instId,
|
id: arg.instId,
|
||||||
mac: arg.mac
|
mac: arg.mac
|
||||||
}, function (err, _res) {
|
}, function onRemove(err, _res) {
|
||||||
res = _res;
|
res = _res;
|
||||||
res.instId = arg.instId; // gross hack, in case caller needs it
|
res.instId = arg.instId; // gross hack, in case caller needs it
|
||||||
next(err);
|
next(err);
|
||||||
@ -2635,6 +2796,93 @@ TritonApi.prototype.deleteFirewallRule = function deleteFirewallRule(opts, cb) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// ---- VLANs
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a VLAN by ID or exact name, in that order.
|
||||||
|
*
|
||||||
|
* If the name is ambiguous, then this errors out.
|
||||||
|
*/
|
||||||
|
TritonApi.prototype.getFabricVlan = function getFabricVlan(name, cb) {
|
||||||
|
assert.ok(typeof (name) === 'string' ||
|
||||||
|
typeof (name) === 'number', 'name');
|
||||||
|
assert.func(cb, 'cb');
|
||||||
|
|
||||||
|
if (+name >= 0 && +name < 4096) {
|
||||||
|
this.cloudapi.getFabricVlan({vlan_id: +name}, function on(err, vlan) {
|
||||||
|
if (err) {
|
||||||
|
if (err.restCode === 'ResourceNotFound') {
|
||||||
|
// Wrap with our own ResourceNotFound for exitStatus=3.
|
||||||
|
err = new errors.ResourceNotFoundError(err,
|
||||||
|
format('vlan with id %s was not found', name));
|
||||||
|
}
|
||||||
|
cb(err);
|
||||||
|
} else {
|
||||||
|
cb(null, vlan);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.cloudapi.listFabricVlans({}, function onList(err, vlans) {
|
||||||
|
if (err) {
|
||||||
|
return cb(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
var nameMatches = [];
|
||||||
|
for (var i = 0; i < vlans.length; i++) {
|
||||||
|
var vlan = vlans[i];
|
||||||
|
if (vlan.name === name) {
|
||||||
|
nameMatches.push(vlan);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nameMatches.length === 1) {
|
||||||
|
cb(null, nameMatches[0]);
|
||||||
|
} else if (nameMatches.length > 1) {
|
||||||
|
cb(new errors.TritonError(format(
|
||||||
|
'vlan name "%s" is ambiguous: matches %d vlans',
|
||||||
|
name, nameMatches.length)));
|
||||||
|
} else {
|
||||||
|
cb(new errors.ResourceNotFoundError(format(
|
||||||
|
'no vlan with name "%s" was found', name)));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a VLAN by ID or exact name, in that order.
|
||||||
|
*
|
||||||
|
* If the name is ambiguous, then this errors out.
|
||||||
|
*/
|
||||||
|
TritonApi.prototype.deleteFabricVlan = function deleteFabricVlan(opts, cb) {
|
||||||
|
assert.object(opts, 'opts');
|
||||||
|
assert.ok(typeof (opts.vlan_id) === 'string' ||
|
||||||
|
typeof (opts.vlan_id) === 'number', 'opts.vlan_id');
|
||||||
|
assert.func(cb, 'cb');
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
var vlanId = opts.vlan_id;
|
||||||
|
|
||||||
|
if (+vlanId >= 0 && +vlanId < 4096) {
|
||||||
|
deleteVlan(+vlanId);
|
||||||
|
} else {
|
||||||
|
self.getFabricVlan(vlanId, function onGet(err, vlan) {
|
||||||
|
if (err) {
|
||||||
|
cb(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteVlan(vlan.vlan_id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteVlan(id) {
|
||||||
|
self.cloudapi.deleteFabricVlan({vlan_id: id}, cb);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// ---- RBAC
|
// ---- RBAC
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright 2016 Joyent, Inc.
|
* Copyright 2018 Joyent, Inc.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -18,6 +18,8 @@ var test = require('tape');
|
|||||||
|
|
||||||
// --- Globals
|
// --- Globals
|
||||||
|
|
||||||
|
var NET_NAME = 'node-triton-testnet967';
|
||||||
|
|
||||||
var CLIENT;
|
var CLIENT;
|
||||||
var NET;
|
var NET;
|
||||||
|
|
||||||
@ -33,11 +35,14 @@ test('TritonApi networks', function (tt) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
tt.test(' cleanup: rm network ' + NET_NAME + ' if exists', function (t) {
|
||||||
|
CLIENT.deleteFabricNetwork({id: NET_NAME}, function () {
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
tt.test(' setup: net', function (t) {
|
tt.test(' setup: net', function (t) {
|
||||||
var opts = {
|
CLIENT.cloudapi.listNetworks({}, function (err, nets) {
|
||||||
account: CLIENT.profile.account
|
|
||||||
};
|
|
||||||
CLIENT.cloudapi.listNetworks(opts, function (err, nets) {
|
|
||||||
if (h.ifErr(t, err))
|
if (h.ifErr(t, err))
|
||||||
return t.end();
|
return t.end();
|
||||||
|
|
||||||
@ -78,6 +83,61 @@ test('TritonApi networks', function (tt) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
tt.test(' TritonApi deleteFabricNetwork', function (t) {
|
||||||
|
function check(genId, idType, vlanId, cb) {
|
||||||
|
CLIENT.cloudapi.createFabricNetwork({
|
||||||
|
name: NET_NAME,
|
||||||
|
subnet: '192.168.97.0/24',
|
||||||
|
provision_start_ip: '192.168.97.1',
|
||||||
|
provision_end_ip: '192.168.97.254',
|
||||||
|
vlan_id: vlanId
|
||||||
|
}, function onCreate(err, net) {
|
||||||
|
if (h.ifErr(t, err, 'Error creating network')) {
|
||||||
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var id = genId(net);
|
||||||
|
CLIENT.deleteFabricNetwork({id: id}, function onDelete(err2) {
|
||||||
|
if (h.ifErr(t, err, 'Error deleting net by ' + idType)) {
|
||||||
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CLIENT.cloudapi.getNetwork(net.id, function onGet(err3) {
|
||||||
|
t.ok(err3, 'Network should be gone');
|
||||||
|
cb();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// get a VLAN, then create and delete a set of fabrics to check it's
|
||||||
|
// possible to delete by id, shortId and name
|
||||||
|
CLIENT.cloudapi.listFabricVlans({}, function onList(err, vlans) {
|
||||||
|
if (vlans.length === 0) {
|
||||||
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getId(net) { return net.id; }
|
||||||
|
function getName(net) { return net.name; }
|
||||||
|
function getShort(net) { return net.id.split('-')[0]; }
|
||||||
|
|
||||||
|
var vlanId = +vlans[0].vlan_id;
|
||||||
|
|
||||||
|
check(getId, 'id', vlanId, function onId() {
|
||||||
|
check(getName, 'name', vlanId, function onName() {
|
||||||
|
check(getShort, 'shortId', vlanId, function onShort() {
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
tt.test(' teardown: client', function (t) {
|
tt.test(' teardown: client', function (t) {
|
||||||
CLIENT.close();
|
CLIENT.close();
|
||||||
t.end();
|
t.end();
|
||||||
|
@ -25,9 +25,9 @@ var NIC;
|
|||||||
|
|
||||||
// --- Tests
|
// --- Tests
|
||||||
|
|
||||||
test('TritonApi networks', function (tt) {
|
test('TritonApi nics', function (tt) {
|
||||||
tt.test(' setup', function (t) {
|
tt.test(' setup', function (t) {
|
||||||
h.createClient(function (err, client_) {
|
h.createClient(function onCreate(err, client_) {
|
||||||
t.error(err);
|
t.error(err);
|
||||||
CLIENT = client_;
|
CLIENT = client_;
|
||||||
t.end();
|
t.end();
|
||||||
@ -36,9 +36,11 @@ test('TritonApi networks', function (tt) {
|
|||||||
|
|
||||||
|
|
||||||
tt.test(' setup: inst', function (t) {
|
tt.test(' setup: inst', function (t) {
|
||||||
CLIENT.cloudapi.listMachines({}, function (err, vms) {
|
CLIENT.cloudapi.listMachines({}, function onList(err, vms) {
|
||||||
if (vms.length === 0)
|
if (vms.length === 0) {
|
||||||
return t.end();
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
t.ok(Array.isArray(vms), 'vms array');
|
t.ok(Array.isArray(vms), 'vms array');
|
||||||
INST = vms[0];
|
INST = vms[0];
|
||||||
@ -49,13 +51,17 @@ test('TritonApi networks', function (tt) {
|
|||||||
|
|
||||||
|
|
||||||
tt.test(' TritonApi listNics', function (t) {
|
tt.test(' TritonApi listNics', function (t) {
|
||||||
if (!INST)
|
if (!INST) {
|
||||||
return t.end();
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
function check(val, valName, next) {
|
function check(val, valName, next) {
|
||||||
CLIENT.listNics({id: val}, function (err, nics) {
|
CLIENT.listNics({id: val}, function onList(err, nics) {
|
||||||
if (h.ifErr(t, err, 'no err ' + valName))
|
if (h.ifErr(t, err, 'no err ' + valName)) {
|
||||||
return t.end();
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
t.ok(Array.isArray(nics), 'nics array');
|
t.ok(Array.isArray(nics), 'nics array');
|
||||||
NIC = nics[0];
|
NIC = nics[0];
|
||||||
@ -66,9 +72,9 @@ test('TritonApi networks', function (tt) {
|
|||||||
|
|
||||||
var shortId = INST.id.split('-')[0];
|
var shortId = INST.id.split('-')[0];
|
||||||
|
|
||||||
check(INST.id, 'id', function () {
|
check(INST.id, 'id', function doId() {
|
||||||
check(INST.name, 'name', function () {
|
check(INST.name, 'name', function doName() {
|
||||||
check(shortId, 'shortId', function () {
|
check(shortId, 'shortId', function doShort() {
|
||||||
t.end();
|
t.end();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -77,13 +83,17 @@ test('TritonApi networks', function (tt) {
|
|||||||
|
|
||||||
|
|
||||||
tt.test(' TritonApi getNic', function (t) {
|
tt.test(' TritonApi getNic', function (t) {
|
||||||
if (!NIC)
|
if (!NIC) {
|
||||||
return t.end();
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
function check(inst, mac, instValName, next) {
|
function check(inst, mac, instValName, next) {
|
||||||
CLIENT.getNic({id: inst, mac: mac}, function (err, nic) {
|
CLIENT.getNic({id: inst, mac: mac}, function onGet(err, nic) {
|
||||||
if (h.ifErr(t, err, 'no err for ' + instValName))
|
if (h.ifErr(t, err, 'no err for ' + instValName)) {
|
||||||
return t.end();
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
t.deepEqual(nic, NIC, instValName);
|
t.deepEqual(nic, NIC, instValName);
|
||||||
|
|
||||||
@ -93,9 +103,9 @@ test('TritonApi networks', function (tt) {
|
|||||||
|
|
||||||
var shortId = INST.id.split('-')[0];
|
var shortId = INST.id.split('-')[0];
|
||||||
|
|
||||||
check(INST.id, NIC.mac, 'id', function () {
|
check(INST.id, NIC.mac, 'id', function doId() {
|
||||||
check(INST.name, NIC.mac, 'name', function () {
|
check(INST.name, NIC.mac, 'name', function doName() {
|
||||||
check(shortId, NIC.mac, 'shortId', function () {
|
check(shortId, NIC.mac, 'shortId', function doShort() {
|
||||||
t.end();
|
t.end();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
120
test/integration/api-vlans.test.js
Normal file
120
test/integration/api-vlans.test.js
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
* 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 2018 Joyent, Inc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Integration tests for using VLAN-related APIs as a module.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var h = require('./helpers');
|
||||||
|
var test = require('tape');
|
||||||
|
|
||||||
|
|
||||||
|
// --- Globals
|
||||||
|
|
||||||
|
var CLIENT;
|
||||||
|
var VLAN;
|
||||||
|
|
||||||
|
|
||||||
|
// --- Tests
|
||||||
|
|
||||||
|
test('TritonApi vlan', function (tt) {
|
||||||
|
tt.test(' setup', function (t) {
|
||||||
|
h.createClient(function onCreate(err, client_) {
|
||||||
|
t.error(err);
|
||||||
|
CLIENT = client_;
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
tt.test(' setup: vlan', function (t) {
|
||||||
|
CLIENT.cloudapi.listFabricVlans({}, function onList(err, vlans) {
|
||||||
|
if (vlans.length === 0) {
|
||||||
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
VLAN = vlans[0];
|
||||||
|
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
tt.test(' TritonApi getFabricVlan', function (t) {
|
||||||
|
if (!VLAN) {
|
||||||
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
function check(val, valName, next) {
|
||||||
|
CLIENT.getFabricVlan(val, function onGet(err, vlan) {
|
||||||
|
if (h.ifErr(t, err, 'no err')) {
|
||||||
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
t.deepEqual(vlan, VLAN, valName);
|
||||||
|
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
check(VLAN.vlan_id, 'vlan_id', function onId() {
|
||||||
|
check(VLAN.name, 'name', function onName() {
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
tt.test(' TritonApi deleteFabricVlan', function (t) {
|
||||||
|
function check(genId, idType, cb) {
|
||||||
|
CLIENT.cloudapi.createFabricVlan({
|
||||||
|
vlan_id: 3291,
|
||||||
|
name: 'test3291'
|
||||||
|
}, function onCreate(err, vlan) {
|
||||||
|
if (h.ifErr(t, err, 'Error creating VLAN')) {
|
||||||
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var id = genId(vlan);
|
||||||
|
CLIENT.deleteFabricVlan({vlan_id: id}, function onDel(err2) {
|
||||||
|
if (h.ifErr(t, err, 'Error deleting VLAN by ' + idType)) {
|
||||||
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CLIENT.cloudapi.getFabricVlan({vlan_id: vlan.vlan_id},
|
||||||
|
function onGet(err3) {
|
||||||
|
t.ok(err3, 'VLAN should be gone');
|
||||||
|
cb();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getVlanId(net) { return net.vlan_id; }
|
||||||
|
function getName(net) { return net.name; }
|
||||||
|
|
||||||
|
check(getVlanId, 'vlan_id', function onId() {
|
||||||
|
check(getName, 'name', function onName() {
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
tt.test(' teardown: client', function (t) {
|
||||||
|
CLIENT.close();
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
@ -5,28 +5,53 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright 2017 Joyent, Inc.
|
* Copyright 2018 Joyent, Inc.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Integration tests for `triton network(s)`
|
* Integration tests for `triton network(s)`
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var h = require('./helpers');
|
var f = require('util').format;
|
||||||
|
var os = require('os');
|
||||||
var test = require('tape');
|
var test = require('tape');
|
||||||
|
var h = require('./helpers');
|
||||||
|
|
||||||
var common = require('../../lib/common');
|
var common = require('../../lib/common');
|
||||||
|
|
||||||
|
|
||||||
// --- Globals
|
// --- Globals
|
||||||
|
|
||||||
|
var NET_NAME = f('nodetritontest-network-%s', os.hostname());
|
||||||
|
|
||||||
var networks;
|
var networks;
|
||||||
|
var vlan;
|
||||||
|
|
||||||
|
var OPTS = {
|
||||||
|
skip: !h.CONFIG.allowWriteActions
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// --- Tests
|
// --- Tests
|
||||||
|
|
||||||
|
if (OPTS.skip) {
|
||||||
|
console.error('** skipping some %s tests', __filename);
|
||||||
|
console.error('** set "allowWriteActions" in test config to enable');
|
||||||
|
}
|
||||||
|
|
||||||
test('triton networks', function (tt) {
|
test('triton networks', function (tt) {
|
||||||
|
|
||||||
|
tt.test(' setup: find a test VLAN', function (t) {
|
||||||
|
h.triton('vlan list -j', function onTriton(err, stdout, stderr) {
|
||||||
|
if (h.ifErr(t, err))
|
||||||
|
return t.end();
|
||||||
|
|
||||||
|
vlan = JSON.parse(stdout.trim().split('\n')[0]);
|
||||||
|
t.ok(vlan, 'vlan for testing found');
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
tt.test(' triton network list -h', function (t) {
|
tt.test(' triton network list -h', function (t) {
|
||||||
h.triton('networks -h', function (err, stdout, stderr) {
|
h.triton('networks -h', function (err, stdout, stderr) {
|
||||||
if (h.ifErr(t, err))
|
if (h.ifErr(t, err))
|
||||||
@ -209,3 +234,135 @@ test('triton network get', function (tt) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
test('triton network create', OPTS, function (tt) {
|
||||||
|
|
||||||
|
tt.test(' cleanup: rm network ' + NET_NAME + ' if exists', function (t) {
|
||||||
|
h.triton('network delete ' + NET_NAME, function (err, stdout) {
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
tt.test(' triton network create -h', function (t) {
|
||||||
|
h.triton('network create -h', function (err, stdout, stderr) {
|
||||||
|
if (h.ifErr(t, err))
|
||||||
|
return t.end();
|
||||||
|
t.ok(/Usage:\s+triton network\b/.test(stdout));
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
tt.test(' triton network help create', function (t) {
|
||||||
|
h.triton('network help create', function (err, stdout, stderr) {
|
||||||
|
if (h.ifErr(t, err))
|
||||||
|
return t.end();
|
||||||
|
t.ok(/Usage:\s+triton network create\b/.test(stdout));
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
tt.test(' triton network create', function (t) {
|
||||||
|
h.triton('network create', function (err, stdout, stderr) {
|
||||||
|
t.ok(err);
|
||||||
|
t.ok(/error \(Usage\)/.test(stderr));
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
tt.test(' triton network create VLAN', function (t) {
|
||||||
|
h.triton('network create --name=' + NET_NAME +
|
||||||
|
' --subnet=192.168.97.0/24 --start_ip=192.168.97.1' +
|
||||||
|
' --end_ip=192.168.97.254 -j ' + vlan.vlan_id,
|
||||||
|
function (err, stdout) {
|
||||||
|
if (h.ifErr(t, err))
|
||||||
|
return t.end();
|
||||||
|
|
||||||
|
var network = JSON.parse(stdout.trim().split('\n')[0]);
|
||||||
|
|
||||||
|
t.equal(network.name, NET_NAME);
|
||||||
|
t.equal(network.subnet, '192.168.97.0/24');
|
||||||
|
t.equal(network.provision_start_ip, '192.168.97.1');
|
||||||
|
t.equal(network.provision_end_ip, '192.168.97.254');
|
||||||
|
t.equal(network.vlan_id, vlan.vlan_id);
|
||||||
|
|
||||||
|
h.triton('network delete ' + network.id, function (err2) {
|
||||||
|
h.ifErr(t, err2);
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
test('triton network delete', OPTS, function (tt) {
|
||||||
|
|
||||||
|
tt.test(' triton network delete -h', function (t) {
|
||||||
|
h.triton('network delete -h', function (err, stdout, stderr) {
|
||||||
|
if (h.ifErr(t, err))
|
||||||
|
return t.end();
|
||||||
|
t.ok(/Usage:\s+triton network\b/.test(stdout));
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
tt.test(' triton network help delete', function (t) {
|
||||||
|
h.triton('network help delete', function (err, stdout, stderr) {
|
||||||
|
if (h.ifErr(t, err))
|
||||||
|
return t.end();
|
||||||
|
t.ok(/Usage:\s+triton network delete\b/.test(stdout));
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
tt.test(' triton network delete', function (t) {
|
||||||
|
h.triton('network delete', function (err, stdout, stderr) {
|
||||||
|
t.ok(err);
|
||||||
|
t.ok(/error \(Usage\)/.test(stderr));
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function deleteNetworkTester(t, deleter) {
|
||||||
|
h.triton('network create --name=' + NET_NAME +
|
||||||
|
' --subnet=192.168.97.0/24 --start_ip=192.168.97.1' +
|
||||||
|
' --end_ip=192.168.97.254 -j ' + vlan.vlan_id,
|
||||||
|
function (err, stdout) {
|
||||||
|
if (h.ifErr(t, err, 'create test network'))
|
||||||
|
return t.end();
|
||||||
|
|
||||||
|
var network = JSON.parse(stdout.trim().split('\n')[0]);
|
||||||
|
|
||||||
|
deleter(null, network, function (err2) {
|
||||||
|
if (h.ifErr(t, err2, 'deleting test network'))
|
||||||
|
return t.end();
|
||||||
|
|
||||||
|
h.triton('network get ' + network.id, function (err3) {
|
||||||
|
t.ok(err3, 'network should be gone');
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
tt.test(' triton network delete ID', function (t) {
|
||||||
|
deleteNetworkTester(t, function (err, network, cb) {
|
||||||
|
h.triton('network delete ' + network.id, cb);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
tt.test(' triton network delete NAME', function (t) {
|
||||||
|
deleteNetworkTester(t, function (err, network, cb) {
|
||||||
|
h.triton('network delete ' + network.name, cb);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
tt.test(' triton network delete SHORTID', function (t) {
|
||||||
|
deleteNetworkTester(t, function (err, network, cb) {
|
||||||
|
var shortid = network.id.split('-')[0];
|
||||||
|
h.triton('network delete ' + shortid, cb);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
@ -41,7 +41,7 @@ test('triton instance nics', OPTS, function (tt) {
|
|||||||
h.printConfig(tt);
|
h.printConfig(tt);
|
||||||
|
|
||||||
tt.test(' cleanup existing inst with alias ' + INST_ALIAS, function (t) {
|
tt.test(' cleanup existing inst with alias ' + INST_ALIAS, function (t) {
|
||||||
h.deleteTestInst(t, INST_ALIAS, function (err) {
|
h.deleteTestInst(t, INST_ALIAS, function onDelete(err) {
|
||||||
t.ifErr(err);
|
t.ifErr(err);
|
||||||
t.end();
|
t.end();
|
||||||
});
|
});
|
||||||
@ -49,8 +49,10 @@ test('triton instance nics', OPTS, function (tt) {
|
|||||||
|
|
||||||
tt.test(' setup: triton instance create', function (t) {
|
tt.test(' setup: triton instance create', function (t) {
|
||||||
h.createTestInst(t, INST_ALIAS, {}, function onInst(err, instId) {
|
h.createTestInst(t, INST_ALIAS, {}, function onInst(err, instId) {
|
||||||
if (h.ifErr(t, err, 'triton instance create'))
|
if (h.ifErr(t, err, 'triton instance create')) {
|
||||||
return t.end();
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
t.ok(instId, 'created instance ' + instId);
|
t.ok(instId, 'created instance ' + instId);
|
||||||
INST = instId;
|
INST = instId;
|
||||||
@ -61,8 +63,10 @@ test('triton instance nics', OPTS, function (tt) {
|
|||||||
|
|
||||||
tt.test(' setup: find network for tests', function (t) {
|
tt.test(' setup: find network for tests', function (t) {
|
||||||
h.triton('network list -j', function onNetworks(err, stdout) {
|
h.triton('network list -j', function onNetworks(err, stdout) {
|
||||||
if (h.ifErr(t, err, 'triton network list'))
|
if (h.ifErr(t, err, 'triton network list')) {
|
||||||
return t.end();
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
NETWORK = JSON.parse(stdout.trim().split('\n')[0]);
|
NETWORK = JSON.parse(stdout.trim().split('\n')[0]);
|
||||||
t.ok(NETWORK, 'NETWORK');
|
t.ok(NETWORK, 'NETWORK');
|
||||||
@ -74,9 +78,11 @@ test('triton instance nics', OPTS, function (tt) {
|
|||||||
tt.test(' triton instance nic create', function (t) {
|
tt.test(' triton instance nic create', function (t) {
|
||||||
var cmd = 'instance nic create -j -w ' + INST + ' ' + NETWORK.id;
|
var cmd = 'instance nic create -j -w ' + INST + ' ' + NETWORK.id;
|
||||||
|
|
||||||
h.triton(cmd, function (err, stdout, stderr) {
|
h.triton(cmd, function onTriton(err, stdout, stderr) {
|
||||||
if (h.ifErr(t, err, 'triton instance nic create'))
|
if (h.ifErr(t, err, 'triton instance nic create')) {
|
||||||
return t.end();
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
NIC = JSON.parse(stdout);
|
NIC = JSON.parse(stdout);
|
||||||
t.ok(NIC, 'created NIC: ' + stdout.trim());
|
t.ok(NIC, 'created NIC: ' + stdout.trim());
|
||||||
@ -88,9 +94,11 @@ test('triton instance nics', OPTS, function (tt) {
|
|||||||
tt.test(' triton instance nic get', function (t) {
|
tt.test(' triton instance nic get', function (t) {
|
||||||
var cmd = 'instance nic get ' + INST + ' ' + NIC.mac;
|
var cmd = 'instance nic get ' + INST + ' ' + NIC.mac;
|
||||||
|
|
||||||
h.triton(cmd, function (err, stdout, stderr) {
|
h.triton(cmd, function onTriton(err, stdout, stderr) {
|
||||||
if (h.ifErr(t, err, 'triton instance nic get'))
|
if (h.ifErr(t, err, 'triton instance nic get')) {
|
||||||
return t.end();
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var obj = JSON.parse(stdout);
|
var obj = JSON.parse(stdout);
|
||||||
t.equal(obj.mac, NIC.mac, 'nic MAC is correct');
|
t.equal(obj.mac, NIC.mac, 'nic MAC is correct');
|
||||||
@ -104,9 +112,11 @@ test('triton instance nics', OPTS, function (tt) {
|
|||||||
tt.test(' triton instance nic list', function (t) {
|
tt.test(' triton instance nic list', function (t) {
|
||||||
var cmd = 'instance nic list ' + INST;
|
var cmd = 'instance nic list ' + INST;
|
||||||
|
|
||||||
h.triton(cmd, function (err, stdout, stderr) {
|
h.triton(cmd, function onTriton(err, stdout, stderr) {
|
||||||
if (h.ifErr(t, err, 'triton instance nic list'))
|
if (h.ifErr(t, err, 'triton instance nic list')) {
|
||||||
return t.end();
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var nics = stdout.trim().split('\n');
|
var nics = stdout.trim().split('\n');
|
||||||
t.ok(nics[0].match(/IP\s+MAC\s+STATE\s+NETWORK/), 'nic list' +
|
t.ok(nics[0].match(/IP\s+MAC\s+STATE\s+NETWORK/), 'nic list' +
|
||||||
@ -115,7 +125,7 @@ test('triton instance nics', OPTS, function (tt) {
|
|||||||
|
|
||||||
t.ok(nics.length >= 1, 'triton nic list expected nic num');
|
t.ok(nics.length >= 1, 'triton nic list expected nic num');
|
||||||
|
|
||||||
var testNics = nics.filter(function (nic) {
|
var testNics = nics.filter(function doFilter(nic) {
|
||||||
return nic.match(NIC.mac);
|
return nic.match(NIC.mac);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -128,17 +138,19 @@ test('triton instance nics', OPTS, function (tt) {
|
|||||||
tt.test(' triton instance nic list -j', function (t) {
|
tt.test(' triton instance nic list -j', function (t) {
|
||||||
var cmd = 'instance nic list -j ' + INST;
|
var cmd = 'instance nic list -j ' + INST;
|
||||||
|
|
||||||
h.triton(cmd, function (err, stdout, stderr) {
|
h.triton(cmd, function onTriton(err, stdout, stderr) {
|
||||||
if (h.ifErr(t, err, 'triton instance nic list'))
|
if (h.ifErr(t, err, 'triton instance nic list')) {
|
||||||
return t.end();
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var nics = stdout.trim().split('\n').map(function (line) {
|
var nics = stdout.trim().split('\n').map(function doParse(line) {
|
||||||
return JSON.parse(line);
|
return JSON.parse(line);
|
||||||
});
|
});
|
||||||
|
|
||||||
t.ok(nics.length >= 1, 'triton nic list expected nic num');
|
t.ok(nics.length >= 1, 'triton nic list expected nic num');
|
||||||
|
|
||||||
var testNics = nics.filter(function (nic) {
|
var testNics = nics.filter(function doFilter(nic) {
|
||||||
return nic.mac === NIC.mac;
|
return nic.mac === NIC.mac;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -150,11 +162,13 @@ test('triton instance nics', OPTS, function (tt) {
|
|||||||
|
|
||||||
tt.test(' triton instance nic list mac=<...>', function (t) {
|
tt.test(' triton instance nic list mac=<...>', function (t) {
|
||||||
var cmd = 'instance nic list -j ' + INST + ' mac=' + NIC.mac;
|
var cmd = 'instance nic list -j ' + INST + ' mac=' + NIC.mac;
|
||||||
h.triton(cmd, function (err, stdout, stderr) {
|
h.triton(cmd, function onTriton(err, stdout, stderr) {
|
||||||
if (h.ifErr(t, err))
|
if (h.ifErr(t, err)) {
|
||||||
return t.end();
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var nics = stdout.trim().split('\n').map(function (str) {
|
var nics = stdout.trim().split('\n').map(function doParse(str) {
|
||||||
return JSON.parse(str);
|
return JSON.parse(str);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -169,11 +183,13 @@ test('triton instance nics', OPTS, function (tt) {
|
|||||||
tt.test(' triton nic list mac=<...>', function (t) {
|
tt.test(' triton nic list mac=<...>', function (t) {
|
||||||
var cmd = 'instance nic list -j ' + INST + ' mac=' + NIC.mac;
|
var cmd = 'instance nic list -j ' + INST + ' mac=' + NIC.mac;
|
||||||
|
|
||||||
h.triton(cmd, function (err, stdout, stderr) {
|
h.triton(cmd, function doTriton(err, stdout, stderr) {
|
||||||
if (h.ifErr(t, err))
|
if (h.ifErr(t, err)) {
|
||||||
return t.end();
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var nics = stdout.trim().split('\n').map(function (str) {
|
var nics = stdout.trim().split('\n').map(function doParse(str) {
|
||||||
return JSON.parse(str);
|
return JSON.parse(str);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -188,9 +204,11 @@ test('triton instance nics', OPTS, function (tt) {
|
|||||||
tt.test(' triton instance nic delete', function (t) {
|
tt.test(' triton instance nic delete', function (t) {
|
||||||
var cmd = 'instance nic delete --force ' + INST + ' ' + NIC.mac;
|
var cmd = 'instance nic delete --force ' + INST + ' ' + NIC.mac;
|
||||||
|
|
||||||
h.triton(cmd, function (err, stdout, stderr) {
|
h.triton(cmd, function doTriton(err, stdout, stderr) {
|
||||||
if (h.ifErr(t, err, 'triton instance nic delete'))
|
if (h.ifErr(t, err, 'triton instance nic delete')) {
|
||||||
return t.end();
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
t.ok(stdout.match('Deleted NIC ' + NIC.mac, 'deleted nic'));
|
t.ok(stdout.match('Deleted NIC ' + NIC.mac, 'deleted nic'));
|
||||||
|
|
||||||
@ -202,9 +220,11 @@ test('triton instance nics', OPTS, function (tt) {
|
|||||||
var cmd = 'instance nic create -j -w ' + INST + ' ipv4_uuid=' +
|
var cmd = 'instance nic create -j -w ' + INST + ' ipv4_uuid=' +
|
||||||
NETWORK.id;
|
NETWORK.id;
|
||||||
|
|
||||||
h.triton(cmd, function (err, stdout, stderr) {
|
h.triton(cmd, function doTriton(err, stdout, stderr) {
|
||||||
if (h.ifErr(t, err, 'triton instance nic create'))
|
if (h.ifErr(t, err, 'triton instance nic create')) {
|
||||||
return t.end();
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
NIC2 = JSON.parse(stdout);
|
NIC2 = JSON.parse(stdout);
|
||||||
|
|
||||||
@ -215,9 +235,11 @@ test('triton instance nics', OPTS, function (tt) {
|
|||||||
tt.test(' triton instance nic with ip get', function (t) {
|
tt.test(' triton instance nic with ip get', function (t) {
|
||||||
var cmd = 'instance nic get ' + INST + ' ' + NIC2.mac;
|
var cmd = 'instance nic get ' + INST + ' ' + NIC2.mac;
|
||||||
|
|
||||||
h.triton(cmd, function (err, stdout, stderr) {
|
h.triton(cmd, function onTriton(err, stdout, stderr) {
|
||||||
if (h.ifErr(t, err, 'triton instance nic get'))
|
if (h.ifErr(t, err, 'triton instance nic get')) {
|
||||||
return t.end();
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var obj = JSON.parse(stdout);
|
var obj = JSON.parse(stdout);
|
||||||
t.equal(obj.mac, NIC2.mac, 'nic MAC is correct');
|
t.equal(obj.mac, NIC2.mac, 'nic MAC is correct');
|
||||||
@ -231,9 +253,11 @@ test('triton instance nics', OPTS, function (tt) {
|
|||||||
tt.test(' triton instance nic with ip delete', function (t) {
|
tt.test(' triton instance nic with ip delete', function (t) {
|
||||||
var cmd = 'instance nic delete --force ' + INST + ' ' + NIC2.mac;
|
var cmd = 'instance nic delete --force ' + INST + ' ' + NIC2.mac;
|
||||||
|
|
||||||
h.triton(cmd, function (err, stdout, stderr) {
|
h.triton(cmd, function onTriton(err, stdout, stderr) {
|
||||||
if (h.ifErr(t, err, 'triton instance nic with ip delete'))
|
if (h.ifErr(t, err, 'triton instance nic with ip delete')) {
|
||||||
return t.end();
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
t.ok(stdout.match('Deleted NIC ' + NIC2.mac, 'deleted nic'));
|
t.ok(stdout.match('Deleted NIC ' + NIC2.mac, 'deleted nic'));
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2015, Joyent, Inc.
|
* Copyright (c) 2018, Joyent, Inc.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -65,8 +65,18 @@ var subs = [
|
|||||||
['ip'],
|
['ip'],
|
||||||
['ssh'],
|
['ssh'],
|
||||||
['network'],
|
['network'],
|
||||||
['network list', 'networks'],
|
['network create'],
|
||||||
|
['network list', 'network ls', 'networks'],
|
||||||
['network get'],
|
['network get'],
|
||||||
|
['network get-default'],
|
||||||
|
['network set-default'],
|
||||||
|
['network delete', 'network rm'],
|
||||||
|
['vlan'],
|
||||||
|
['vlan create'],
|
||||||
|
['vlan list', 'vlan ls'],
|
||||||
|
['vlan get'],
|
||||||
|
['vlan update'],
|
||||||
|
['vlan delete', 'vlan rm'],
|
||||||
['key'],
|
['key'],
|
||||||
['key add'],
|
['key add'],
|
||||||
['key list', 'key ls', 'keys'],
|
['key list', 'key ls', 'keys'],
|
||||||
|
418
test/integration/cli-vlans.test.js
Normal file
418
test/integration/cli-vlans.test.js
Normal file
@ -0,0 +1,418 @@
|
|||||||
|
/*
|
||||||
|
* 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 2018 Joyent, Inc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Integration tests for `triton vlans`
|
||||||
|
*/
|
||||||
|
|
||||||
|
var f = require('util').format;
|
||||||
|
var os = require('os');
|
||||||
|
var test = require('tape');
|
||||||
|
var h = require('./helpers');
|
||||||
|
|
||||||
|
var common = require('../../lib/common');
|
||||||
|
|
||||||
|
|
||||||
|
// --- Globals
|
||||||
|
|
||||||
|
var VLAN_NAME = f('nodetritontest-vlan-%s', os.hostname());
|
||||||
|
var VLAN_ID = 3197;
|
||||||
|
|
||||||
|
var VLAN;
|
||||||
|
|
||||||
|
var OPTS = {
|
||||||
|
skip: !h.CONFIG.allowWriteActions
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// --- Tests
|
||||||
|
|
||||||
|
if (OPTS.skip) {
|
||||||
|
console.error('** skipping some %s tests', __filename);
|
||||||
|
console.error('** set "allowWriteActions" in test config to enable');
|
||||||
|
}
|
||||||
|
|
||||||
|
test('triton vlan list', function (tt) {
|
||||||
|
|
||||||
|
tt.test(' triton vlan list -h', function (t) {
|
||||||
|
h.triton('vlan list -h', function onTriton(err, stdout, stderr) {
|
||||||
|
if (h.ifErr(t, err)) {
|
||||||
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
t.ok(/Usage:\s+triton vlan list/.test(stdout));
|
||||||
|
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
tt.test(' triton vlan list', function (t) {
|
||||||
|
h.triton('vlan list', function onTriton(err, stdout, stderr) {
|
||||||
|
if (h.ifErr(t, err)) {
|
||||||
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
t.ok(/^VLAN_ID\b/.test(stdout));
|
||||||
|
t.ok(/\bNAME\b/.test(stdout));
|
||||||
|
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
tt.test(' triton vlan list -j', function (t) {
|
||||||
|
h.triton('vlan list -j', function onTriton(err, stdout, stderr) {
|
||||||
|
if (h.ifErr(t, err)) {
|
||||||
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
VLAN = JSON.parse(stdout.trim().split('\n')[0]);
|
||||||
|
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
tt.test(' triton vlan list vlan_id=<...>', function (t) {
|
||||||
|
var cmd = 'vlan list -j vlan_id=' + VLAN.vlan_id;
|
||||||
|
h.triton(cmd, function onTriton(err, stdout, stderr) {
|
||||||
|
if (h.ifErr(t, err)) {
|
||||||
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var vlans = stdout.trim().split('\n').map(function onParse(str) {
|
||||||
|
return JSON.parse(str);
|
||||||
|
});
|
||||||
|
|
||||||
|
t.deepEqual(vlans, [VLAN]);
|
||||||
|
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
tt.test(' triton vlan list vlan_id=<...> name=<...> (good)', function (t) {
|
||||||
|
var cmd = 'vlan list -j vlan_id=' + VLAN.vlan_id + ' name=' + VLAN.name;
|
||||||
|
|
||||||
|
h.triton(cmd, function onTriton(err, stdout, stderr) {
|
||||||
|
if (h.ifErr(t, err)) {
|
||||||
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var vlans = stdout.trim().split('\n').map(function onParse(str) {
|
||||||
|
return JSON.parse(str);
|
||||||
|
});
|
||||||
|
|
||||||
|
t.deepEqual(vlans, [VLAN]);
|
||||||
|
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
tt.test(' triton vlan list vlan_id=<...> name=<...> (bad)', function (t) {
|
||||||
|
// search for a mismatch, should return nada
|
||||||
|
var cmd = 'vlan list -j vlan_id=' + VLAN.vlan_id + ' name=' +
|
||||||
|
VLAN.name + 'a';
|
||||||
|
|
||||||
|
h.triton(cmd, function onTriton(err, stdout, stderr) {
|
||||||
|
if (h.ifErr(t, err)) {
|
||||||
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
t.equal(stdout, '');
|
||||||
|
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
test('triton vlan get', function (tt) {
|
||||||
|
|
||||||
|
tt.test(' triton vlan get -h', function (t) {
|
||||||
|
h.triton('vlan get -h', function onTriton(err, stdout, stderr) {
|
||||||
|
if (h.ifErr(t, err)) {
|
||||||
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
t.ok(/Usage:\s+triton vlan\b/.test(stdout));
|
||||||
|
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
tt.test(' triton vlan help get', function (t) {
|
||||||
|
h.triton('vlan help get', function onTriton(err, stdout, stderr) {
|
||||||
|
if (h.ifErr(t, err)) {
|
||||||
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
t.ok(/Usage:\s+triton vlan get\b/.test(stdout));
|
||||||
|
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
tt.test(' triton vlan get', function (t) {
|
||||||
|
h.triton('vlan get', function onTriton(err, stdout, stderr) {
|
||||||
|
t.ok(err);
|
||||||
|
t.ok(/error \(Usage\)/.test(stderr));
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
tt.test(' triton vlan get ID', function (t) {
|
||||||
|
h.triton('vlan get ' + VLAN.vlan_id,
|
||||||
|
function onTriton(err, stdout, stderr) {
|
||||||
|
if (h.ifErr(t, err)) {
|
||||||
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var vlan = JSON.parse(stdout);
|
||||||
|
t.equal(vlan.vlan_id, VLAN.vlan_id);
|
||||||
|
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
tt.test(' triton vlan get NAME', function (t) {
|
||||||
|
h.triton('vlan get ' + VLAN.name,
|
||||||
|
function onTriton(err, stdout, stderr) {
|
||||||
|
if (h.ifErr(t, err)) {
|
||||||
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var vlan = JSON.parse(stdout);
|
||||||
|
t.equal(vlan.vlan_id, VLAN.vlan_id);
|
||||||
|
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
test('triton vlan networks', function (tt) {
|
||||||
|
|
||||||
|
tt.test(' triton vlan networks -h', function (t) {
|
||||||
|
h.triton('vlan networks -h', function onTriton(err, stdout, stderr) {
|
||||||
|
if (h.ifErr(t, err)) {
|
||||||
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
t.ok(/Usage:\s+triton vlan networks/.test(stdout));
|
||||||
|
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
tt.test(' triton vlan help networks', function (t) {
|
||||||
|
h.triton('vlan help networks', function onTriton(err, stdout, stderr) {
|
||||||
|
if (h.ifErr(t, err)) {
|
||||||
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
t.ok(/Usage:\s+triton vlan networks/.test(stdout));
|
||||||
|
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
tt.test(' triton vlan networks', function (t) {
|
||||||
|
h.triton('vlan networks', function onTriton(err, stdout, stderr) {
|
||||||
|
t.ok(err);
|
||||||
|
t.ok(/error \(Usage\)/.test(stderr));
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
tt.test(' triton vlan networks ID', function (t) {
|
||||||
|
h.triton('vlan networks -j ' + VLAN.vlan_id,
|
||||||
|
function onTriton(err, stdout, stderr) {
|
||||||
|
if (h.ifErr(t, err)) {
|
||||||
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var vlan = JSON.parse(stdout);
|
||||||
|
t.equal(vlan.vlan_id, VLAN.vlan_id);
|
||||||
|
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
tt.test(' triton vlan networks NAME', function (t) {
|
||||||
|
h.triton('vlan networks -j ' + VLAN.name,
|
||||||
|
function onTriton(err, stdout, stderr) {
|
||||||
|
if (h.ifErr(t, err)) {
|
||||||
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var vlan = JSON.parse(stdout);
|
||||||
|
t.equal(vlan.vlan_id, VLAN.vlan_id);
|
||||||
|
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
test('triton vlan create', OPTS, function (tt) {
|
||||||
|
|
||||||
|
tt.test(' cleanup: rm vlan ' + VLAN_NAME + ' if exists', function (t) {
|
||||||
|
h.triton('vlan delete ' + VLAN_NAME, function onTriton(err, stdout) {
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
tt.test(' triton vlan create -h', function (t) {
|
||||||
|
h.triton('vlan create -h', function onTriton(err, stdout, stderr) {
|
||||||
|
if (h.ifErr(t, err)) {
|
||||||
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
t.ok(/Usage:\s+triton vlan\b/.test(stdout));
|
||||||
|
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
tt.test(' triton vlan help create', function (t) {
|
||||||
|
h.triton('vlan help create', function onTriton(err, stdout, stderr) {
|
||||||
|
if (h.ifErr(t, err)) {
|
||||||
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
t.ok(/Usage:\s+triton vlan create\b/.test(stdout));
|
||||||
|
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
tt.test(' triton vlan create', function (t) {
|
||||||
|
h.triton('vlan create', function onTriton(err, stdout, stderr) {
|
||||||
|
t.ok(err);
|
||||||
|
t.ok(/error \(Usage\)/.test(stderr));
|
||||||
|
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
tt.test(' triton vlan create VLAN', function (t) {
|
||||||
|
h.triton('vlan create -j --name=' + VLAN_NAME + ' ' + VLAN_ID,
|
||||||
|
function onTriton(err, stdout) {
|
||||||
|
if (h.ifErr(t, err)) {
|
||||||
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var vlan = JSON.parse(stdout.trim().split('\n')[0]);
|
||||||
|
|
||||||
|
t.equal(vlan.name, VLAN_NAME);
|
||||||
|
t.equal(vlan.vlan_id, VLAN_ID);
|
||||||
|
|
||||||
|
h.triton('vlan delete ' + vlan.vlan_id, function onTriton2(err2) {
|
||||||
|
h.ifErr(t, err2);
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
test('triton vlan delete', OPTS, function (tt) {
|
||||||
|
|
||||||
|
tt.test(' triton vlan delete -h', function (t) {
|
||||||
|
h.triton('vlan delete -h', function onTriton(err, stdout, stderr) {
|
||||||
|
if (h.ifErr(t, err)) {
|
||||||
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
t.ok(/Usage:\s+triton vlan\b/.test(stdout));
|
||||||
|
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
tt.test(' triton vlan help delete', function (t) {
|
||||||
|
h.triton('vlan help delete', function onTriton(err, stdout, stderr) {
|
||||||
|
if (h.ifErr(t, err)) {
|
||||||
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
t.ok(/Usage:\s+triton vlan delete\b/.test(stdout));
|
||||||
|
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
tt.test(' triton vlan delete', function (t) {
|
||||||
|
h.triton('vlan delete', function onTriton(err, stdout, stderr) {
|
||||||
|
t.ok(err);
|
||||||
|
t.ok(/error \(Usage\)/.test(stderr));
|
||||||
|
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function deleteNetworkTester(t, deleter) {
|
||||||
|
h.triton('vlan create -j --name=' + VLAN_NAME + ' ' + VLAN_ID,
|
||||||
|
function onTriton(err, stdout) {
|
||||||
|
if (h.ifErr(t, err, 'create test vlan')) {
|
||||||
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var vlan = JSON.parse(stdout.trim().split('\n')[0]);
|
||||||
|
|
||||||
|
deleter(null, vlan, function onDelete(err2) {
|
||||||
|
if (h.ifErr(t, err2, 'deleting test vlan')) {
|
||||||
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
h.triton('vlan get ' + vlan.vlan_id, function onTriton2(err3) {
|
||||||
|
t.ok(err3, 'vlan should be gone');
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
tt.test(' triton vlan delete ID', function (t) {
|
||||||
|
deleteNetworkTester(t, function doDelete(err, vlan, cb) {
|
||||||
|
h.triton('vlan delete ' + vlan.vlan_id, cb);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
tt.test(' triton vlan delete NAME', function (t) {
|
||||||
|
deleteNetworkTester(t, function doDelete(err, vlan, cb) {
|
||||||
|
h.triton('vlan delete ' + vlan.name, cb);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
@ -183,6 +183,7 @@ function getTestImg(t, cb) {
|
|||||||
var candidateImageNames = {
|
var candidateImageNames = {
|
||||||
'base-64-lts': true,
|
'base-64-lts': true,
|
||||||
'base-64': true,
|
'base-64': true,
|
||||||
|
'minimal-64-lts': true,
|
||||||
'minimal-64': true,
|
'minimal-64': true,
|
||||||
'base-32-lts': true,
|
'base-32-lts': true,
|
||||||
'base-32': true,
|
'base-32': true,
|
||||||
|
Reference in New Issue
Block a user