mirror of
https://github.com/balena-io/balena-cli.git
synced 2024-12-24 07:46:39 +00:00
Make specifying the version during configuration optional
`version` used to be optional but it seems we recently had to make it a required parameter. However it really feels redundant when all it’s used for is to determine whether the command should issue a legacy user API key or a provisioning key. This makes version optional but tries to figure it out by itself by reading os-release from the image's boot partition. This is not foul-proof however, and while it'll work with most recent images it won't work with all and in that case it'll bail out and only then warn the user to specify it via the --version argument. Change-type: minor
This commit is contained in:
parent
561325e66d
commit
8291c96e69
@ -973,7 +973,9 @@ the path to the output JSON file
|
||||
Use this command to configure a previously downloaded operating system image for
|
||||
the specific device or for an application generally.
|
||||
|
||||
Calling this command with the exact version number of the targeted image is required.
|
||||
This command will try to automatically determine the operating system version in order
|
||||
to correctly configure the image. It may fail to do so however, in which case you'll
|
||||
have to call this command again with the exact version number of the targeted image.
|
||||
|
||||
Note that device api keys are only supported on balenaOS 2.0.3+.
|
||||
|
||||
@ -983,9 +985,10 @@ are passed directly on the command line, but the recommended way is to pass eith
|
||||
|
||||
Examples:
|
||||
|
||||
$ balena os configure ../path/rpi.img --device 7cf02a6 --version 2.12.7
|
||||
$ balena os configure ../path/rpi.img --device 7cf02a6 --version 2.12.7 --device-api-key <existingDeviceKey>
|
||||
$ balena os configure ../path/rpi.img --app MyApp --version 2.12.7
|
||||
$ 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
|
||||
|
||||
### Options
|
||||
|
||||
@ -1135,13 +1138,13 @@ that will be asked for the relevant device type.
|
||||
|
||||
Examples:
|
||||
|
||||
$ balena config generate --device 7cf02a6 --version 2.12.7
|
||||
$ balena config generate --device 7cf02a6 --version 2.12.7 --generate-device-api-key
|
||||
$ 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 --output config.json
|
||||
$ balena config generate --app MyApp --version 2.12.7 --network wifi --wifiSsid mySsid --wifiKey abcdefgh --appUpdatePollInterval 1
|
||||
$ balena config generate --device 7cf02a6
|
||||
$ balena config generate --device 7cf02a6 --generate-device-api-key
|
||||
$ balena config generate --device 7cf02a6 --device-api-key <existingDeviceKey>
|
||||
$ balena config generate --device 7cf02a6 --output config.json
|
||||
$ balena config generate --app MyApp
|
||||
$ balena config generate --app MyApp --output config.json
|
||||
$ balena config generate --app MyApp --network wifi --wifiSsid mySsid --wifiKey abcdefgh --appUpdatePollInterval 1
|
||||
|
||||
### Options
|
||||
|
||||
|
@ -1,115 +0,0 @@
|
||||
###
|
||||
Copyright 2016-2017 Balena
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
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.
|
||||
###
|
||||
|
||||
_ = require('lodash')
|
||||
|
||||
exports.yes =
|
||||
signature: 'yes'
|
||||
description: 'confirm non interactively'
|
||||
boolean: true
|
||||
alias: 'y'
|
||||
|
||||
exports.optionalApplication =
|
||||
signature: 'application'
|
||||
parameter: 'application'
|
||||
description: 'application name'
|
||||
alias: [ 'a', 'app' ]
|
||||
|
||||
exports.application = _.defaults
|
||||
required: 'You have to specify an application'
|
||||
, exports.optionalApplication
|
||||
|
||||
exports.optionalDevice =
|
||||
signature: 'device'
|
||||
parameter: 'device'
|
||||
description: 'device uuid'
|
||||
alias: 'd'
|
||||
|
||||
exports.optionalDeviceApiKey =
|
||||
signature: 'deviceApiKey'
|
||||
description: 'custom device key - note that this is only supported on balenaOS 2.0.3+'
|
||||
parameter: 'device-api-key'
|
||||
alias: 'k'
|
||||
|
||||
exports.optionalOsVersion =
|
||||
signature: 'version'
|
||||
description: 'a balenaOS version'
|
||||
parameter: 'version'
|
||||
|
||||
exports.osVersion = _.defaults
|
||||
required: 'You have to specify an exact os version'
|
||||
, exports.optionalOsVersion
|
||||
|
||||
exports.booleanDevice =
|
||||
signature: 'device'
|
||||
description: 'device'
|
||||
boolean: true
|
||||
alias: 'd'
|
||||
|
||||
exports.osVersionOrSemver =
|
||||
signature: 'version'
|
||||
description: """
|
||||
exact version number, or a valid semver range,
|
||||
or 'latest' (includes pre-releases),
|
||||
or 'default' (excludes pre-releases if at least one stable version is available),
|
||||
or 'recommended' (excludes pre-releases, will fail if only pre-release versions are available),
|
||||
or 'menu' (will show the interactive menu)
|
||||
"""
|
||||
parameter: 'version'
|
||||
|
||||
exports.network =
|
||||
signature: 'network'
|
||||
parameter: 'network'
|
||||
description: 'network type'
|
||||
alias: 'n'
|
||||
|
||||
exports.wifiSsid =
|
||||
signature: 'ssid'
|
||||
parameter: 'ssid'
|
||||
description: 'wifi ssid, if network is wifi'
|
||||
alias: 's'
|
||||
|
||||
exports.wifiKey =
|
||||
signature: 'key'
|
||||
parameter: 'key'
|
||||
description: 'wifi key, if network is wifi'
|
||||
alias: 'k'
|
||||
|
||||
exports.forceUpdateLock =
|
||||
signature: 'force'
|
||||
description: 'force action if the update lock is set'
|
||||
boolean: true
|
||||
alias: 'f'
|
||||
|
||||
exports.drive =
|
||||
signature: 'drive'
|
||||
description: 'the drive to write the image to, like `/dev/sdb` or `/dev/mmcblk0`.
|
||||
Careful with this as you can erase your hard drive.
|
||||
Check `balena util available-drives` for available options.'
|
||||
parameter: 'drive'
|
||||
alias: 'd'
|
||||
|
||||
exports.advancedConfig =
|
||||
signature: 'advanced'
|
||||
description: 'show advanced configuration options'
|
||||
boolean: true
|
||||
alias: 'v'
|
||||
|
||||
exports.hostOSAccess =
|
||||
signature: 'host'
|
||||
boolean: true
|
||||
description: 'access host OS (for devices with balenaOS >= 2.7.5)'
|
||||
alias: 's'
|
@ -231,17 +231,17 @@ exports.generate =
|
||||
|
||||
Examples:
|
||||
|
||||
$ balena config generate --device 7cf02a6 --version 2.12.7
|
||||
$ balena config generate --device 7cf02a6 --version 2.12.7 --generate-device-api-key
|
||||
$ 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 --output config.json
|
||||
$ balena config generate --app MyApp --version 2.12.7 \
|
||||
$ balena config generate --device 7cf02a6
|
||||
$ balena config generate --device 7cf02a6 --generate-device-api-key
|
||||
$ balena config generate --device 7cf02a6 --device-api-key <existingDeviceKey>
|
||||
$ balena config generate --device 7cf02a6 --output config.json
|
||||
$ balena config generate --app MyApp
|
||||
$ balena config generate --app MyApp --output config.json
|
||||
$ balena config generate --app MyApp \
|
||||
--network wifi --wifiSsid mySsid --wifiKey abcdefgh --appUpdatePollInterval 1
|
||||
'''
|
||||
options: [
|
||||
commandOptions.osVersion
|
||||
commandOptions.optionalOsVersion
|
||||
commandOptions.optionalApplication
|
||||
commandOptions.optionalDevice
|
||||
commandOptions.optionalDeviceApiKey
|
||||
|
@ -27,12 +27,13 @@ exports.osInit =
|
||||
root: true
|
||||
action: (params, options, done) ->
|
||||
Promise = require('bluebird')
|
||||
init = require('resin-device-init')
|
||||
init = require('balena-device-init')
|
||||
helpers = require('../utils/helpers')
|
||||
|
||||
return Promise.try ->
|
||||
config = JSON.parse(params.config)
|
||||
init.initialize(params.image, params.type, config)
|
||||
configPromise = Promise.try -> JSON.parse(params.config)
|
||||
manifestPromise = helpers.getManifest(params.image, params.type)
|
||||
Promise.join configPromise, manifestPromise, (config, manifest) ->
|
||||
init.initialize(params.image, manifest, config)
|
||||
.then(helpers.osProgressHandler)
|
||||
.nodeify(done)
|
||||
|
||||
|
@ -151,7 +151,7 @@ buildConfig = (image, deviceType, advanced = false) ->
|
||||
form = require('resin-cli-form')
|
||||
helpers = require('../utils/helpers')
|
||||
|
||||
helpers.getManifest(image, deviceType)
|
||||
Promise.resolve(helpers.getManifest(image, deviceType))
|
||||
.get('options')
|
||||
.then (questions) ->
|
||||
if not advanced
|
||||
@ -203,7 +203,9 @@ exports.configure =
|
||||
Use this command to configure a previously downloaded operating system image for
|
||||
the specific device or for an application generally.
|
||||
|
||||
Calling this command with the exact version number of the targeted image is required.
|
||||
This command will try to automatically determine the operating system version in order
|
||||
to correctly configure the image. It may fail to do so however, in which case you'll
|
||||
have to call this command again with the exact version number of the targeted image.
|
||||
|
||||
Note that device api keys are only supported on balenaOS 2.0.3+.
|
||||
|
||||
@ -213,9 +215,10 @@ exports.configure =
|
||||
|
||||
Examples:
|
||||
|
||||
$ balena os configure ../path/rpi.img --device 7cf02a6 --version 2.12.7
|
||||
$ balena os configure ../path/rpi.img --device 7cf02a6 --version 2.12.7 --device-api-key <existingDeviceKey>
|
||||
$ balena os configure ../path/rpi.img --app MyApp --version 2.12.7
|
||||
$ 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
|
||||
'''
|
||||
permission: 'user'
|
||||
options: [
|
||||
@ -223,7 +226,7 @@ exports.configure =
|
||||
commandOptions.optionalApplication
|
||||
commandOptions.optionalDevice
|
||||
commandOptions.optionalDeviceApiKey
|
||||
commandOptions.osVersion
|
||||
commandOptions.optionalOsVersion
|
||||
{
|
||||
signature: 'config'
|
||||
description: 'path to the config JSON file, see `balena os build-config`'
|
||||
@ -236,7 +239,7 @@ exports.configure =
|
||||
Promise = require('bluebird')
|
||||
readFileAsync = Promise.promisify(fs.readFile)
|
||||
balena = require('balena-sdk').fromSharedOptions()
|
||||
init = require('resin-device-init')
|
||||
init = require('balena-device-init')
|
||||
helpers = require('../utils/helpers')
|
||||
patterns = require('../utils/patterns')
|
||||
{ generateDeviceConfig, generateApplicationConfig } = require('../utils/config')
|
||||
@ -265,20 +268,32 @@ exports.configure =
|
||||
|
||||
balena.models[configurationResourceType].get(uuid || options.application)
|
||||
.then (appOrDevice) ->
|
||||
Promise.try ->
|
||||
manifestPromise = helpers.getManifest(params.image, appOrDevice.device_type)
|
||||
answersPromise = Promise.try ->
|
||||
if options.config
|
||||
return readFileAsync(options.config, 'utf8')
|
||||
.then(JSON.parse)
|
||||
return buildConfig(params.image, appOrDevice.device_type, options.advanced)
|
||||
.then (answers) ->
|
||||
Promise.join answersPromise, manifestPromise, (answers, manifest) ->
|
||||
answers.version = options.version
|
||||
|
||||
(if configurationResourceType == 'device'
|
||||
generateDeviceConfig(appOrDevice, deviceApiKey, answers)
|
||||
else
|
||||
generateApplicationConfig(appOrDevice, answers)
|
||||
).then (config) ->
|
||||
init.configure(params.image, appOrDevice.device_type, config, answers)
|
||||
if not answers.version?
|
||||
answers.version = helpers.getOsVersion(params.image, manifest).tap (version) ->
|
||||
if not version?
|
||||
throw new Error(
|
||||
'Could not read OS version from the image. ' +
|
||||
'Please specify the version manually with the ' +
|
||||
'--version argument to this command.'
|
||||
)
|
||||
|
||||
Promise.props(answers).then (answers) ->
|
||||
(if configurationResourceType == 'device'
|
||||
generateDeviceConfig(appOrDevice, deviceApiKey, answers)
|
||||
else
|
||||
generateApplicationConfig(appOrDevice, answers)
|
||||
)
|
||||
.then (config) ->
|
||||
init.configure(params.image, manifest, config, answers)
|
||||
.then(helpers.osProgressHandler)
|
||||
.nodeify(done)
|
||||
|
||||
|
@ -72,11 +72,10 @@ export function generateApplicationConfig(
|
||||
options: { version: string },
|
||||
) {
|
||||
return generateBaseConfig(application, options).tap(config => {
|
||||
if (semver.satisfies(options.version, '>=2.7.8')) {
|
||||
return addProvisioningKey(config, application.id);
|
||||
} else {
|
||||
if (semver.satisfies(options.version, '<2.7.8')) {
|
||||
return addApplicationKey(config, application.id);
|
||||
}
|
||||
return addProvisioningKey(config, application.id);
|
||||
});
|
||||
}
|
||||
|
||||
@ -91,13 +90,13 @@ export function generateDeviceConfig(
|
||||
.get(device.belongs_to__application.__id)
|
||||
.then(application => {
|
||||
return generateBaseConfig(application, options).tap(config => {
|
||||
if (deviceApiKey) {
|
||||
return addDeviceKey(config, device.uuid, deviceApiKey);
|
||||
} else if (semver.satisfies(options.version, '>=2.0.3')) {
|
||||
return addDeviceKey(config, device.uuid, true);
|
||||
} else {
|
||||
if (
|
||||
deviceApiKey == null &&
|
||||
semver.satisfies(options.version, '<2.0.3')
|
||||
) {
|
||||
return addApplicationKey(config, application.id);
|
||||
}
|
||||
return addDeviceKey(config, device.uuid, deviceApiKey || true);
|
||||
});
|
||||
})
|
||||
.then(config => {
|
||||
|
@ -15,16 +15,16 @@ limitations under the License.
|
||||
*/
|
||||
|
||||
import os = require('os');
|
||||
import Promise = require('bluebird');
|
||||
import Bluebird = require('bluebird');
|
||||
import _ = require('lodash');
|
||||
import chalk from 'chalk';
|
||||
import rindle = require('rindle');
|
||||
import visuals = require('resin-cli-visuals');
|
||||
import BalenaSdk = require('balena-sdk');
|
||||
|
||||
import { InitializeEmitter, OperationState } from 'resin-device-init';
|
||||
import { InitializeEmitter, OperationState } from 'balena-device-init';
|
||||
|
||||
const waitStreamAsync = Promise.promisify(rindle.wait);
|
||||
const waitStreamAsync = Bluebird.promisify(rindle.wait);
|
||||
|
||||
const balena = BalenaSdk.fromSharedOptions();
|
||||
|
||||
@ -75,27 +75,29 @@ export function sudo(
|
||||
return executeWithPrivileges(command, stderr);
|
||||
}
|
||||
|
||||
export function runCommand(command: string): Promise<void> {
|
||||
export function runCommand(command: string): Bluebird<void> {
|
||||
const capitano = require('capitano');
|
||||
return Promise.fromCallback(resolver => capitano.run(command, resolver));
|
||||
return Bluebird.fromCallback(resolver => capitano.run(command, resolver));
|
||||
}
|
||||
|
||||
export function getManifest(
|
||||
export async function getManifest(
|
||||
image: string,
|
||||
deviceType: string,
|
||||
): Promise<BalenaSdk.DeviceType> {
|
||||
const imagefs = require('resin-image-fs');
|
||||
// Attempt to read manifest from the first
|
||||
// partition, but fallback to the API if
|
||||
// we encounter any errors along the way.
|
||||
return imagefs
|
||||
.readFile({
|
||||
image,
|
||||
partition: 1,
|
||||
path: '/device-type.json',
|
||||
})
|
||||
.then(JSON.parse)
|
||||
.catch(() => balena.models.device.getManifestBySlug(deviceType));
|
||||
const init = await import('balena-device-init');
|
||||
const manifest = await init.getImageManifest(image);
|
||||
if (manifest != null) {
|
||||
return manifest;
|
||||
}
|
||||
return balena.models.device.getManifestBySlug(deviceType);
|
||||
}
|
||||
|
||||
export async function getOsVersion(
|
||||
image: string,
|
||||
manifest: BalenaSdk.DeviceType,
|
||||
): Promise<string | null> {
|
||||
const init = await import('balena-device-init');
|
||||
return init.getImageOsVersion(image, manifest);
|
||||
}
|
||||
|
||||
export function osProgressHandler(step: InitializeEmitter) {
|
||||
@ -121,8 +123,8 @@ export function osProgressHandler(step: InitializeEmitter) {
|
||||
|
||||
export function getArchAndDeviceType(
|
||||
applicationName: string,
|
||||
): Promise<{ arch: string; device_type: string }> {
|
||||
return Promise.join(
|
||||
): Bluebird<{ arch: string; device_type: string }> {
|
||||
return Bluebird.join(
|
||||
getApplication(applicationName),
|
||||
balena.models.config.getDeviceTypes(),
|
||||
function(app, deviceTypes) {
|
||||
|
@ -103,6 +103,7 @@
|
||||
"any-promise": "^1.3.0",
|
||||
"archiver": "^2.1.0",
|
||||
"balena-config-json": "^2.0.0",
|
||||
"balena-device-init": "^5.0.0",
|
||||
"balena-image-manager": "^6.0.0",
|
||||
"balena-preload": "^8.0.0",
|
||||
"balena-sdk": "^11.0.0",
|
||||
@ -155,7 +156,6 @@
|
||||
"resin-cli-form": "^2.0.0",
|
||||
"resin-cli-visuals": "^1.4.0",
|
||||
"resin-compose-parse": "^2.0.0",
|
||||
"resin-device-init": "^4.0.0",
|
||||
"resin-doodles": "0.0.1",
|
||||
"resin-image-fs": "^5.0.2",
|
||||
"resin-multibuild": "^0.9.0",
|
||||
|
@ -1,6 +1,7 @@
|
||||
declare module 'resin-device-init' {
|
||||
declare module 'balena-device-init' {
|
||||
import * as Promise from 'bluebird';
|
||||
import { EventEmitter } from 'events';
|
||||
import { DeviceType } from 'balena-sdk';
|
||||
|
||||
interface OperationState {
|
||||
operation:
|
||||
@ -60,9 +61,23 @@ declare module 'resin-device-init' {
|
||||
on(event: 'burn', callback: (state: BurnProgress) => void): void;
|
||||
}
|
||||
|
||||
export function configure(
|
||||
image: string,
|
||||
manifest: DeviceType,
|
||||
config: {},
|
||||
options?: {},
|
||||
): Promise<InitializeEmitter>;
|
||||
|
||||
export function initialize(
|
||||
image: string,
|
||||
deviceType: string,
|
||||
manifest: DeviceType,
|
||||
config: {},
|
||||
): Promise<InitializeEmitter>;
|
||||
|
||||
export function getImageOsVersion(
|
||||
image: string,
|
||||
manifest: DeviceType,
|
||||
): Promise<string | null>;
|
||||
|
||||
export function getImageManifest(image: string): Promise<DeviceType | null>;
|
||||
}
|
Loading…
Reference in New Issue
Block a user