mirror of
https://github.com/balena-io/balena-cli.git
synced 2025-02-21 01:42:26 +00:00
Merge pull request #1047 from balena-io/1013-os-configure-device-type
Add explicit device type option to `os configure` & `config generate`
This commit is contained in:
commit
b9b4343fd5
@ -1072,12 +1072,16 @@ This command still supports the *deprecated* format where the UUID and optionall
|
||||
are passed directly on the command line, but the recommended way is to pass either an --app or
|
||||
--device argument. The deprecated format will be remove in a future release.
|
||||
|
||||
In case that you want to configure an image for an application with mixed device types,
|
||||
you can pass the --device-type argument along with --app to specify the target device type.
|
||||
|
||||
Examples:
|
||||
|
||||
$ balena os configure ../path/rpi.img --device 7cf02a6
|
||||
$ balena os configure ../path/rpi.img --device 7cf02a6 --device-api-key <existingDeviceKey>
|
||||
$ balena os configure ../path/rpi.img --app MyApp
|
||||
$ balena os configure ../path/rpi.img --app MyApp --version 2.12.7
|
||||
$ balena os configure ../path/rpi3.img --device 7cf02a6
|
||||
$ balena os configure ../path/rpi3.img --device 7cf02a6 --device-api-key <existingDeviceKey>
|
||||
$ balena os configure ../path/rpi3.img --app MyApp
|
||||
$ balena os configure ../path/rpi3.img --app MyApp --version 2.12.7
|
||||
$ balena os configure ../path/rpi3.img --app MyFinApp --device-type raspberrypi3
|
||||
|
||||
### Options
|
||||
|
||||
@ -1097,6 +1101,10 @@ device uuid
|
||||
|
||||
custom device key - note that this is only supported on balenaOS 2.0.3+
|
||||
|
||||
#### --deviceType <device-type>
|
||||
|
||||
device type slug
|
||||
|
||||
#### --version <version>
|
||||
|
||||
a balenaOS version
|
||||
@ -1225,6 +1233,9 @@ This is interactive by default, but you can do this automatically without intera
|
||||
by specifying an option for each question on the command line, if you know the questions
|
||||
that will be asked for the relevant device type.
|
||||
|
||||
In case that you want to configure an image for an application with mixed device types,
|
||||
you can pass the --device-type argument along with --app to specify the target device type.
|
||||
|
||||
Examples:
|
||||
|
||||
$ balena config generate --device 7cf02a6 --version 2.12.7
|
||||
@ -1232,6 +1243,7 @@ Examples:
|
||||
$ balena config generate --device 7cf02a6 --version 2.12.7 --device-api-key <existingDeviceKey>
|
||||
$ balena config generate --device 7cf02a6 --version 2.12.7 --output config.json
|
||||
$ balena config generate --app MyApp --version 2.12.7
|
||||
$ balena config generate --app MyApp --version 2.12.7 --device-type fincm3
|
||||
$ balena config generate --app MyApp --version 2.12.7 --output config.json
|
||||
$ balena config generate --app MyApp --version 2.12.7 --network wifi --wifiSsid mySsid --wifiKey abcdefgh --appUpdatePollInterval 1
|
||||
|
||||
@ -1253,6 +1265,10 @@ device uuid
|
||||
|
||||
custom device key - note that this is only supported on balenaOS 2.0.3+
|
||||
|
||||
#### --deviceType <device-type>
|
||||
|
||||
device type slug
|
||||
|
||||
#### --generate-device-api-key
|
||||
|
||||
generate a fresh device key for the device
|
||||
|
@ -57,6 +57,12 @@ export const optionalDeviceApiKey = {
|
||||
alias: 'k',
|
||||
};
|
||||
|
||||
export const optionalDeviceType = {
|
||||
signature: 'deviceType',
|
||||
description: 'device type slug',
|
||||
parameter: 'device-type',
|
||||
};
|
||||
|
||||
export const optionalOsVersion = {
|
||||
signature: 'version',
|
||||
description: 'a balenaOS version',
|
||||
|
@ -229,6 +229,9 @@ exports.generate =
|
||||
by specifying an option for each question on the command line, if you know the questions
|
||||
that will be asked for the relevant device type.
|
||||
|
||||
In case that you want to configure an image for an application with mixed device types,
|
||||
you can pass the --device-type argument along with --app to specify the target device type.
|
||||
|
||||
Examples:
|
||||
|
||||
$ balena config generate --device 7cf02a6 --version 2.12.7
|
||||
@ -236,6 +239,7 @@ exports.generate =
|
||||
$ balena config generate --device 7cf02a6 --version 2.12.7 --device-api-key <existingDeviceKey>
|
||||
$ balena config generate --device 7cf02a6 --version 2.12.7 --output config.json
|
||||
$ balena config generate --app MyApp --version 2.12.7
|
||||
$ balena config generate --app MyApp --version 2.12.7 --device-type fincm3
|
||||
$ balena config generate --app MyApp --version 2.12.7 --output config.json
|
||||
$ balena config generate --app MyApp --version 2.12.7 \
|
||||
--network wifi --wifiSsid mySsid --wifiKey abcdefgh --appUpdatePollInterval 1
|
||||
@ -245,6 +249,7 @@ exports.generate =
|
||||
commandOptions.optionalApplication
|
||||
commandOptions.optionalDevice
|
||||
commandOptions.optionalDeviceApiKey
|
||||
commandOptions.optionalDeviceType
|
||||
{
|
||||
signature: 'generate-device-api-key'
|
||||
description: 'generate a fresh device key for the device'
|
||||
@ -288,6 +293,7 @@ exports.generate =
|
||||
prettyjson = require('prettyjson')
|
||||
|
||||
{ generateDeviceConfig, generateApplicationConfig } = require('../utils/config')
|
||||
helpers = require('../utils/helpers')
|
||||
{ exitWithExpectedError } = require('../utils/patterns')
|
||||
|
||||
if not options.device? and not options.application?
|
||||
@ -299,13 +305,38 @@ exports.generate =
|
||||
$ balena help config generate
|
||||
'''
|
||||
|
||||
if !options.application and options.deviceType
|
||||
patterns.exitWithExpectedError '''
|
||||
Specifying a different device type is only supported when
|
||||
generating a config for an application:
|
||||
|
||||
* An application, with --app <appname>
|
||||
* A specific device type, with --device-type <deviceTypeSlug>
|
||||
|
||||
See the help page for examples:
|
||||
|
||||
$ balena help config generate
|
||||
'''
|
||||
|
||||
Promise.try ->
|
||||
if options.device?
|
||||
return balena.models.device.get(options.device)
|
||||
return balena.models.application.get(options.application)
|
||||
.then (resource) ->
|
||||
balena.models.device.getManifestBySlug(resource.device_type)
|
||||
.get('options')
|
||||
deviceType = options.deviceType || resource.device_type
|
||||
manifestPromise = balena.models.device.getManifestBySlug(deviceType)
|
||||
|
||||
if options.application && options.deviceType
|
||||
app = resource
|
||||
appManifestPromise = balena.models.device.getManifestBySlug(app.device_type)
|
||||
manifestPromise = manifestPromise.tap (paramDeviceType) ->
|
||||
appManifestPromise.then (appDeviceType) ->
|
||||
if not helpers.areDeviceTypesCompatible(appDeviceType, paramDeviceType)
|
||||
throw new balena.errors.BalenaInvalidDeviceType(
|
||||
"Device type #{options.deviceType} is incompatible with application #{options.application}"
|
||||
)
|
||||
|
||||
manifestPromise.get('options')
|
||||
.then (formOptions) ->
|
||||
# Pass params as an override: if there is any param with exactly the same name as a
|
||||
# required option, that value is used (and the corresponding question is not asked)
|
||||
@ -316,6 +347,7 @@ exports.generate =
|
||||
if resource.uuid?
|
||||
generateDeviceConfig(resource, options.deviceApiKey || options['generate-device-api-key'], answers)
|
||||
else
|
||||
answers.deviceType = deviceType
|
||||
generateApplicationConfig(resource, answers)
|
||||
.then (config) ->
|
||||
if options.output?
|
||||
|
@ -147,23 +147,28 @@ exports.download =
|
||||
console.info('The image was downloaded successfully')
|
||||
.nodeify(done)
|
||||
|
||||
buildConfig = (image, deviceType, advanced = false) ->
|
||||
Promise = require('bluebird')
|
||||
buildConfigForDeviceType = (deviceType, advanced = false) ->
|
||||
form = require('resin-cli-form')
|
||||
helpers = require('../utils/helpers')
|
||||
|
||||
Promise.resolve(helpers.getManifest(image, deviceType))
|
||||
.get('options')
|
||||
.then (questions) ->
|
||||
if not advanced
|
||||
advancedGroup = _.find questions,
|
||||
name: 'advanced'
|
||||
isGroup: true
|
||||
questions = deviceType.options
|
||||
if not advanced
|
||||
advancedGroup = _.find questions,
|
||||
name: 'advanced'
|
||||
isGroup: true
|
||||
|
||||
if advancedGroup?
|
||||
override = helpers.getGroupDefaults(advancedGroup)
|
||||
if advancedGroup?
|
||||
override = helpers.getGroupDefaults(advancedGroup)
|
||||
|
||||
return form.run(questions, { override })
|
||||
return form.run(questions, { override })
|
||||
|
||||
buildConfig = (image, deviceTypeSlug, advanced = false) ->
|
||||
Promise = require('bluebird')
|
||||
helpers = require('../utils/helpers')
|
||||
|
||||
Promise.resolve(helpers.getManifest(image, deviceTypeSlug))
|
||||
.then (deviceTypeManifest) ->
|
||||
buildConfigForDeviceType(deviceTypeManifest, advanced)
|
||||
|
||||
exports.buildConfig =
|
||||
signature: 'os build-config <image> <device-type>'
|
||||
@ -214,12 +219,16 @@ exports.configure =
|
||||
are passed directly on the command line, but the recommended way is to pass either an --app or
|
||||
--device argument. The deprecated format will be remove in a future release.
|
||||
|
||||
In case that you want to configure an image for an application with mixed device types,
|
||||
you can pass the --device-type argument along with --app to specify the target device type.
|
||||
|
||||
Examples:
|
||||
|
||||
$ balena os configure ../path/rpi.img --device 7cf02a6
|
||||
$ balena os configure ../path/rpi.img --device 7cf02a6 --device-api-key <existingDeviceKey>
|
||||
$ balena os configure ../path/rpi.img --app MyApp
|
||||
$ balena os configure ../path/rpi.img --app MyApp --version 2.12.7
|
||||
$ balena os configure ../path/rpi3.img --device 7cf02a6
|
||||
$ balena os configure ../path/rpi3.img --device 7cf02a6 --device-api-key <existingDeviceKey>
|
||||
$ balena os configure ../path/rpi3.img --app MyApp
|
||||
$ balena os configure ../path/rpi3.img --app MyApp --version 2.12.7
|
||||
$ balena os configure ../path/rpi3.img --app MyFinApp --device-type raspberrypi3
|
||||
'''
|
||||
permission: 'user'
|
||||
options: [
|
||||
@ -227,6 +236,7 @@ exports.configure =
|
||||
commandOptions.optionalApplication
|
||||
commandOptions.optionalDevice
|
||||
commandOptions.optionalDeviceApiKey
|
||||
commandOptions.optionalDeviceType
|
||||
commandOptions.optionalOsVersion
|
||||
{
|
||||
signature: 'config'
|
||||
@ -260,6 +270,19 @@ exports.configure =
|
||||
$ balena help os configure
|
||||
'''
|
||||
|
||||
if !options.application and options.deviceType
|
||||
patterns.exitWithExpectedError '''
|
||||
Specifying a different device type is only supported when
|
||||
configuring an image using an application as a parameter:
|
||||
|
||||
* An application, with --app <appname>
|
||||
* A specific device type, with --device-type <deviceTypeSlug>
|
||||
|
||||
See the help page for examples:
|
||||
|
||||
$ balena help os configure
|
||||
'''
|
||||
|
||||
uuid = options.device
|
||||
deviceApiKey = options.deviceApiKey
|
||||
|
||||
@ -269,15 +292,33 @@ exports.configure =
|
||||
|
||||
balena.models[configurationResourceType].get(uuid || options.application)
|
||||
.then (appOrDevice) ->
|
||||
manifestPromise = helpers.getManifest(params.image, appOrDevice.device_type)
|
||||
deviceType = options.deviceType || appOrDevice.device_type
|
||||
manifestPromise = helpers.getManifest(params.image, deviceType)
|
||||
|
||||
if options.application && options.deviceType
|
||||
app = appOrDevice
|
||||
appManifestPromise = balena.models.device.getManifestBySlug(app.device_type)
|
||||
paramManifestPromise = balena.models.device.getManifestBySlug(options.deviceType)
|
||||
manifestPromise = Promise.resolve(manifestPromise).tap ->
|
||||
Promise.join appManifestPromise, paramManifestPromise, (appDeviceType, paramDeviceType) ->
|
||||
if not helpers.areDeviceTypesCompatible(appDeviceType, paramDeviceType)
|
||||
throw new balena.errors.BalenaInvalidDeviceType(
|
||||
"Device type #{options.deviceType} is incompatible with application #{options.application}"
|
||||
)
|
||||
|
||||
answersPromise = Promise.try ->
|
||||
if options.config
|
||||
return readFileAsync(options.config, 'utf8')
|
||||
.then(JSON.parse)
|
||||
return buildConfig(params.image, appOrDevice.device_type, options.advanced)
|
||||
return manifestPromise.then (deviceTypeManifest) ->
|
||||
buildConfigForDeviceType(deviceTypeManifest, options.advanced)
|
||||
|
||||
Promise.join answersPromise, manifestPromise, (answers, manifest) ->
|
||||
answers.version = options.version
|
||||
|
||||
if configurationResourceType == 'application'
|
||||
answers.deviceType = deviceType
|
||||
|
||||
if not answers.version?
|
||||
answers.version = Promise.resolve(helpers.getOsVersion(params.image, manifest)).tap (version) ->
|
||||
if not version?
|
||||
|
@ -50,7 +50,11 @@ type ImgConfig = {
|
||||
|
||||
export function generateBaseConfig(
|
||||
application: BalenaSdk.Application,
|
||||
options: { version: string; appUpdatePollInterval?: number },
|
||||
options: {
|
||||
version: string;
|
||||
appUpdatePollInterval?: number;
|
||||
deviceType?: string;
|
||||
},
|
||||
): Promise<ImgConfig> {
|
||||
options = {
|
||||
...options,
|
||||
@ -69,7 +73,7 @@ export function generateBaseConfig(
|
||||
|
||||
export function generateApplicationConfig(
|
||||
application: BalenaSdk.Application,
|
||||
options: { version: string },
|
||||
options: { version: string; deviceType?: string },
|
||||
) {
|
||||
return generateBaseConfig(application, options).tap(config => {
|
||||
if (semver.satisfies(options.version, '<2.7.8')) {
|
||||
@ -89,7 +93,11 @@ export function generateDeviceConfig(
|
||||
return balena.models.application
|
||||
.get(device.belongs_to__application.__id)
|
||||
.then(application => {
|
||||
return generateBaseConfig(application, options).tap(config => {
|
||||
const baseConfigOpts = {
|
||||
...options,
|
||||
deviceType: device.device_type,
|
||||
};
|
||||
return generateBaseConfig(application, baseConfigOpts).tap(config => {
|
||||
if (
|
||||
deviceApiKey == null &&
|
||||
semver.satisfies(options.version, '<2.0.3')
|
||||
|
@ -92,6 +92,13 @@ export async function getManifest(
|
||||
return balena.models.device.getManifestBySlug(deviceType);
|
||||
}
|
||||
|
||||
export const areDeviceTypesCompatible = (
|
||||
deviceTypeA: BalenaSdk.DeviceType,
|
||||
deviceTypeB: BalenaSdk.DeviceType,
|
||||
) =>
|
||||
deviceTypeA.arch === deviceTypeB.arch &&
|
||||
!!deviceTypeA.isDependent === !!deviceTypeB.isDependent;
|
||||
|
||||
export async function getOsVersion(
|
||||
image: string,
|
||||
manifest: BalenaSdk.DeviceType,
|
||||
|
Loading…
x
Reference in New Issue
Block a user