mirror of
https://github.com/balena-io/balena-cli.git
synced 2024-12-19 05:37:51 +00:00
allow prebuilding the device config and reusing it
This commit is contained in:
parent
9fb5b52069
commit
2e7e033bb9
2
.gitignore
vendored
2
.gitignore
vendored
@ -31,3 +31,5 @@ resinrc.yml
|
|||||||
.idea
|
.idea
|
||||||
.vscode
|
.vscode
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
||||||
|
/tmp
|
||||||
|
@ -15,6 +15,9 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
- Actually tolerate the `--yes` param to `resin device init`
|
- Actually tolerate the `--yes` param to `resin device init`
|
||||||
- Allows passing `--drive` to `resin device init`
|
- Allows passing `--drive` to `resin device init`
|
||||||
- List detected drives with `resin os available-drives`
|
- 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
|
### Fixed
|
||||||
|
|
||||||
|
@ -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.',
|
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',
|
parameter: 'drive',
|
||||||
alias: 'd'
|
alias: 'd'
|
||||||
|
}, {
|
||||||
|
signature: 'config',
|
||||||
|
description: 'stringified JSON with the device config, see `resin os build-config`',
|
||||||
|
parameter: 'config'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
permission: 'user',
|
permission: 'user',
|
||||||
@ -310,7 +314,9 @@ exports.init = {
|
|||||||
return capitanoRunAsync("device register " + application.app_name).then(resin.models.device.get).tap(function(device) {
|
return capitanoRunAsync("device register " + application.app_name).then(resin.models.device.get).tap(function(device) {
|
||||||
var configureCommand;
|
var configureCommand;
|
||||||
configureCommand = "os configure '" + tempPath + "' " + device.uuid;
|
configureCommand = "os configure '" + tempPath + "' " + device.uuid;
|
||||||
if (options.advanced) {
|
if (options.config) {
|
||||||
|
configureCommand += " --config '" + options.config + "'";
|
||||||
|
} else if (options.advanced) {
|
||||||
configureCommand += ' --advanced';
|
configureCommand += ' --advanced';
|
||||||
}
|
}
|
||||||
return capitanoRunAsync(configureCommand).then(function() {
|
return capitanoRunAsync(configureCommand).then(function() {
|
||||||
|
@ -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
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
var _, commandOptions, formatVersion, initWarningMessage, resolveVersion;
|
var INIT_WARNING_MESSAGE, _, buildConfig, commandOptions, formatVersion, resolveVersion;
|
||||||
|
|
||||||
commandOptions = require('./command-options');
|
commandOptions = require('./command-options');
|
||||||
|
|
||||||
@ -135,10 +135,34 @@ exports.download = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.configure = {
|
buildConfig = function(image, deviceType, advanced) {
|
||||||
signature: 'os configure <image> <uuid>',
|
var form, helpers;
|
||||||
description: 'configure an os image',
|
if (advanced == null) {
|
||||||
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',
|
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',
|
permission: 'user',
|
||||||
options: [
|
options: [
|
||||||
{
|
{
|
||||||
@ -146,38 +170,58 @@ exports.configure = {
|
|||||||
description: 'show advanced commands',
|
description: 'show advanced commands',
|
||||||
boolean: true,
|
boolean: true,
|
||||||
alias: 'v'
|
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) {
|
action: function(params, options, done) {
|
||||||
var form, helpers, init, resin;
|
var Promise, fs, writeFileAsync;
|
||||||
resin = require('resin-sdk-preconfigured');
|
fs = require('fs');
|
||||||
form = require('resin-cli-form');
|
Promise = require('bluebird');
|
||||||
init = require('resin-device-init');
|
writeFileAsync = Promise.promisify(fs.writeFile);
|
||||||
helpers = require('../utils/helpers');
|
return buildConfig(params.image, params['device-type'], options.advanced).then(function(answers) {
|
||||||
console.info('Configuring operating system image');
|
return writeFileAsync(options.output, JSON.stringify(answers, null, 4));
|
||||||
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);
|
|
||||||
});
|
|
||||||
}).nodeify(done);
|
}).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 = {
|
exports.availableDrives = {
|
||||||
signature: 'os available-drives',
|
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 = {
|
exports.initialize = {
|
||||||
signature: 'os initialize <image>',
|
signature: 'os initialize <image>',
|
||||||
description: 'initialize an os 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',
|
permission: 'user',
|
||||||
options: [
|
options: [
|
||||||
commandOptions.yes, {
|
commandOptions.yes, {
|
||||||
@ -238,7 +284,7 @@ exports.initialize = {
|
|||||||
form = require('resin-cli-form');
|
form = require('resin-cli-form');
|
||||||
patterns = require('../utils/patterns');
|
patterns = require('../utils/patterns');
|
||||||
helpers = require('../utils/helpers');
|
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) {
|
return helpers.getManifest(params.image, options.type).then(function(manifest) {
|
||||||
var ref;
|
var ref;
|
||||||
return (ref = manifest.initialization) != null ? ref.options : void 0;
|
return (ref = manifest.initialization) != null ? ref.options : void 0;
|
||||||
|
@ -172,6 +172,8 @@ capitano.command(actions.os.availableDrives);
|
|||||||
|
|
||||||
capitano.command(actions.os.download);
|
capitano.command(actions.os.download);
|
||||||
|
|
||||||
|
capitano.command(actions.os.buildConfig);
|
||||||
|
|
||||||
capitano.command(actions.os.configure);
|
capitano.command(actions.os.configure);
|
||||||
|
|
||||||
capitano.command(actions.os.initialize);
|
capitano.command(actions.os.initialize);
|
||||||
|
@ -380,6 +380,11 @@ exports.init =
|
|||||||
parameter: 'drive'
|
parameter: 'drive'
|
||||||
alias: 'd'
|
alias: 'd'
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
signature: 'config'
|
||||||
|
description: 'stringified JSON with the device config, see `resin os build-config`'
|
||||||
|
parameter: 'config'
|
||||||
|
}
|
||||||
]
|
]
|
||||||
permission: 'user'
|
permission: 'user'
|
||||||
action: (params, options, done) ->
|
action: (params, options, done) ->
|
||||||
@ -412,7 +417,9 @@ exports.init =
|
|||||||
.then(resin.models.device.get)
|
.then(resin.models.device.get)
|
||||||
.tap (device) ->
|
.tap (device) ->
|
||||||
configureCommand = "os configure '#{tempPath}' #{device.uuid}"
|
configureCommand = "os configure '#{tempPath}' #{device.uuid}"
|
||||||
if options.advanced
|
if options.config
|
||||||
|
configureCommand += " --config '#{options.config}'"
|
||||||
|
else if options.advanced
|
||||||
configureCommand += ' --advanced'
|
configureCommand += ' --advanced'
|
||||||
capitanoRunAsync(configureCommand)
|
capitanoRunAsync(configureCommand)
|
||||||
.then ->
|
.then ->
|
||||||
|
@ -144,11 +144,65 @@ exports.download =
|
|||||||
console.info('The image was downloaded successfully')
|
console.info('The image was downloaded successfully')
|
||||||
.nodeify(done)
|
.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 =
|
exports.configure =
|
||||||
signature: 'os configure <image> <uuid>'
|
signature: 'os configure <image> <uuid>'
|
||||||
description: 'configure an os image'
|
description: 'configure an os image'
|
||||||
help: '''
|
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:
|
Examples:
|
||||||
|
|
||||||
@ -156,41 +210,32 @@ exports.configure =
|
|||||||
'''
|
'''
|
||||||
permission: 'user'
|
permission: 'user'
|
||||||
options: [
|
options: [
|
||||||
signature: 'advanced'
|
{
|
||||||
description: 'show advanced commands'
|
signature: 'advanced'
|
||||||
boolean: true
|
description: 'show advanced commands'
|
||||||
alias: 'v'
|
boolean: true
|
||||||
|
alias: 'v'
|
||||||
|
}
|
||||||
|
{
|
||||||
|
signature: 'config'
|
||||||
|
description: 'stringified JSON with the device config, see `resin os build-config`'
|
||||||
|
parameter: 'config'
|
||||||
|
}
|
||||||
]
|
]
|
||||||
action: (params, options, done) ->
|
action: (params, options, done) ->
|
||||||
resin = require('resin-sdk-preconfigured')
|
resin = require('resin-sdk-preconfigured')
|
||||||
form = require('resin-cli-form')
|
|
||||||
init = require('resin-device-init')
|
init = require('resin-device-init')
|
||||||
helpers = require('../utils/helpers')
|
helpers = require('../utils/helpers')
|
||||||
|
|
||||||
console.info('Configuring operating system image')
|
console.info('Configuring operating system image')
|
||||||
resin.models.device.get(params.uuid).then (device) ->
|
resin.models.device.get(params.uuid).then (device) ->
|
||||||
helpers.getManifest(params.image, device.device_type)
|
if options.config
|
||||||
.get('options')
|
return JSON.parse(options.config)
|
||||||
.then (questions) ->
|
buildConfig(params.image, device.device_type, options.advanced)
|
||||||
|
.then (answers) ->
|
||||||
if not options.advanced
|
init.configure(params.image, params.uuid, answers).then(helpers.osProgressHandler)
|
||||||
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)
|
|
||||||
.nodeify(done)
|
.nodeify(done)
|
||||||
|
|
||||||
initWarningMessage = '''
|
|
||||||
Note: Initializing the device may ask for administrative permissions
|
|
||||||
because we need to access the raw devices directly.
|
|
||||||
'''
|
|
||||||
|
|
||||||
exports.availableDrives =
|
exports.availableDrives =
|
||||||
# TODO: dedupe with https://github.com/resin-io-modules/resin-cli-visuals/blob/master/lib/widgets/drive/index.coffee
|
# TODO: dedupe with https://github.com/resin-io-modules/resin-cli-visuals/blob/master/lib/widgets/drive/index.coffee
|
||||||
signature: 'os available-drives'
|
signature: 'os available-drives'
|
||||||
@ -217,6 +262,10 @@ exports.availableDrives =
|
|||||||
drives.forEach (drive) ->
|
drives.forEach (drive) ->
|
||||||
console.log(formatDrive(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 =
|
exports.initialize =
|
||||||
signature: 'os initialize <image>'
|
signature: 'os initialize <image>'
|
||||||
@ -224,7 +273,7 @@ exports.initialize =
|
|||||||
help: """
|
help: """
|
||||||
Use this command to initialize a device with previously configured operating system image.
|
Use this command to initialize a device with previously configured operating system image.
|
||||||
|
|
||||||
#{initWarningMessage}
|
#{INIT_WARNING_MESSAGE}
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
|
|
||||||
@ -257,7 +306,7 @@ exports.initialize =
|
|||||||
console.info("""
|
console.info("""
|
||||||
Initializing device
|
Initializing device
|
||||||
|
|
||||||
#{initWarningMessage}
|
#{INIT_WARNING_MESSAGE}
|
||||||
""")
|
""")
|
||||||
helpers.getManifest(params.image, options.type)
|
helpers.getManifest(params.image, options.type)
|
||||||
.then (manifest) ->
|
.then (manifest) ->
|
||||||
|
@ -138,6 +138,7 @@ capitano.command(actions.env.remove)
|
|||||||
capitano.command(actions.os.versions)
|
capitano.command(actions.os.versions)
|
||||||
capitano.command(actions.os.availableDrives)
|
capitano.command(actions.os.availableDrives)
|
||||||
capitano.command(actions.os.download)
|
capitano.command(actions.os.download)
|
||||||
|
capitano.command(actions.os.buildConfig)
|
||||||
capitano.command(actions.os.configure)
|
capitano.command(actions.os.configure)
|
||||||
capitano.command(actions.os.initialize)
|
capitano.command(actions.os.initialize)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user