Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TRITON-2191 Initial support of AWS style VPCs #308

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ Known issues:

## not yet released

## 7.13.0

- [TRITON-2182] Added `triton changefeed` subcommand

## 7.12.2

- Add in sourcing from an instance tag an alternate port to ssh to for
Expand Down
6 changes: 5 additions & 1 deletion lib/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*/

/*
* Copyright (c) 2017, Joyent, Inc.
* Copyright 2020 Joyent, Inc.
*
* The `triton` CLI class.
*/
Expand Down Expand Up @@ -211,6 +211,7 @@ function CLI() {
'network',
'fwrule',
'vlan',
'vpc',
{ group: 'Other Commands' },
'info',
'account',
Expand Down Expand Up @@ -710,6 +711,9 @@ CLI.prototype.do_network = require('./do_network');
// VLANs
CLI.prototype.do_vlan = require('./do_vlan');

// VPCs
CLI.prototype.do_vpc = require('./do_vpc');

// Hidden commands
CLI.prototype.do_cloudapi = require('./do_cloudapi');
CLI.prototype.do_badger = require('./do_badger');
Expand Down
203 changes: 203 additions & 0 deletions lib/cloudapi2.js
Original file line number Diff line number Diff line change
Expand Up @@ -804,6 +804,209 @@ function deleteFabricVlan(opts, cb) {
});
};

// ---- VPCs

/*
* Creates a VPC.
*
* @param {Object} options object containing:
* - {String} name (required) A unique name to identify the VPC.
* - {String} cidr (required) A CIDR description of the VPC.
* - {String} description (optional)
* @param {Function} callback for the form f(err, vpc, res).
*/
CloudApi.prototype.createVPC =
function createVPC(opts, cb) {
assert.objects(opts, 'opts');
assert.string(opts.subnet, 'opts.subnet');
assert.string(opts.name, 'opts.name');
assert.optionalString(opts.description, 'opts.description');

var data = common.objCopy(opts);

this._request({
method: 'POST',
path: format('/%s/vpc', this.account),
data: data
}, function onReq(err, req, res, body) {
cb(err, body, res);
});
};

/**
* List all VPCs for a user.
*
* Returns an array of objects.
*
* @param opts {Object} Options
* @param {Function} callback of the form f(err, vpcs, res).
*/
CloudApi.prototype.listVPCs =
function listVPCs(opts, cb) {
assert.object(opts, 'opts');
assert.func(cb, 'cb');

var endpoint = format('/%s/vpc', this.account);
this._passThrough(endpoint, opts, cb);
};

CloudApi.prototype.getVPC =
function getVPC(opts, cb) {
assert.object(opts, 'opts');
assert.string(opts.vpc_id, 'opts.vpc_id');
assert.func(cb, 'cb');

var endpoint = format('/%s/vpc/%s', this.account, opts.vpc_id);
this._request(endpoint, function onReq(err, req, res, body) {
cb(err, body, res);
});
};

// <updatable account field> -> <expected typeof>
CloudApi.prototype.UPDATE_VPC_FIELDS = {
name: 'string',
description: 'string'
};

/**
* Updates a VPC.
*
* @param {Object} opts opject containing:
* - {String} vpc_id: The VPC uuid. Required.
* - {String} name: The VPC name. Optional.
* - {String} description: Description of the VLAN. Optional.
* @param {Function} callback for the form `function (err, vpc, res)`
*/
CloudApi.prototype.updateVPC =
function updateVPC(opts, cb) {
assert.object(opts, 'opts');
assert.string(opts.vpc_id, 'opts.vpc_id');
assert.optionalString(opts.name, 'opts.name');
assert.optionalStirng(opts.description, 'opts.description');
assert.func(cb, 'cb');

var data = {};
Object.keys(this.UPDATE_VPC_FIELDS).forEach(function forCb(attr) {
if (opts[attr] !== undefined)
data[attr] = opts[attr];
});

var vpcId = opts.vpc_id;

this._request({
method: 'POST',
path: format('/%s/vpc/%s', this.account, vpcId),
data: data
}, function onReq(err, req, res, body) {
cb(err, body, res);
});
};

/*
* Remove a VPC.
*
* @param {Object} opts (object)
* - {String} vpc_id: The VPC uuid. Required.
* @param {Function} cb of the form `function (err, res)`.
*/
CloudApi.prototype.deleteVPC =
function deleteVPC(opts, cb) {
assert.object(opts, 'opts');
assert.uuid(opts.vpc_id, 'opts.vpc_id');
assert.func(cb, 'cb');

this._request({
method: 'DELETE',
path: format('/%s/vpc/%s', this.account, opts.vpc_id)
}, function onReq(err, req, res) {
cb(err, res);
});
};

