joyent/node-triton#197 Create triton image export command
This commit is contained in:
parent
33ff58c3d3
commit
17669f35ea
@ -7,6 +7,10 @@ Known issues:
|
|||||||
|
|
||||||
## not yet released
|
## not yet released
|
||||||
|
|
||||||
|
## 5.2.0
|
||||||
|
|
||||||
|
- [joyent/node-triton#197] Create triton image export command
|
||||||
|
|
||||||
## 5.1.1
|
## 5.1.1
|
||||||
|
|
||||||
- [joyent/node-triton#190] Fix `triton profile create|docker-setup` breakage
|
- [joyent/node-triton#190] Fix `triton profile create|docker-setup` breakage
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright 2015 Joyent, Inc.
|
* Copyright 2017 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/
|
||||||
@ -669,7 +669,32 @@ function createImageFromMachine(opts, cb) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export an image to Manta.
|
||||||
|
* <http://apidocs.joyent.com/cloudapi/#ExportImage>
|
||||||
|
*
|
||||||
|
* @param {Object} opts
|
||||||
|
* - {UUID} id Required. The id of the image to export.
|
||||||
|
* - {String} manta_path Required. The path in Manta to write the image.
|
||||||
|
* @param {Function} cb of the form `function (err, exportInfo, res)`
|
||||||
|
*/
|
||||||
|
CloudApi.prototype.exportImage = function exportImage(opts, cb) {
|
||||||
|
assert.uuid(opts.id, 'id');
|
||||||
|
assert.string(opts.manta_path, 'manta_path');
|
||||||
|
assert.func(cb, 'cb');
|
||||||
|
var data = {
|
||||||
|
action: 'export',
|
||||||
|
manta_path: opts.manta_path
|
||||||
|
};
|
||||||
|
|
||||||
|
this._request({
|
||||||
|
method: 'POST',
|
||||||
|
path: format('/%s/images/%s', this.account, opts.id),
|
||||||
|
data: data
|
||||||
|
}, function (err, req, res, body) {
|
||||||
|
cb(err, 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.
|
||||||
|
120
lib/do_image/do_export.js
Normal file
120
lib/do_image/do_export.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 2017 Joyent, Inc.
|
||||||
|
*
|
||||||
|
* `triton image export ...`
|
||||||
|
*/
|
||||||
|
|
||||||
|
var assert = require('assert-plus');
|
||||||
|
var format = require('util').format;
|
||||||
|
var vasync = require('vasync');
|
||||||
|
|
||||||
|
var common = require('../common');
|
||||||
|
var errors = require('../errors');
|
||||||
|
|
||||||
|
// ---- the command
|
||||||
|
|
||||||
|
function do_export(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 exportImage(ctx, next) {
|
||||||
|
log.trace({dryRun: opts.dry_run, manta_path: ctx.manta_path},
|
||||||
|
'image export path');
|
||||||
|
|
||||||
|
console.log('Exporting image %s to %s', args[0], args[1]);
|
||||||
|
|
||||||
|
if (opts.dry_run) {
|
||||||
|
next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tritonapi.exportImage({
|
||||||
|
image: args[0],
|
||||||
|
manta_path: args[1]
|
||||||
|
}, function (err, exportInfo) {
|
||||||
|
if (err) {
|
||||||
|
next(new errors.TritonError(err,
|
||||||
|
'error exporting image to manta'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.trace({exportInfo: exportInfo}, 'image export: exportInfo');
|
||||||
|
ctx.exportInfo = exportInfo;
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
function outputResults(ctx, next) {
|
||||||
|
if (opts.json) {
|
||||||
|
console.log(JSON.stringify(ctx.exportInfo));
|
||||||
|
} else {
|
||||||
|
console.log(' Manta URL: %s', ctx.exportInfo.manta_url);
|
||||||
|
console.log('Manifest path: %s', ctx.exportInfo.manifest_path);
|
||||||
|
console.log(' Image path: %s', ctx.exportInfo.image_path);
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
]}, function (err) {
|
||||||
|
cb(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
do_export.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 exporting.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
names: ['json', 'j'],
|
||||||
|
type: 'bool',
|
||||||
|
help: 'JSON stream output.'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
do_export.synopses = [
|
||||||
|
'{{name}} {{cmd}} [OPTIONS] IMAGE MANTA_PATH'
|
||||||
|
];
|
||||||
|
|
||||||
|
do_export.help = [
|
||||||
|
/* BEGIN JSSTYLED */
|
||||||
|
'Export an image.',
|
||||||
|
'',
|
||||||
|
'{{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).',
|
||||||
|
'',
|
||||||
|
'Note: Only images that are owned by the account can be exported.'
|
||||||
|
/* END JSSTYLED */
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
do_export.completionArgtypes = ['tritonimage', 'none'];
|
||||||
|
|
||||||
|
module.exports = do_export;
|
@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright 2015 Joyent, Inc.
|
* Copyright 2017 Joyent, Inc.
|
||||||
*
|
*
|
||||||
* `triton image ...`
|
* `triton image ...`
|
||||||
*/
|
*/
|
||||||
@ -35,6 +35,7 @@ function ImageCLI(top) {
|
|||||||
'get',
|
'get',
|
||||||
'create',
|
'create',
|
||||||
'delete',
|
'delete',
|
||||||
|
'export',
|
||||||
'wait'
|
'wait'
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
@ -50,6 +51,7 @@ ImageCLI.prototype.do_list = require('./do_list');
|
|||||||
ImageCLI.prototype.do_get = require('./do_get');
|
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_wait = require('./do_wait');
|
ImageCLI.prototype.do_wait = require('./do_wait');
|
||||||
|
|
||||||
|
|
||||||
|
@ -205,6 +205,25 @@ function _stepPkgId(arg, next) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A function appropriate for `vasync.pipeline` funcs that takes a `arg.image`
|
||||||
|
* image name, shortid, or uuid, and determines the image id (setting it
|
||||||
|
* as arg.imgId).
|
||||||
|
*/
|
||||||
|
function _stepImgId(arg, next) {
|
||||||
|
assert.object(arg.client, 'arg.client');
|
||||||
|
assert.string(arg.image, 'arg.image');
|
||||||
|
|
||||||
|
arg.client.getImage(arg.image, function (err, img) {
|
||||||
|
if (err) {
|
||||||
|
next(err);
|
||||||
|
} else {
|
||||||
|
arg.imgId = img.id;
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A function appropriate for `vasync.pipeline` funcs that takes a `arg.id`
|
* A function appropriate for `vasync.pipeline` funcs that takes a `arg.id`
|
||||||
* fwrule shortid or uuid, and determines the fwrule id (setting it
|
* fwrule shortid or uuid, and determines the fwrule id (setting it
|
||||||
@ -641,6 +660,62 @@ TritonApi.prototype.getImage = function getImage(opts, cb) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export and image to Manta.
|
||||||
|
*
|
||||||
|
* @param {Object} opts
|
||||||
|
* - {String} image The image UUID, name, or short ID. Required.
|
||||||
|
* - {String} manta_path The path in Manta where the image will be
|
||||||
|
* exported. Required.
|
||||||
|
* @param {Function} cb `function (err, exportInfo, res)`
|
||||||
|
* On failure `err` is an error instance, else it is null.
|
||||||
|
* On success: `exportInfo` is an object with three properties:
|
||||||
|
* - {String} manta_url The url of the Manta API endpoint where the
|
||||||
|
* image was exported.
|
||||||
|
* - {String} manifest_path The pathname in Manta of the exported image
|
||||||
|
* manifest.
|
||||||
|
* - {String} image_path The pathname in Manta of the exported image.
|
||||||
|
* and `res` is the CloudAPI `ExportImage` response.
|
||||||
|
*/
|
||||||
|
TritonApi.prototype.exportImage = function exportImage(opts, cb)
|
||||||
|
{
|
||||||
|
var self = this;
|
||||||
|
assert.object(opts, 'opts');
|
||||||
|
assert.string(opts.image, 'opts.image');
|
||||||
|
assert.string(opts.manta_path, 'opts.manta_path');
|
||||||
|
assert.func(cb, 'cb');
|
||||||
|
|
||||||
|
var res = null;
|
||||||
|
var exportInfo = null;
|
||||||
|
var arg = {
|
||||||
|
image: opts.image,
|
||||||
|
client: self
|
||||||
|
};
|
||||||
|
|
||||||
|
vasync.pipeline({arg: arg, funcs: [
|
||||||
|
_stepImgId,
|
||||||
|
function cloudApiExportImage(ctx, next) {
|
||||||
|
self.cloudapi.exportImage({
|
||||||
|
id: ctx.imgId, manta_path: opts.manta_path },
|
||||||
|
function (err, exportInfo_, res_) {
|
||||||
|
if (err) {
|
||||||
|
next(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
exportInfo = exportInfo_;
|
||||||
|
res = res_;
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
]}, function (err) {
|
||||||
|
if (err) {
|
||||||
|
cb(err, exportInfo, res);
|
||||||
|
} else {
|
||||||
|
cb(null, exportInfo, 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.
|
||||||
@ -2389,8 +2464,7 @@ TritonApi.prototype.rebootInstance = function rebootInstance(opts, cb) {
|
|||||||
var theRecord = null;
|
var theRecord = null;
|
||||||
for (var i = 0; i < audit.length; i++) {
|
for (var i = 0; i < audit.length; i++) {
|
||||||
if (audit[i].action === 'reboot' &&
|
if (audit[i].action === 'reboot' &&
|
||||||
Date.parse(audit[i].time) > resTime)
|
Date.parse(audit[i].time) > resTime) {
|
||||||
{
|
|
||||||
theRecord = audit[i];
|
theRecord = audit[i];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -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.1.1",
|
"version": "5.2.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": {
|
||||||
|
Reference in New Issue
Block a user