Compare commits
1 Commits
master
...
PUBAPI-142
Author | SHA1 | Date | |
---|---|---|---|
|
de9505d569 |
@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2016 Joyent, Inc.
|
||||
* Copyright 2017 Joyent, Inc.
|
||||
*
|
||||
* `triton instance create ...`
|
||||
*/
|
||||
@ -20,6 +20,59 @@ var distractions = require('../distractions');
|
||||
var errors = require('../errors');
|
||||
var mat = require('../metadataandtags');
|
||||
|
||||
function parseVolume(volume) {
|
||||
var components;
|
||||
var VALID_MODES = ['ro', 'rw'];
|
||||
var VALID_VOLUME_NAME_REGEXP = /^[a-zA-Z0-9][a-zA-Z0-9_\.\-]+$/;
|
||||
|
||||
if (typeof(volume) !== 'string') {
|
||||
return new errors.UsageError('unparseable volume specified');
|
||||
}
|
||||
|
||||
components = volume.split(':');
|
||||
if (components.length !== 2 && components.length !== 3) {
|
||||
return new errors.UsageError('invalid volume specified, must be in ' +
|
||||
'the form "<volume name>:<mount path>[:<mode>]", got: "' + volume +
|
||||
'"');
|
||||
}
|
||||
|
||||
// first component should be a volume name. We only check here that it
|
||||
// syntactically looks like a volume name, we'll leave the upstream to
|
||||
// determine if it's not actually a volume.
|
||||
if (!VALID_VOLUME_NAME_REGEXP.test(components[0])) {
|
||||
return new errors.UsageError('invalid volume name, got: "' + volume +
|
||||
'"');
|
||||
}
|
||||
|
||||
// second component should be an absolute path
|
||||
// NOTE: if we ever move past node 0.10, we could use path.isAbsolute(path)
|
||||
if (components[1].length === 0 || (components[1])[0] !== '/') {
|
||||
return new errors.UsageError('invalid volume mountpoint, must be ' +
|
||||
'absolute path, got: "' + volume + '"');
|
||||
}
|
||||
if (components[1].indexOf('\0') !== -1) {
|
||||
return new errors.UsageError('invalid volume mountpoint, contains ' +
|
||||
'invalid characters, got: "' + volume + '"');
|
||||
}
|
||||
if (components[1].search(/[^\/]/) === -1) {
|
||||
return new errors.UsageError('invalid volume mountpoint, must contain ' +
|
||||
'at least one non-/ character, got: "' + volume + '"');
|
||||
}
|
||||
|
||||
// third component is optional mode: 'ro' or 'rw'
|
||||
if (components.length === 3 && VALID_MODES.indexOf(components[2]) === -1) {
|
||||
return new errors.UsageError('invalid volume mode, got: "' + volume +
|
||||
'"');
|
||||
}
|
||||
|
||||
return {
|
||||
mode: components[2] || 'rw',
|
||||
mountpoint: components[1],
|
||||
name: components[0]
|
||||
};
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function do_create(subcmd, opts, args, cb) {
|
||||
if (opts.help) {
|
||||
@ -132,6 +185,37 @@ function do_create(subcmd, opts, args, cb) {
|
||||
next();
|
||||
},
|
||||
|
||||
/*
|
||||
* Make sure if volumes were passed, they're in the correct form.
|
||||
*/
|
||||
function parseVolumes(ctx, next) {
|
||||
var idx;
|
||||
var validationErr;
|
||||
var volume;
|
||||
var volumes = [];
|
||||
|
||||
if (!opts.volume) {
|
||||
next();
|
||||
return;
|
||||
}
|
||||
|
||||
for (idx = 0; idx < opts.volume.length; idx++) {
|
||||
volume = parseVolume(opts.volume[idx]);
|
||||
if (volume instanceof Error) {
|
||||
validationErr = volume;
|
||||
next(validationErr);
|
||||
return;
|
||||
}
|
||||
volumes.push(volume);
|
||||
}
|
||||
|
||||
if (volumes.length > 0) {
|
||||
ctx.volumes = volumes;
|
||||
}
|
||||
|
||||
next();
|
||||
},
|
||||
|
||||
/*
|
||||
* Determine `ctx.locality` according to what CloudAPI supports
|
||||
* based on `ctx.affinities` parsed earlier.
|
||||
@ -279,7 +363,8 @@ function do_create(subcmd, opts, args, cb) {
|
||||
image: ctx.img.id,
|
||||
'package': ctx.pkg && ctx.pkg.id,
|
||||
networks: ctx.nets && ctx.nets.map(
|
||||
function (net) { return net.id; })
|
||||
function (net) { return net.id; }),
|
||||
volumes: ctx.volumes && ctx.volumes
|
||||
};
|
||||
if (ctx.locality) {
|
||||
createOpts.locality = ctx.locality;
|
||||
@ -495,6 +580,12 @@ do_create.options = [
|
||||
names: ['json', 'j'],
|
||||
type: 'bool',
|
||||
help: 'JSON stream output.'
|
||||
},
|
||||
{
|
||||
names: ['volume', 'v'],
|
||||
type: 'arrayOfString',
|
||||
help: 'Mount a volume into the container (non-KVM only) ' +
|
||||
'<volume-name:/mount/point>[:access-mode]'
|
||||
}
|
||||
];
|
||||
|
||||
|
Reference in New Issue
Block a user