/**
* Creates a network on a VPC
*
* @param {Object} options object containing:
* - {String} vpc_id (required) The VPC uuid
* - {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.
* - {Array} resolvers (optional) DNS resolvers for hosts on network.
* - {Object} routes (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.createVPCNetwork =
function createVPCNetwork(opts, cb) {
assert.object(opts, 'opts');
assert.uuid(opts.vpc_id, 'opts.vpc_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.optionalArrayOfString(opts.resolvers, 'opts.resolvers');
assert.optionalObject(opts.routes, 'opts.routes');
assert.optionalBool(opts.internet_nat, 'opts.internet_nat');

var data = common.objCopy(opts);
var vpcId = data.vpc_id;
delete data.vpc_id;

this._request({
method: 'POST',
path: format('/%s/vpc/%s/networks', this.account, vpcId),
data: data
}, function reqCb(err, req, res, body) {
cb(err, body, res);
});
};

/**
* Lists all networks on a VPC.
*
* Returns an array of objects.
*
* @param {Object} options object containing:
* - {String} vpc_id (required) VPC uuid.
* @param {Function} callback of the form f(err, networks, res).
*/
CloudApi.prototype.listVPCNetworks =
function listVPCNetworks(opts, cb) {
assert.object(opts, 'opts');
assert.uuid(opts.vpc_id, 'opts.vpc_id');
assert.func(cb, 'cb');

var endpoint = format('/%s/vpc/%s/networks', this.account, opts.vpc_id);
this._passThrough(endpoint, opts, cb);
};

/**
* Remove a VPC network
*
* @param {Object} opts (object)
* - {String} id: The network id. Required.
* - {String} vpc_id: The VPC id. Required.
* @param {Function} cb of the form `function (err, res)`
*/
CloudApi.prototype.deleteVPCNetwork =
function deleteVPCNetwork(opts, cb) {
assert.object(opts, 'opts');
assert.uuid(opts.id, 'opts.id');
assert.uuid(opts.vpc_id, 'opts.vpc_id');
assert.func(cb, 'cb');

this._request({
method: 'DELETE',
path: format('/%s/vpc/networks/%s', this.account, opts.vpc_id, opts.id)
}, function reqCb(err, req, res) {
cb(err, res);
});
};

// ---- datacenters

Expand Down
142 changes: 142 additions & 0 deletions lib/do_vpc/do_create.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
/*
* 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 2021 Joyent, Inc.
*
* `triton vpc create ...`
*/

var assert = require('assert-plus');
var format = require('util').format;
var jsprim = require('jsprim');
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 CIDR block'));
return;
} else if (args.length > 1) {
cb(new errors.UsageError('incorrect number of arguments'));
return;
}

var cidr = args[0];

if (typeof (cidr) !== 'string') {
cb(new errors.UsageError('CIDR must be a string'));
return;
}

if (!opts.name) {
cb(new errors.UsageError('must provide a --name (-n)'));
return;
}

var createOpts = {
name: opts.name,
ip4_cidr: cidr
};

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.createVPC(createOpts, function onCreate(err, vpc) {
if (err) {
cb(err);
return;
}

if (opts.json) {
console.log(JSON.stringify(vpc));
} else {
if (vpc.name) {
console.log('Created VPC %s (%s)', vpc.name,
vpc.vpc_id);
} else {
console.log('Created vlan %s', vpc.vpc_id);
}
}

cb();
});
});
}


do_create.options = [
{
names: ['help', 'h'],
type: 'bool',
help: 'Show this help.'
},
{
group: 'Create options'
},
{
names: ['name', 'n'],
type: 'string',
helpArg: 'NAME',
help: 'Name of the VPC.'
},
{
names: ['description', 'D'],
type: 'string',
helpArg: 'DESC',
help: 'Description of the VPC.'
},
{
group: 'Other options'
},
{
names: ['json', 'j'],
type: 'bool',
help: 'JSON stream output.'
}
];

do_create.synopses = ['{{name}} {{cmd}} [OPTIONS] CIDR'];

do_create.help = [
'Create a VPC.',
'',
'{{usage}}',
'',
'{{options}}',
'Example:',
' triton vpc create -n "prod" -D "Production VPC" 192.168.0.0/16'
].join('\n');

do_create.helpOpts = {
helpCol: 16
};

module.exports = do_create;
Loading