Merge pull request #2334 from balena-io/2005-os-esr-versions-hostapp

os versions, os download: Add support for balenaOS ESR versions
This commit is contained in:
bulldozer-balena[bot] 2021-11-20 01:17:17 +00:00 committed by GitHub
commit 6c29d0ae27
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 108 additions and 49 deletions

View File

@ -2240,6 +2240,9 @@ device UUID
Show the available balenaOS versions for the given device type.
Check available types with `balena devices supported`.
balenaOS ESR versions can be listed with the '--esr' option. See also:
https://www.balena.io/docs/reference/OS/extended-support-release/
Examples:
$ balena os versions raspberrypi3
@ -2252,23 +2255,28 @@ device type
### Options
#### --esr
select balenaOS ESR versions
## os download <type>
Download an unconfigured OS image for a certain device type.
Check available types with `balena devices supported`
Download an unconfigured OS image for the specified device type.
Check available device types with 'balena devices supported'.
Note: Currently this command only works with balenaCloud, not openBalena.
If using openBalena, please download the OS from: https://www.balena.io/os/
If version is not specified the newest stable (non-pre-release) version of OS
is downloaded (if available), otherwise the newest version (if all existing
versions for the given device type are pre-release).
The '--version' option is used to select the balenaOS version. If omitted,
the latest released version is downloaded (and if only pre-release versions
exist, the latest pre-release version is downloaded).
You can pass `--version menu` to pick the OS version from the interactive menu
of all available versions.
Use '--version menu' or '--version menu-esr' to interactively select the
OS version. The latter lists ESR versions which are only available for
download on Production and Enterprise plans. See also:
https://www.balena.io/docs/reference/OS/extended-support-release/
To download a development image append `.dev` to the version or select from
the interactive menu.
Development images can be selected by appending `.dev` to the version.
Examples:
@ -2294,11 +2302,13 @@ output path
#### --version VERSION
exact version number, or a valid semver range,
version number (ESR or non-ESR versions),
or semver range (non-ESR versions only),
or 'latest' (includes pre-releases),
or 'default' (excludes pre-releases if at least one stable version is available),
or 'default' (excludes pre-releases if at least one released version is available),
or 'recommended' (excludes pre-releases, will fail if only pre-release versions are available),
or 'menu' (will show the interactive menu)
or 'menu' (interactive menu, non-ESR versions),
or 'menu-esr' (interactive menu, ESR versions)
## os build-config <image> <device-type>

View File

