TRITON-116 node-triton image sharing
Reviewed by: Trent Mick <trentm@gmail.com> Approved by: Trent Mick <trentm@gmail.com>
This commit is contained in:
parent
e7c02436df
commit
3f243f8c8f
@ -6,6 +6,11 @@ Known issues:
|
|||||||
|
|
||||||
## not yet released
|
## not yet released
|
||||||
|
|
||||||
|
## 5.7.0
|
||||||
|
|
||||||
|
- [TRITON-116] node-triton image sharing. Adds `triton image share` and
|
||||||
|
`triton image unshare` commands.
|
||||||
|
|
||||||
## 5.6.1
|
## 5.6.1
|
||||||
|
|
||||||
- [PUBAPI-1470] volume objects should expose their creation timestamp in a
|
- [PUBAPI-1470] volume objects should expose their creation timestamp in a
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright 2017 Joyent, Inc.
|
* Copyright (c) 2018, Joyent, Inc.
|
||||||
*
|
*
|
||||||
* Client library for the SmartDataCenter Cloud API (cloudapi).
|
* Client library for the SmartDataCenter Cloud API (cloudapi).
|
||||||
* http://apidocs.joyent.com/cloudapi/
|
* http://apidocs.joyent.com/cloudapi/
|
||||||
@ -767,6 +767,33 @@ CloudApi.prototype.exportImage = function exportImage(opts, cb) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update an image.
|
||||||
|
* <http://apidocs.joyent.com/cloudapi/#UpdateImage>
|
||||||
|
*
|
||||||
|
* @param {Object} opts
|
||||||
|
* - {UUID} id Required. The id of the image to update.
|
||||||
|
* - {Object} fields Required. The fields to update in the image.
|
||||||
|
* @param {Function} cb of the form `function (err, body, res)`
|
||||||
|
*/
|
||||||
|
CloudApi.prototype.updateImage = function shareImage(opts, cb) {
|
||||||
|
assert.uuid(opts.id, 'id');
|
||||||
|
assert.object(opts.fields, 'fields');
|
||||||
|
assert.func(cb, 'cb');
|
||||||
|
|
||||||
|
this._request({
|
||||||
|
method: 'POST',
|
||||||
|
path: format('/%s/images/%s?action=update', this.account, opts.id),
|
||||||
|
data: opts.fields
|
||||||
|
}, function (err, req, res, body) {
|
||||||
|
if (err) {
|
||||||
|
cb(err, null, res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cb(null, body, res);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wait for an image to go one of a set of specfic states.
|
* Wait for an image to go one of a set of specfic states.
|
||||||
*
|
*
|
||||||
|
115
lib/do_image/do_share.js
Normal file
115
lib/do_image/do_share.js
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018, Joyent, Inc.
|
||||||
|
*
|
||||||
|
* `triton image share ...`
|
||||||
|
*/
|
||||||
|
|
||||||
|
var format = require('util').format;
|
||||||
|
var vasync = require('vasync');
|
||||||
|
|
||||||
|
var common = require('../common');
|
||||||
|
var errors = require('../errors');
|
||||||
|
|
||||||
|
// ---- the command
|
||||||
|
|
||||||
|
function do_share(subcmd, opts, args, cb) {
|
||||||
|
if (opts.help) {
|
||||||
|
this.do_help('help', {}, [subcmd], cb);
|
||||||
|
return;
|
||||||
|
} else if (args.length !== 2) {
|
||||||
|
cb(new errors.UsageError(
|
||||||
|
'incorrect number of args: expect 2, got ' + args.length));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var log = this.top.log;
|
||||||
|
var tritonapi = this.top.tritonapi;
|
||||||
|
|
||||||
|
vasync.pipeline({arg: {cli: this.top}, funcs: [
|
||||||
|
common.cliSetupTritonApi,
|
||||||
|
function shareImage(ctx, next) {
|
||||||
|
log.trace({dryRun: opts.dry_run, account: ctx.account},
|
||||||
|
'image share account');
|
||||||
|
|
||||||
|
if (opts.dry_run) {
|
||||||
|
next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tritonapi.shareImage({
|
||||||
|
image: args[0],
|
||||||
|
account: args[1]
|
||||||
|
}, function (err, img) {
|
||||||
|
if (err) {
|
||||||
|
next(new errors.TritonError(err, 'error sharing image'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.trace({img: img}, 'image share result');
|
||||||
|
|
||||||
|
if (opts.json) {
|
||||||
|
console.log(JSON.stringify(img));
|
||||||
|
} else {
|
||||||
|
console.log('Shared image %s with account %s',
|
||||||
|
args[0], args[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
]}, function (err) {
|
||||||
|
cb(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
do_share.options = [
|
||||||
|
{
|
||||||
|
names: ['help', 'h'],
|
||||||
|
type: 'bool',
|
||||||
|
help: 'Show this help.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
group: 'Other options'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
names: ['dry-run'],
|
||||||
|
type: 'bool',
|
||||||
|
help: 'Go through the motions without actually sharing.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
names: ['json', 'j'],
|
||||||
|
type: 'bool',
|
||||||
|
help: 'JSON stream output.'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
do_share.synopses = [
|
||||||
|
'{{name}} {{cmd}} [OPTIONS] IMAGE ACCOUNT'
|
||||||
|
];
|
||||||
|
|
||||||
|
do_share.help = [
|
||||||
|
/* BEGIN JSSTYLED */
|
||||||
|
'Share an image with another account.',
|
||||||
|
'',
|
||||||
|
'{{usage}}',
|
||||||
|
'',
|
||||||
|
'{{options}}',
|
||||||
|
'Where "IMAGE" is an image id (a full UUID), an image name (selects the',
|
||||||
|
'latest, by "published_at", image with that name), an image "name@version"',
|
||||||
|
'(selects latest match by "published_at"), or an image short ID (ID prefix).',
|
||||||
|
'',
|
||||||
|
'Where "ACCOUNT" is the full account UUID.',
|
||||||
|
'',
|
||||||
|
'Note: Only images that are owned by the account can be shared.'
|
||||||
|
/* END JSSTYLED */
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
do_share.completionArgtypes = ['tritonimage', 'none'];
|
||||||
|
|
||||||
|
module.exports = do_share;
|
115
lib/do_image/do_unshare.js
Normal file
115
lib/do_image/do_unshare.js
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018, Joyent, Inc.
|
||||||
|
*
|
||||||
|
* `triton image unshare ...`
|
||||||
|
*/
|
||||||
|
|
||||||
|
var format = require('util').format;
|
||||||
|
var vasync = require('vasync');
|
||||||
|
|
||||||
|
var common = require('../common');
|
||||||
|
var errors = require('../errors');
|
||||||
|
|
||||||
|
// ---- the command
|
||||||
|
|
||||||
|
function do_unshare(subcmd, opts, args, cb) {
|
||||||
|
if (opts.help) {
|
||||||
|
this.do_help('help', {}, [subcmd], cb);
|
||||||
|
return;
|
||||||
|
} else if (args.length !== 2) {
|
||||||
|
cb(new errors.UsageError(
|
||||||
|
'incorrect number of args: expect 2, got ' + args.length));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var log = this.top.log;
|
||||||
|
var tritonapi = this.top.tritonapi;
|
||||||
|
|
||||||
|
vasync.pipeline({arg: {cli: this.top}, funcs: [
|
||||||
|
common.cliSetupTritonApi,
|
||||||
|
function unshareImage(ctx, next) {
|
||||||
|
log.trace({dryRun: opts.dry_run, account: ctx.account},
|
||||||
|
'image unshare account');
|
||||||
|
|
||||||
|
if (opts.dry_run) {
|
||||||
|
next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tritonapi.unshareImage({
|
||||||
|
image: args[0],
|
||||||
|
account: args[1]
|
||||||
|
}, function (err, img) {
|
||||||
|
if (err) {
|
||||||
|
next(new errors.TritonError(err, 'error unsharing image'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.trace({img: img}, 'image unshare result');
|
||||||
|
|
||||||
|
if (opts.json) {
|
||||||
|
console.log(JSON.stringify(img));
|
||||||
|
} else {
|
||||||
|
console.log('Unshared image %s with account %s',
|
||||||
|
args[0], args[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
]}, function (err) {
|
||||||
|
cb(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
do_unshare.options = [
|
||||||
|
{
|
||||||
|
names: ['help', 'h'],
|
||||||
|
type: 'bool',
|
||||||
|
help: 'Show this help.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
group: 'Other options'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
names: ['dry-run'],
|
||||||
|
type: 'bool',
|
||||||
|
help: 'Go through the motions without actually sharing.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
names: ['json', 'j'],
|
||||||
|
type: 'bool',
|
||||||
|
help: 'JSON stream output.'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
do_unshare.synopses = [
|
||||||
|
'{{name}} {{cmd}} [OPTIONS] IMAGE ACCOUNT'
|
||||||
|
];
|
||||||
|
|
||||||
|
do_unshare.help = [
|
||||||
|
/* BEGIN JSSTYLED */
|
||||||
|
'Unshare an image with another account.',
|
||||||
|
'',
|
||||||
|
'{{usage}}',
|
||||||
|
'',
|
||||||
|
'{{options}}',
|
||||||
|
'Where "IMAGE" is an image id (a full UUID), an image name (selects the',
|
||||||
|
'latest, by "published_at", image with that name), an image "name@version"',
|
||||||
|
'(selects latest match by "published_at"), or an image short ID (ID prefix).',
|
||||||
|
'',
|
||||||
|
'Where "ACCOUNT" is the full account UUID.',
|
||||||
|
'',
|
||||||
|
'Note: Only images that are owned by the account can be unshared.'
|
||||||
|
/* END JSSTYLED */
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
do_unshare.completionArgtypes = ['tritonimage', 'none'];
|
||||||
|
|
||||||
|
module.exports = do_unshare;
|
@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright 2017 Joyent, Inc.
|
* Copyright (c) 2018, Joyent, Inc.
|
||||||
*
|
*
|
||||||
* `triton image ...`
|
* `triton image ...`
|
||||||
*/
|
*/
|
||||||
@ -36,6 +36,8 @@ function ImageCLI(top) {
|
|||||||
'create',
|
'create',
|
||||||
'delete',
|
'delete',
|
||||||
'export',
|
'export',
|
||||||
|
'share',
|
||||||
|
'unshare',
|
||||||
'wait'
|
'wait'
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
@ -52,6 +54,8 @@ ImageCLI.prototype.do_get = require('./do_get');
|
|||||||
ImageCLI.prototype.do_create = require('./do_create');
|
ImageCLI.prototype.do_create = require('./do_create');
|
||||||
ImageCLI.prototype.do_delete = require('./do_delete');
|
ImageCLI.prototype.do_delete = require('./do_delete');
|
||||||
ImageCLI.prototype.do_export = require('./do_export');
|
ImageCLI.prototype.do_export = require('./do_export');
|
||||||
|
ImageCLI.prototype.do_share = require('./do_share');
|
||||||
|
ImageCLI.prototype.do_unshare = require('./do_unshare');
|
||||||
ImageCLI.prototype.do_wait = require('./do_wait');
|
ImageCLI.prototype.do_wait = require('./do_wait');
|
||||||
|
|
||||||
|
|
||||||
|
109
lib/tritonapi.js
109
lib/tritonapi.js
@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright 2017 Joyent, Inc.
|
* Copyright (c) 2018, Joyent, Inc.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* BEGIN JSSTYLED */
|
/* BEGIN JSSTYLED */
|
||||||
@ -233,10 +233,10 @@ function _stepPkgId(arg, next) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A function appropriate for `vasync.pipeline` funcs that takes a `arg.image`
|
* A function appropriate for `vasync.pipeline` funcs that takes a `arg.image`
|
||||||
* image name, shortid, or uuid, and determines the image id (setting it
|
* image name, shortid, or uuid, and determines the image object (setting it
|
||||||
* as arg.imgId).
|
* as arg.img).
|
||||||
*/
|
*/
|
||||||
function _stepImgId(arg, next) {
|
function _stepImg(arg, next) {
|
||||||
assert.object(arg.client, 'arg.client');
|
assert.object(arg.client, 'arg.client');
|
||||||
assert.string(arg.image, 'arg.image');
|
assert.string(arg.image, 'arg.image');
|
||||||
|
|
||||||
@ -244,7 +244,7 @@ function _stepImgId(arg, next) {
|
|||||||
if (err) {
|
if (err) {
|
||||||
next(err);
|
next(err);
|
||||||
} else {
|
} else {
|
||||||
arg.imgId = img.id;
|
arg.img = img;
|
||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -745,10 +745,10 @@ TritonApi.prototype.exportImage = function exportImage(opts, cb)
|
|||||||
};
|
};
|
||||||
|
|
||||||
vasync.pipeline({arg: arg, funcs: [
|
vasync.pipeline({arg: arg, funcs: [
|
||||||
_stepImgId,
|
_stepImg,
|
||||||
function cloudApiExportImage(ctx, next) {
|
function cloudApiExportImage(ctx, next) {
|
||||||
self.cloudapi.exportImage({
|
self.cloudapi.exportImage({
|
||||||
id: ctx.imgId, manta_path: opts.manta_path },
|
id: ctx.img.id, manta_path: opts.manta_path },
|
||||||
function (err, exportInfo_, res_) {
|
function (err, exportInfo_, res_) {
|
||||||
if (err) {
|
if (err) {
|
||||||
next(err);
|
next(err);
|
||||||
@ -769,6 +769,101 @@ TritonApi.prototype.exportImage = function exportImage(opts, cb)
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Share an image with another account.
|
||||||
|
*
|
||||||
|
* @param {Object} opts
|
||||||
|
* - {String} image The image UUID, name, or short ID. Required.
|
||||||
|
* - {String} account The account UUID. Required.
|
||||||
|
* @param {Function} cb `function (err, img)`
|
||||||
|
* On failure `err` is an error instance, else it is null.
|
||||||
|
* On success: `img` is an image object.
|
||||||
|
*/
|
||||||
|
TritonApi.prototype.shareImage = function shareImage(opts, cb)
|
||||||
|
{
|
||||||
|
var self = this;
|
||||||
|
assert.object(opts, 'opts');
|
||||||
|
assert.string(opts.image, 'opts.image');
|
||||||
|
assert.string(opts.account, 'opts.account');
|
||||||
|
assert.func(cb, 'cb');
|
||||||
|
|
||||||
|
var arg = {
|
||||||
|
image: opts.image,
|
||||||
|
client: self
|
||||||
|
};
|
||||||
|
var res;
|
||||||
|
|
||||||
|
vasync.pipeline({arg: arg, funcs: [
|
||||||
|
_stepImg,
|
||||||
|
function validateAcl(ctx, next) {
|
||||||
|
ctx.acl = ctx.img.acl && ctx.img.acl.slice() || [];
|
||||||
|
if (ctx.acl.indexOf(opts.account) === -1) {
|
||||||
|
ctx.acl.push(opts.account);
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
},
|
||||||
|
function cloudApiShareImage(ctx, next) {
|
||||||
|
self.cloudapi.updateImage({id: ctx.img.id, fields: {acl: ctx.acl}},
|
||||||
|
function _updateImageCb(err, img) {
|
||||||
|
res = img;
|
||||||
|
next(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
]}, function (err) {
|
||||||
|
cb(err, res);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unshare an image with another account.
|
||||||
|
*
|
||||||
|
* @param {Object} opts
|
||||||
|
* - {String} image The image UUID, name, or short ID. Required.
|
||||||
|
* - {String} account The account UUID. Required.
|
||||||
|
* @param {Function} cb `function (err, img)`
|
||||||
|
* On failure `err` is an error instance, else it is null.
|
||||||
|
* On success: `img` is an image object.
|
||||||
|
*/
|
||||||
|
TritonApi.prototype.unshareImage = function unshareImage(opts, cb)
|
||||||
|
{
|
||||||
|
var self = this;
|
||||||
|
assert.object(opts, 'opts');
|
||||||
|
assert.string(opts.image, 'opts.image');
|
||||||
|
assert.string(opts.account, 'opts.account');
|
||||||
|
assert.func(cb, 'cb');
|
||||||
|
|
||||||
|
var arg = {
|
||||||
|
image: opts.image,
|
||||||
|
client: self
|
||||||
|
};
|
||||||
|
var res;
|
||||||
|
|
||||||
|
vasync.pipeline({arg: arg, funcs: [
|
||||||
|
_stepImg,
|
||||||
|
function validateAcl(ctx, next) {
|
||||||
|
assert.object(ctx.img, 'img');
|
||||||
|
ctx.acl = ctx.img.acl && ctx.img.acl.slice() || [];
|
||||||
|
var aclIdx = ctx.acl.indexOf(opts.account);
|
||||||
|
if (aclIdx === -1) {
|
||||||
|
cb(new errors.TritonError(format('image is not shared with %s',
|
||||||
|
opts.account)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ctx.acl.splice(aclIdx, 1);
|
||||||
|
next();
|
||||||
|
},
|
||||||
|
function cloudApiUnshareImage(ctx, next) {
|
||||||
|
self.cloudapi.updateImage({id: ctx.img.id, fields: {acl: ctx.acl}},
|
||||||
|
function _updateImageCb(err, img) {
|
||||||
|
res = img;
|
||||||
|
next(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
]}, function (err) {
|
||||||
|
cb(err, res);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an active package by ID, exact name, or short ID, in that order.
|
* Get an active package by ID, exact name, or short ID, in that order.
|
||||||
*
|
*
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "triton",
|
"name": "triton",
|
||||||
"description": "Joyent Triton CLI and client (https://www.joyent.com/triton)",
|
"description": "Joyent Triton CLI and client (https://www.joyent.com/triton)",
|
||||||
"version": "5.6.1",
|
"version": "5.7.0",
|
||||||
"author": "Joyent (joyent.com)",
|
"author": "Joyent (joyent.com)",
|
||||||
"homepage": "https://github.com/joyent/node-triton",
|
"homepage": "https://github.com/joyent/node-triton",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -33,7 +33,8 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"tape": "4.2.0",
|
"tape": "4.2.0",
|
||||||
"tap-summary": "3.0.2"
|
"tap-summary": "3.0.2",
|
||||||
|
"uuid": "3.2.1"
|
||||||
},
|
},
|
||||||
"main": "./lib",
|
"main": "./lib",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright 2016, Joyent, Inc.
|
* Copyright (c) 2018, Joyent, Inc.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -15,6 +15,7 @@
|
|||||||
var format = require('util').format;
|
var format = require('util').format;
|
||||||
var os = require('os');
|
var os = require('os');
|
||||||
var test = require('tape');
|
var test = require('tape');
|
||||||
|
var uuid = require('uuid');
|
||||||
var vasync = require('vasync');
|
var vasync = require('vasync');
|
||||||
|
|
||||||
var common = require('../../lib/common');
|
var common = require('../../lib/common');
|
||||||
@ -199,6 +200,62 @@ test('triton image ...', testOpts, function (tt) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
tt.test(' triton image share ...', function (t) {
|
||||||
|
var dummyUuid = uuid.v4();
|
||||||
|
var argv = ['image', 'share', img.id, dummyUuid];
|
||||||
|
h.safeTriton(t, argv, function (err) {
|
||||||
|
if (err) {
|
||||||
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
argv = ['image', 'get', '-j', img.id];
|
||||||
|
h.safeTriton(t, argv, function (err2, stdout2) {
|
||||||
|
t.ifErr(err2, 'image get response');
|
||||||
|
if (err2) {
|
||||||
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var result = JSON.parse(stdout2);
|
||||||
|
t.ok(result, 'image share result');
|
||||||
|
t.ok(result.acl, 'image share result.acl');
|
||||||
|
if (result.acl && Array.isArray(result.acl)) {
|
||||||
|
t.notEqual(result.acl.indexOf(dummyUuid), -1,
|
||||||
|
'image share result.acl contains uuid');
|
||||||
|
} else {
|
||||||
|
t.fail('image share result does not contain acl array');
|
||||||
|
}
|
||||||
|
unshareImage();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function unshareImage() {
|
||||||
|
argv = ['image', 'unshare', img.id, dummyUuid];
|
||||||
|
h.safeTriton(t, argv, function (err) {
|
||||||
|
if (err) {
|
||||||
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
argv = ['image', 'get', '-j', img.id];
|
||||||
|
h.safeTriton(t, argv, function (err2, stdout2) {
|
||||||
|
t.ifErr(err2, 'image get response');
|
||||||
|
if (err2) {
|
||||||
|
t.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var result = JSON.parse(stdout2);
|
||||||
|
t.ok(result, 'image unshare result');
|
||||||
|
if (result.acl && Array.isArray(result.acl)) {
|
||||||
|
t.equal(result.acl.indexOf(dummyUuid), -1,
|
||||||
|
'image unshare result.acl should not contain uuid');
|
||||||
|
} else {
|
||||||
|
t.equal(result.acl, undefined, 'image has no acl');
|
||||||
|
}
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// TODO: Once have `triton ssh ...` working in test suite without hangs,
|
// TODO: Once have `triton ssh ...` working in test suite without hangs,
|
||||||
// then want to check that the created VM has the markerFile.
|
// then want to check that the created VM has the markerFile.
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user