mirror of
https://github.com/balena-io/balena-cli.git
synced 2024-12-19 05:37:51 +00:00
device os-update: allow host OS upgrade with development balenaOS images
also: fix `device os-update` incorrectly showing 0% progress convert `device os-update` to use async/await Change-type: minor Resolves: #1725 Signed-off-by: Scott Lowe <scott@balena.io>
This commit is contained in:
parent
7f79451376
commit
320b4864d9
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2016-2017 Balena
|
||||
Copyright 2016-2020 Balena Ltd.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@ -16,6 +16,7 @@ limitations under the License.
|
||||
import { Device } from 'balena-sdk';
|
||||
import { CommandDefinition } from 'capitano';
|
||||
import { stripIndent } from 'common-tags';
|
||||
import { ExpectedError } from '../errors';
|
||||
import { getBalenaSdk } from '../utils/lazy';
|
||||
import { normalizeUuidProp } from '../utils/normalization';
|
||||
import * as commandOptions from './command-options';
|
||||
@ -55,62 +56,67 @@ export const osUpdate: CommandDefinition<OsUpdate.Args, OsUpdate.Options> = {
|
||||
const patterns = await import('../utils/patterns');
|
||||
const form = await import('resin-cli-form');
|
||||
|
||||
return sdk.models.device
|
||||
.get(params.uuid, {
|
||||
$select: ['uuid', 'device_type', 'os_version', 'os_variant'],
|
||||
})
|
||||
.then(async ({ uuid, device_type, os_version, os_variant }) => {
|
||||
const currentOsVersion = sdk.models.device.getOsVersion({
|
||||
os_version,
|
||||
os_variant,
|
||||
} as Device);
|
||||
if (!currentOsVersion) {
|
||||
patterns.exitWithExpectedError(
|
||||
'The current os version of the device is not available',
|
||||
);
|
||||
// Just to make TS happy
|
||||
return;
|
||||
}
|
||||
// Get device info
|
||||
const {
|
||||
uuid,
|
||||
device_type,
|
||||
os_version,
|
||||
os_variant,
|
||||
} = await sdk.models.device.get(params.uuid, {
|
||||
$select: ['uuid', 'device_type', 'os_version', 'os_variant'],
|
||||
});
|
||||
|
||||
return sdk.models.os
|
||||
.getSupportedOsUpdateVersions(device_type, currentOsVersion)
|
||||
.then(hupVersionInfo => {
|
||||
if (hupVersionInfo.versions.length === 0) {
|
||||
patterns.exitWithExpectedError(
|
||||
'There are no available Host OS update targets for this device',
|
||||
);
|
||||
}
|
||||
// Get current device OS version
|
||||
const currentOsVersion = sdk.models.device.getOsVersion({
|
||||
os_version,
|
||||
os_variant,
|
||||
} as Device);
|
||||
if (!currentOsVersion) {
|
||||
throw new ExpectedError(
|
||||
'The current os version of the device is not available',
|
||||
);
|
||||
}
|
||||
|
||||
if (options.version != null) {
|
||||
if (!_.includes(hupVersionInfo.versions, options.version)) {
|
||||
patterns.exitWithExpectedError(
|
||||
'The provided version is not in the Host OS update targets for this device',
|
||||
);
|
||||
}
|
||||
return options.version;
|
||||
}
|
||||
// Get supported OS update versions
|
||||
const hupVersionInfo = await sdk.models.os.getSupportedOsUpdateVersions(
|
||||
device_type,
|
||||
currentOsVersion,
|
||||
);
|
||||
if (hupVersionInfo.versions.length === 0) {
|
||||
throw new ExpectedError(
|
||||
'There are no available Host OS update targets for this device',
|
||||
);
|
||||
}
|
||||
|
||||
return form.ask({
|
||||
message: 'Target OS version',
|
||||
type: 'list',
|
||||
choices: hupVersionInfo.versions.map(version => ({
|
||||
name:
|
||||
hupVersionInfo.recommended === version
|
||||
? `${version} (recommended)`
|
||||
: version,
|
||||
value: version,
|
||||
})),
|
||||
});
|
||||
})
|
||||
.then(version =>
|
||||
patterns
|
||||
.confirm(
|
||||
options.yes || false,
|
||||
'Host OS updates require a device restart when they complete. Are you sure you want to proceed?',
|
||||
)
|
||||
.then(() => sdk.models.device.startOsUpdate(uuid, version))
|
||||
.then(() => patterns.awaitDeviceOsUpdate(uuid, version)),
|
||||
);
|
||||
// Get target OS version
|
||||
let targetOsVersion = options.version;
|
||||
if (targetOsVersion != null) {
|
||||
if (!_.includes(hupVersionInfo.versions, targetOsVersion)) {
|
||||
throw new ExpectedError(
|
||||
`The provided version ${targetOsVersion} is not in the Host OS update targets for this device`,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
targetOsVersion = await form.ask({
|
||||
message: 'Target OS version',
|
||||
type: 'list',
|
||||
choices: hupVersionInfo.versions.map(version => ({
|
||||
name:
|
||||
hupVersionInfo.recommended === version
|
||||
? `${version} (recommended)`
|
||||
: version,
|
||||
value: version,
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
// Confirm and start update
|
||||
await patterns.confirm(
|
||||
options.yes || false,
|
||||
'Host OS updates require a device restart when they complete. Are you sure you want to proceed?',
|
||||
);
|
||||
|
||||
await sdk.models.device.startOsUpdate(uuid, targetOsVersion);
|
||||
await patterns.awaitDeviceOsUpdate(uuid, targetOsVersion);
|
||||
},
|
||||
};
|
||||
|
@ -48,7 +48,7 @@ Examples:
|
||||
`,
|
||||
permission: 'user',
|
||||
async action(params) {
|
||||
const key = await getBalenaSdk().models.key.get(params.id);
|
||||
const key = await getBalenaSdk().models.key.get(parseInt(params.id, 10));
|
||||
|
||||
console.log(getVisuals().table.vertical(key, ['id', 'title']));
|
||||
|
||||
@ -86,7 +86,7 @@ Examples:
|
||||
'Are you sure you want to delete the key?',
|
||||
);
|
||||
|
||||
await getBalenaSdk().models.key.remove(params.id);
|
||||
await getBalenaSdk().models.key.remove(parseInt(params.id, 10));
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -18,7 +18,7 @@ import { Device } from 'balena-sdk';
|
||||
|
||||
export const getDeviceOsProgress = (device: Device) => {
|
||||
if (!device.is_online) {
|
||||
return 0;
|
||||
return null;
|
||||
}
|
||||
|
||||
const status = BalenaDeviceStatus.getStatus(device).key;
|
||||
|
@ -293,10 +293,7 @@ export function awaitDeviceOsUpdate(uuid: string, targetOsVersion: string) {
|
||||
balena.models.device.getOsUpdateStatus(uuid),
|
||||
balena.models.device.get(uuid).then(getDeviceOsProgress),
|
||||
]).then(([osUpdateStatus, osUpdateProgress]) => {
|
||||
if (
|
||||
osUpdateStatus.status === 'update_done' ||
|
||||
osUpdateStatus.status === 'done'
|
||||
) {
|
||||
if (osUpdateStatus.status === 'done') {
|
||||
console.info(
|
||||
`The device ${deviceName} has been updated to v${targetOsVersion} and will restart shortly!`,
|
||||
);
|
||||
@ -311,7 +308,10 @@ export function awaitDeviceOsUpdate(uuid: string, targetOsVersion: string) {
|
||||
return;
|
||||
}
|
||||
|
||||
progressBar.update({ percentage: osUpdateProgress });
|
||||
if (osUpdateProgress !== null) {
|
||||
// Avoid resetting to 0% at end of process when device goes offline.
|
||||
progressBar.update({ percentage: osUpdateProgress });
|
||||
}
|
||||
|
||||
return Bluebird.delay(3000).then(poll);
|
||||
});
|
||||
@ -451,6 +451,8 @@ export function printErrorMessage(message: string) {
|
||||
* "expected" errors (say, a JSON parsing error in a file provided by the user)
|
||||
* don't warrant reporting through Sentry.io. For such mundane errors, catch
|
||||
* them and call this function.
|
||||
*
|
||||
* DEPRECATED: Use `throw new ExpectedError(<message>)` instead.
|
||||
*/
|
||||
export function exitWithExpectedError(message: string | Error): never {
|
||||
if (message instanceof Error) {
|
||||
|
54
npm-shrinkwrap.json
generated
54
npm-shrinkwrap.json
generated
@ -2089,9 +2089,9 @@
|
||||
}
|
||||
},
|
||||
"balena-hup-action-utils": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/balena-hup-action-utils/-/balena-hup-action-utils-3.0.2.tgz",
|
||||
"integrity": "sha512-AwTAFQN4mtjsRLhkzspMKGBykWKvjVlZnzhAu6uyPBn8PGocyB3D30bR2jWgapd6uSdPJf38fcspRDbcpx3CHA==",
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/balena-hup-action-utils/-/balena-hup-action-utils-4.0.0.tgz",
|
||||
"integrity": "sha512-Qwk4h6QRqBiJNONRyoHPKtxgoRucdCK5VTG0A6LSCAo0qQrBRi4Alhdq76ksHQgZ2t/Gewfa7cuVAgiH78YMfw==",
|
||||
"requires": {
|
||||
"balena-semver": "^2.0.0",
|
||||
"lodash": "^4.17.11"
|
||||
@ -2124,9 +2124,9 @@
|
||||
}
|
||||
},
|
||||
"balena-pine": {
|
||||
"version": "10.1.1",
|
||||
"resolved": "https://registry.npmjs.org/balena-pine/-/balena-pine-10.1.1.tgz",
|
||||
"integrity": "sha512-Py0Id0w1QwwM20/gmZ4hRgTOf0sbCwmjGwkE0G/AO6fqnlFDe5ehaebzXk3AtWmW3K7WGDPUxcNAHohHG8aRJA==",
|
||||
"version": "10.1.3",
|
||||
"resolved": "https://registry.npmjs.org/balena-pine/-/balena-pine-10.1.3.tgz",
|
||||
"integrity": "sha512-dOjftYx7vf9e3C9ENJyYyD8DNtQl6CxXuWgvNImfvK3Rw+zSRBPYfLw6S4MqbCWkcsQGjaS/zun/VJ9UNjJYhQ==",
|
||||
"requires": {
|
||||
"balena-errors": "^4.2.1",
|
||||
"bluebird": "^3.7.2",
|
||||
@ -2235,16 +2235,16 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"qs": {
|
||||
"version": "6.9.1",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.9.1.tgz",
|
||||
"integrity": "sha512-Cxm7/SS/y/Z3MHWSxXb8lIFqgqBowP5JMlTUFyJN88y0SGQhVmZnqFK/PeuMX9LzUyWsqqhNxIyg0jlzq946yA=="
|
||||
"version": "6.9.3",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.9.3.tgz",
|
||||
"integrity": "sha512-EbZYNarm6138UKKq46tdx08Yo/q9ZhFoAXAI1meAFd2GtbRDhbZY2WQSICskT0c5q99aFzLG1D4nvTk9tqfXIw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"balena-sdk": {
|
||||
"version": "12.29.1",
|
||||
"resolved": "https://registry.npmjs.org/balena-sdk/-/balena-sdk-12.29.1.tgz",
|
||||
"integrity": "sha512-e6nIuP16AaDpGQnOCDPR7kptCM7/iWHPp6bdmUeBsw9e5IX4zwI0FwFHi4L9EoRxByLKI5oRZYeYGeU++Sd1Nw==",
|
||||
"version": "12.33.0",
|
||||
"resolved": "https://registry.npmjs.org/balena-sdk/-/balena-sdk-12.33.0.tgz",
|
||||
"integrity": "sha512-riqcJeA8SYMf20bgt1lhgw/eWiWXVwivGHgBer54/dxDIo48RIwys98LvkisIO2sTco1AmTL4Q0rePsMGjEYwQ==",
|
||||
"requires": {
|
||||
"@types/bluebird": "^3.5.30",
|
||||
"@types/lodash": "^4.14.149",
|
||||
@ -2253,8 +2253,8 @@
|
||||
"abortcontroller-polyfill": "^1.4.0",
|
||||
"balena-auth": "^3.0.1",
|
||||
"balena-device-status": "^3.2.1",
|
||||
"balena-errors": "^4.2.1",
|
||||
"balena-hup-action-utils": "~3.0.0",
|
||||
"balena-errors": "^4.3.0",
|
||||
"balena-hup-action-utils": "~4.0.0",
|
||||
"balena-pine": "^10.1.1",
|
||||
"balena-register-device": "^6.0.1",
|
||||
"balena-request": "^10.0.8",
|
||||
@ -2269,9 +2269,23 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/node": {
|
||||
"version": "8.10.59",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.59.tgz",
|
||||
"integrity": "sha512-8RkBivJrDCyPpBXhVZcjh7cQxVBSmRk9QM7hOketZzp6Tg79c0N8kkpAIito9bnJ3HCVCHVYz+KHTEbfQNfeVQ=="
|
||||
"version": "8.10.60",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.60.tgz",
|
||||
"integrity": "sha512-YjPbypHFuiOV0bTgeF07HpEEqhmHaZqYNSdCKeBJa+yFoQ/7BC+FpJcwmi34xUIIRVFktnUyP1dPU8U0612GOg=="
|
||||
},
|
||||
"balena-errors": {
|
||||
"version": "4.3.2",
|
||||
"resolved": "https://registry.npmjs.org/balena-errors/-/balena-errors-4.3.2.tgz",
|
||||
"integrity": "sha512-daa+3jHqvoha8zIIIX4jvxdus1LWhH+2Y5IJOzOuIzxmfLEq51EXeszMbcHrbSLlGlJpfaJDG7dfBmFXtabL6Q==",
|
||||
"requires": {
|
||||
"tslib": "^1.11.1",
|
||||
"typed-error": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"tslib": {
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz",
|
||||
"integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -2314,9 +2328,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/node": {
|
||||
"version": "8.10.59",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.59.tgz",
|
||||
"integrity": "sha512-8RkBivJrDCyPpBXhVZcjh7cQxVBSmRk9QM7hOketZzp6Tg79c0N8kkpAIito9bnJ3HCVCHVYz+KHTEbfQNfeVQ=="
|
||||
"version": "8.10.60",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.60.tgz",
|
||||
"integrity": "sha512-YjPbypHFuiOV0bTgeF07HpEEqhmHaZqYNSdCKeBJa+yFoQ/7BC+FpJcwmi34xUIIRVFktnUyP1dPU8U0612GOg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -173,7 +173,7 @@
|
||||
"balena-errors": "^4.2.1",
|
||||
"balena-image-manager": "^6.1.2",
|
||||
"balena-preload": "^8.4.0",
|
||||
"balena-sdk": "^12.29.1",
|
||||
"balena-sdk": "^12.33.0",
|
||||
"balena-semver": "^2.2.0",
|
||||
"balena-settings-client": "^4.0.4",
|
||||
"balena-sync": "^10.2.0",
|
||||
|
Loading…
Reference in New Issue
Block a user