balena-cli
Version:
The official balena Command Line Interface
166 lines (150 loc) • 6.61 kB
text/typescript
/**
* @license
* 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.
* 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.
*/
import { Flags, Args, Command } from '@oclif/core';
import { getBalenaSdk, stripIndent } from '../../utils/lazy';
export default class OsDownloadCmd extends Command {
public static description = stripIndent`
Download an unconfigured OS image.
Download an unconfigured OS image for the specified device type.
Check available device types with 'balena device-type list'.
Note: Currently this command only works with balenaCloud, not openBalena.
If using openBalena, please download the OS from: https://www.balena.io/os/
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).
Use '--type' to specify the type of OS download
If omitted, the default type for the specified device type-version combination is used.
Some OS download types may not be available for certain device types and 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/
Development images can be selected by appending \`.dev\` to the version.
`;
public static examples = [
'$ balena os download raspberrypi3 -o ../foo/bar/raspberrypi3.img',
'$ balena os download raspberrypi3 -o ../foo/bar/raspberrypi3.img --version 2.101.7',
'$ balena os download raspberrypi3 -o ../foo/bar/raspberrypi3.img --version 2022.7.0',
'$ balena os download raspberrypi3 -o ../foo/bar/raspberrypi3.img --version ^2.90.0',
'$ balena os download raspberrypi3 -o ../foo/bar/raspberrypi3.img --version 2.60.1+rev1',
'$ balena os download raspberrypi3 -o ../foo/bar/raspberrypi3.img --version 2.60.1+rev1.dev',
'$ balena os download raspberrypi3 -o ../foo/bar/raspberrypi3.img --version 2021.10.2.prod',
'$ balena os download raspberrypi3 -o ../foo/bar/raspberrypi3.img --version latest',
'$ balena os download raspberrypi3 -o ../foo/bar/raspberrypi3.img --version menu',
'$ balena os download raspberrypi3 -o ../foo/bar/raspberrypi3.img --version menu-esr',
'$ balena os download generic-amd64 -o ../foo/bar/generic-amd64.img --type installation-media',
];
public static args = {
type: Args.string({
description: 'the device type',
required: true,
}),
};
public static flags = {
output: Flags.string({
description: 'output path',
char: 'o',
required: true,
}),
version: Flags.string({
description: stripIndent`
version number (ESR or non-ESR versions),
or semver range (non-ESR versions only),
or 'latest' (excludes invalidated & pre-releases),
or 'menu' (interactive menu, non-ESR versions),
or 'menu-esr' (interactive menu, ESR versions)
`,
}),
type: Flags.string({
options: ['installation-media', 'disk-image'],
description: stripIndent`
'disk-image' (for flashing onto device system disk/storage)
or 'installation-media' (for creating installation media to automatically erase, format, and install balenaOS on a device)
`,
}),
};
public async run() {
const { args: params, flags: options } = await this.parse(OsDownloadCmd);
const { downloadOSImage, isESR } = await import('../../utils/os');
const balena = getBalenaSdk();
// TODO: Check the OS release's assets for a file that would start with `balena-image-flasher-${DEVICE_TYPE_SLUG}.manifest` once they have been backfilled
const dtManifest = await balena.models.config.getDeviceTypeManifestBySlug(
params.type,
);
const defaultImageType = /^(resin|balena)-image-flasher\b/.test(
dtManifest.yocto.deployArtifact,
)
? 'installation-media'
: 'disk-image';
if (
options.type === 'installation-media' ||
(defaultImageType === 'installation-media' && !options.type)
) {
// If the user is downloading an installation-media image, warn them that an installation-media image will wipe the target device's storage
// This is because some users may not understand the difference between an installation-media and disk-image, and may be surprised that the downloaded image will wipe their device when flashed
// Additionally, when no type is specified, the type of image downloaded depends on the device type, and some device types default to installation-media images, so we want to warn in that case as well
console.warn(
"WARNING: balenaOS installation media automatically and without confirmation erases and formats the target device's internal storage when booted.",
);
}
// balenaOS ESR versions require user authentication
if (options.version) {
if (options.version === 'menu-esr' || isESR(options.version)) {
try {
const { checkLoggedIn } = await import('../../utils/patterns');
await checkLoggedIn();
} catch (e) {
const { ExpectedError, NotLoggedInError } =
await import('../../errors');
if (e instanceof NotLoggedInError) {
throw new ExpectedError(stripIndent`
${e.message}
User authentication is required to download balenaOS ESR versions.`);
}
throw e;
}
}
}
try {
await downloadOSImage(
params.type,
options.output,
options.version,
defaultImageType === options.type
? undefined
: (options.type as 'installation-media' | 'disk-image' | undefined),
);
} catch (e) {
e.deviceTypeSlug = params.type;
e.message ??= '';
const { OSVersionNotFoundError } = await import('../../errors');
if (e instanceof OSVersionNotFoundError) {
const version = options.version ?? '';
if (
!version.endsWith('.dev') &&
!version.endsWith('.prod') &&
/^v?\d+\.\d+\.\d+/.test(version)
) {
e.message += `
** Hint: some OS releases require specifying the full OS version including
** the '.prod' or '.dev' suffix, e.g. '--version 2021.10.2.prod'`;
}
}
throw e;
}
}
}