@ -34,21 +34,22 @@ export default class OsDownloadCmd extends Command {
public static description = stripIndent`
Download an unconfigured OS image.
Download an unconfigured OS image for a certain device type.
Check available types with \`balena devices supported\`
Download an unconfigured OS image for the specified device type.
Check available device types with 'balena devices supported'.
Note: Currently this command only works with balenaCloud, not openBalena.
If using openBalena, please download the OS from: https://www.balena.io/os/
If version is not specified the newest stable (non-pre-release) version of OS
is downloaded (if available), otherwise the newest version (if all existing
versions for the given device type are pre-release).
The '--version' option is used to select the balenaOS version. If omitted,
the latest released version is downloaded (and if only pre-release versions
exist, the latest pre-release version is downloaded).
You can pass \`--version menu\` to pick the OS version from the interactive menu
of all available versions.
Use '--version menu' or '--version menu-esr' to interactively select the
OS version. The latter lists ESR versions which are only available for
download on Production and Enterprise plans. See also:
https://www.balena.io/docs/reference/OS/extended-support-release/
To download a development image append \`.dev\` to the version or select from
the interactive menu.
Development images can be selected by appending \`.dev\` to the version.
`;
public static examples = [
'$ balena os download raspberrypi3 -o ../foo/bar/raspberry-pi.img',
@ -78,11 +79,13 @@ export default class OsDownloadCmd extends Command {
}),
version: flags.string({
description: stripIndent`
exact version number, or a valid semver range,
version number (ESR or non-ESR versions),
or semver range (non-ESR versions only),
or 'latest' (includes pre-releases),
or 'default' (excludes pre-releases if at least one stable version is available),
or 'default' (excludes pre-releases if at least one released version is available),
or 'recommended' (excludes pre-releases, will fail if only pre-release versions are available),
or 'menu' (will show the interactive menu)
or 'menu' (interactive menu, non-ESR versions),
or 'menu-esr' (interactive menu, ESR versions)
`,
}),
help: cf.help,

View File

@ -18,9 +18,10 @@
import { flags } from '@oclif/command';
import Command from '../../command';
import * as cf from '../../utils/common-flags';
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
import { stripIndent } from '../../utils/lazy';
interface FlagsDef {
esr?: boolean;
help: void;
}
@ -34,6 +35,9 @@ export default class OsVersionsCmd extends Command {
Show the available balenaOS versions for the given device type.
Check available types with \`balena devices supported\`.
balenaOS ESR versions can be listed with the '--esr' option. See also:
https://www.balena.io/docs/reference/OS/extended-support-release/
`;
public static examples = ['$ balena os versions raspberrypi3'];
@ -50,16 +54,20 @@ export default class OsVersionsCmd extends Command {
public static flags: flags.Input<FlagsDef> = {
help: cf.help,
esr: flags.boolean({
description: 'select balenaOS ESR versions',
default: false,
}),
};
public async run() {
const { args: params } = this.parse<FlagsDef, ArgsDef>(OsVersionsCmd);
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
OsVersionsCmd,
);
const { versions: vs, recommended } =
await getBalenaSdk().models.os.getSupportedVersions(params.type);
const { getFormattedOsVersions } = await import('../../utils/cloud');
const vs = await getFormattedOsVersions(params.type, !!options.esr);
vs.forEach((v) => {
console.log(`v${v}` + (v === recommended ? ' (recommended)' : ''));
});
console.log(vs.map((v) => v.formattedVersion).join('\n'));
}
}

View File

@ -130,15 +130,13 @@ export async function downloadOSImage(
console.info(`Getting device operating system for ${deviceType}`);
if (!OSVersion) {
console.warn('OS version not specified: using latest stable version');
console.warn('OS version not specified: using latest released version');
}
OSVersion = OSVersion
? await resolveOSVersion(deviceType, OSVersion)
: 'default';
const displayVersion = OSVersion === 'default' ? '' : ` ${OSVersion}`;
// Override the default zlib flush value as we've seen cases of
// incomplete files being identified as successful downloads when using Z_SYNC_FLUSH.
// Using Z_NO_FLUSH results in a Z_BUF_ERROR instead of a corrupt image file.
@ -150,10 +148,17 @@ export async function downloadOSImage(
const manager = await import('balena-image-manager');
const stream = await manager.get(deviceType, OSVersion);
const displayVersion = await new Promise((resolve, reject) => {
stream.on('error', reject);
stream.on('balena-image-manager:resolved-version', resolve);
});
const visuals = getVisuals();
const bar = new visuals.Progress(`Downloading Device OS${displayVersion}`);
const bar = new visuals.Progress(
`Downloading balenaOS version ${displayVersion}`,
);
const spinner = new visuals.Spinner(
`Downloading Device OS${displayVersion} (size unknown)`,
`Downloading balenaOS version ${displayVersion} (size unknown)`,
);
stream.on('progress', (state: any) => {
@ -183,28 +188,29 @@ export async function downloadOSImage(
const streamToPromise = await import('stream-to-promise');
await streamToPromise(stream.pipe(output));
console.info('The image was downloaded successfully');
console.info(
`balenaOS image version ${displayVersion} downloaded successfully`,
);
return outputPath;
}
async function resolveOSVersion(deviceType: string, version: string) {
if (version !== 'menu') {
async function resolveOSVersion(
deviceType: string,
version: string,
): Promise<string> {
if (!['menu', 'menu-esr'].includes(version)) {
if (version[0] === 'v') {
version = version.slice(1);
}
return version;
}
const vs = (
(await getBalenaSdk().models.hostapp.getAllOsVersions([deviceType]))[
deviceType
] ?? []
).filter((v) => v.osType === 'default');
const vs = await getFormattedOsVersions(deviceType, version === 'menu-esr');
const choices = vs.map((v) => ({
value: v.rawVersion,
name: `v${v.rawVersion}` + (v.isRecommended ? ' (recommended)' : ''),
name: v.formattedVersion,
}));
return getCliForm().ask({
@ -214,3 +220,35 @@ async function resolveOSVersion(deviceType: string, version: string) {
default: (vs.find((v) => v.isRecommended) ?? vs[0])?.rawVersion,
});
}
/**
* Return the output of sdk.models.hostapp.getAvailableOsVersions(), filtered
* regarding ESR or non-ESR versions, and having the `formattedVersion` field
* reformatted for compatibility with the pre-existing output format of the
* `os versions` and `os download` commands.
*/
export async function getFormattedOsVersions(
deviceType: string,
esr: boolean,
): Promise<SDK.OsVersion[]> {
const versions: SDK.OsVersion[] = (
(await getBalenaSdk().models.hostapp.getAvailableOsVersions([deviceType]))[
deviceType
] ?? []
)
.filter((v: SDK.OsVersion) => v.osType === (esr ? 'esr' : 'default'))
.map((v: SDK.OsVersion) => {
const i = v.formattedVersion.indexOf(' ');
v.formattedVersion =
i < 0
? `v${v.rawVersion}`
: `v${v.rawVersion}${v.formattedVersion.substring(i)}`;
return v;
});
if (!versions.length) {
throw new ExpectedError(stripIndent`
Error: No balenaOS versions found for device type '${deviceType}'.
Double-check the device type slug with 'balena devices supported'.`);
}
return versions;
}

6
npm-shrinkwrap.json generated
View File

@ -3785,9 +3785,9 @@
}
},
"balena-image-manager": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/balena-image-manager/-/balena-image-manager-7.0.3.tgz",
"integrity": "sha512-KLb/5JksYxCR7JClq+MAuCMYPNMAXB9MgqubUvzj4mI/Yec3XD4xZ2BMITwINrl4sMKui/G7t/R5tBNFZsFe9w==",
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/balena-image-manager/-/balena-image-manager-7.1.0.tgz",
"integrity": "sha512-W8Etn0PBQJUlTJ1m1rCuQQ8TTLdkBoNP2SRHQqez2HANQp+T38wFjQXVx9PhQ6J7eqOYuW87SkJiKLpnmlz79Q==",
"requires": {
"balena-sdk": "^15.2.1",
"mime": "^2.4.6",

View File

@ -205,7 +205,7 @@
"balena-device-init": "^6.0.0",
"balena-errors": "^4.7.1",
"balena-image-fs": "^7.0.6",
"balena-image-manager": "^7.0.3",
"balena-image-manager": "^7.1.0",
"balena-preload": "^11.0.0",
"balena-release": "^3.2.0",
"balena-sdk": "^15.51.1",