allow prebuilding the device config and reusing it

This commit is contained in:
Eugene Mirotin 2017-06-12 11:42:08 +03:00
parent 9fb5b52069
commit 2e7e033bb9
8 changed files with 178 additions and 62 deletions

2
.gitignore vendored
View File

@ -31,3 +31,5 @@ resinrc.yml
.idea
.vscode
.DS_Store
/tmp

View File

@ -15,6 +15,9 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- Actually tolerate the `--yes` param to `resin device init`
- Allows passing `--drive` to `resin device init`
- List detected drives with `resin os available-drives`
- Add the `resin os build-config` method to pass the interactive config step once
and reuse the built file for consequent `resin os configure` calls (added the new `--config` param to it),
and for `resin device init` (same `--config` param)
### Fixed

View File

@ -276,6 +276,10 @@ exports.init = {
description: 'the drive to write the image to, like /dev/sdb. Careful with this as you can erase your hard drive. Check `resin os available-drives` for available options.',
parameter: 'drive',
alias: 'd'
}, {
signature: 'config',
description: 'stringified JSON with the device config, see `resin os build-config`',
parameter: 'config'
}
],
permission: 'user',
@ -310,7 +314,9 @@ exports.init = {
return capitanoRunAsync("device register " + application.app_name).then(resin.models.device.get).tap(function(device) {
var configureCommand;
configureCommand = "os configure '" + tempPath + "' " + device.uuid;
if (options.advanced) {
if (options.config) {
configureCommand += " --config '" + options.config + "'";
} else if (options.advanced) {
configureCommand += ' --advanced';
}
return capitanoRunAsync(configureCommand).then(function() {

View File

@ -15,7 +15,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
var _, commandOptions, formatVersion, initWarningMessage, resolveVersion;
var INIT_WARNING_MESSAGE, _, buildConfig, commandOptions, formatVersion, resolveVersion;
commandOptions = require('./command-options');
@ -135,10 +135,34 @@ exports.download = {
}
};
exports.configure = {
signature: 'os configure <image> <uuid>',
description: 'configure an os image',
help: 'Use this command to configure a previously download operating system image with a device.\n\nExamples:\n\n $ resin os configure ../path/rpi.img 7cf02a6',
buildConfig = function(image, deviceType, advanced) {
var form, helpers;
if (advanced == null) {
advanced = false;
}
form = require('resin-cli-form');
helpers = require('../utils/helpers');
return helpers.getManifest(image, deviceType).get('options').then(function(questions) {
var advancedGroup, override;
if (!advanced) {
advancedGroup = _.findWhere(questions, {
name: 'advanced',
isGroup: true
});
if (advancedGroup != null) {
override = helpers.getGroupDefaults(advancedGroup);
}
}
return form.run(questions, {
override: override
});
});
};
exports.buildConfig = {
signature: 'os build-config <image> <device-type>',
description: 'build the OS config and save it to the JSON file',
help: 'Use this command to prebuild the OS config once and skip the interactive part of `resin os configure`.\n\nExamples:\n\n $ resin os build-config ../path/rpi3.img raspberrypi3 --output rpi3-config.json\n $ resin os configure ../path/rpi3.img 7cf02a6 --config "$(cat rpi3-config.json)"',
permission: 'user',
options: [
{
@ -146,38 +170,58 @@ exports.configure = {
description: 'show advanced commands',
boolean: true,
alias: 'v'
}, {
signature: 'output',
description: 'the path to the output JSON file',
alias: 'o',
required: 'the output path is required',
parameter: 'output'
}
],
action: function(params, options, done) {
var form, helpers, init, resin;
resin = require('resin-sdk-preconfigured');
form = require('resin-cli-form');
init = require('resin-device-init');
helpers = require('../utils/helpers');
console.info('Configuring operating system image');
return resin.models.device.get(params.uuid).then(function(device) {
return helpers.getManifest(params.image, device.device_type).get('options').then(function(questions) {
var advancedGroup, override;
if (!options.advanced) {
advancedGroup = _.findWhere(questions, {
name: 'advanced',
isGroup: true
});
if (advancedGroup != null) {
override = helpers.getGroupDefaults(advancedGroup);
}
}
return form.run(questions, {
override: override
});
}).then(function(answers) {
return init.configure(params.image, params.uuid, answers).then(helpers.osProgressHandler);
});
var Promise, fs, writeFileAsync;
fs = require('fs');
Promise = require('bluebird');
writeFileAsync = Promise.promisify(fs.writeFile);
return buildConfig(params.image, params['device-type'], options.advanced).then(function(answers) {
return writeFileAsync(options.output, JSON.stringify(answers, null, 4));
}).nodeify(done);
}
};
initWarningMessage = 'Note: Initializing the device may ask for administrative permissions\nbecause we need to access the raw devices directly.';
exports.configure = {
signature: 'os configure <image> <uuid>',
description: 'configure an os image',
help: 'Use this command to configure a previously downloaded operating system image for the specific device.\n\nExamples:\n\n $ resin os configure ../path/rpi.img 7cf02a6',
permission: 'user',
options: [
{
signature: 'advanced',
description: 'show advanced commands',
boolean: true,
alias: 'v'
}, {
signature: 'config',
description: 'stringified JSON with the device config, see `resin os build-config`',
parameter: 'config'
}
],
action: function(params, options, done) {
var helpers, init, resin;
resin = require('resin-sdk-preconfigured');
init = require('resin-device-init');
helpers = require('../utils/helpers');
console.info('Configuring operating system image');
return resin.models.device.get(params.uuid).then(function(device) {
if (options.config) {
return JSON.parse(options.config);
}
return buildConfig(params.image, device.device_type, options.advanced);
}).then(function(answers) {
return init.configure(params.image, params.uuid, answers).then(helpers.osProgressHandler);
}).nodeify(done);
}
};
exports.availableDrives = {
signature: 'os available-drives',
@ -212,10 +256,12 @@ exports.availableDrives = {
}
};
INIT_WARNING_MESSAGE = 'Note: Initializing the device may ask for administrative permissions\nbecause we need to access the raw devices directly.';
exports.initialize = {
signature: 'os initialize <image>',
description: 'initialize an os image',
help: "Use this command to initialize a device with previously configured operating system image.\n\n" + initWarningMessage + "\n\nExamples:\n\n $ resin os initialize ../path/rpi.img --type 'raspberry-pi'",
help: "Use this command to initialize a device with previously configured operating system image.\n\n" + INIT_WARNING_MESSAGE + "\n\nExamples:\n\n $ resin os initialize ../path/rpi.img --type 'raspberry-pi'",
permission: 'user',
options: [
commandOptions.yes, {
@ -238,7 +284,7 @@ exports.initialize = {
form = require('resin-cli-form');
patterns = require('../utils/patterns');
helpers = require('../utils/helpers');
console.info("Initializing device\n\n" + initWarningMessage);
console.info("Initializing device\n\n" + INIT_WARNING_MESSAGE);
return helpers.getManifest(params.image, options.type).then(function(manifest) {
var ref;
return (ref = manifest.initialization) != null ? ref.options : void 0;

View File

@ -172,6 +172,8 @@ capitano.command(actions.os.availableDrives);
capitano.command(actions.os.download);
capitano.command(actions.os.buildConfig);
capitano.command(actions.os.configure);
capitano.command(actions.os.initialize);

View File

@ -380,6 +380,11 @@ exports.init =
parameter: 'drive'
alias: 'd'
}
{
signature: 'config'
description: 'stringified JSON with the device config, see `resin os build-config`'
parameter: 'config'
}
]
permission: 'user'
action: (params, options, done) ->
@ -412,7 +417,9 @@ exports.init =
.then(resin.models.device.get)
.tap (device) ->
configureCommand = "os configure '#{tempPath}' #{device.uuid}"
if options.advanced
if options.config
configureCommand += " --config '#{options.config}'"
else if options.advanced
configureCommand += ' --advanced'
capitanoRunAsync(configureCommand)
.then ->

View File

@ -144,11 +144,65 @@ exports.download =
console.info('The image was downloaded successfully')
.nodeify(done)
buildConfig = (image, deviceType, advanced = false) ->
form = require('resin-cli-form')
helpers = require('../utils/helpers')
helpers.getManifest(image, deviceType)
.get('options')
.then (questions) ->
if not advanced
advancedGroup = _.findWhere questions,
name: 'advanced'
isGroup: true
if advancedGroup?
override = helpers.getGroupDefaults(advancedGroup)
return form.run(questions, { override })
exports.buildConfig =
signature: 'os build-config <image> <device-type>'
description: 'build the OS config and save it to the JSON file'
help: '''
Use this command to prebuild the OS config once and skip the interactive part of `resin os configure`.
Examples:
$ resin os build-config ../path/rpi3.img raspberrypi3 --output rpi3-config.json
$ resin os configure ../path/rpi3.img 7cf02a6 --config "$(cat rpi3-config.json)"
'''
permission: 'user'
options: [
{
signature: 'advanced'
description: 'show advanced commands'
boolean: true
alias: 'v'
}
{
signature: 'output'
description: 'the path to the output JSON file'
alias: 'o'
required: 'the output path is required'
parameter: 'output'
}
]
action: (params, options, done) ->
fs = require('fs')
Promise = require('bluebird')
writeFileAsync = Promise.promisify(fs.writeFile)
buildConfig(params.image, params['device-type'], options.advanced)
.then (answers) ->
writeFileAsync(options.output, JSON.stringify(answers, null, 4))
.nodeify(done)
exports.configure =
signature: 'os configure <image> <uuid>'
description: 'configure an os image'
help: '''
Use this command to configure a previously download operating system image with a device.
Use this command to configure a previously downloaded operating system image for the specific device.
Examples:
@ -156,41 +210,32 @@ exports.configure =
'''
permission: 'user'
options: [
signature: 'advanced'
description: 'show advanced commands'
boolean: true
alias: 'v'
{
signature: 'advanced'
description: 'show advanced commands'
boolean: true
alias: 'v'
}
{
signature: 'config'
description: 'stringified JSON with the device config, see `resin os build-config`'
parameter: 'config'
}
]
action: (params, options, done) ->
resin = require('resin-sdk-preconfigured')
form = require('resin-cli-form')
init = require('resin-device-init')
helpers = require('../utils/helpers')
console.info('Configuring operating system image')
resin.models.device.get(params.uuid).then (device) ->
helpers.getManifest(params.image, device.device_type)
.get('options')
.then (questions) ->
if not options.advanced
advancedGroup = _.findWhere questions,
name: 'advanced'
isGroup: true
if advancedGroup?
override = helpers.getGroupDefaults(advancedGroup)
return form.run(questions, { override })
.then (answers) ->
init.configure(params.image, params.uuid, answers).then(helpers.osProgressHandler)
if options.config
return JSON.parse(options.config)
buildConfig(params.image, device.device_type, options.advanced)
.then (answers) ->
init.configure(params.image, params.uuid, answers).then(helpers.osProgressHandler)
.nodeify(done)
initWarningMessage = '''
Note: Initializing the device may ask for administrative permissions
because we need to access the raw devices directly.
'''
exports.availableDrives =
# TODO: dedupe with https://github.com/resin-io-modules/resin-cli-visuals/blob/master/lib/widgets/drive/index.coffee
signature: 'os available-drives'
@ -217,6 +262,10 @@ exports.availableDrives =
drives.forEach (drive) ->
console.log(formatDrive(drive))
INIT_WARNING_MESSAGE = '''
Note: Initializing the device may ask for administrative permissions
because we need to access the raw devices directly.
'''
exports.initialize =
signature: 'os initialize <image>'
@ -224,7 +273,7 @@ exports.initialize =
help: """
Use this command to initialize a device with previously configured operating system image.
#{initWarningMessage}
#{INIT_WARNING_MESSAGE}
Examples:
@ -257,7 +306,7 @@ exports.initialize =
console.info("""
Initializing device
#{initWarningMessage}
#{INIT_WARNING_MESSAGE}
""")
helpers.getManifest(params.image, options.type)
.then (manifest) ->

View File

@ -138,6 +138,7 @@ capitano.command(actions.env.remove)
capitano.command(actions.os.versions)
capitano.command(actions.os.availableDrives)
capitano.command(actions.os.download)
capitano.command(actions.os.buildConfig)
capitano.command(actions.os.configure)
capitano.command(actions.os.initialize)