Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make the --type parameter in os initialize & the --device-type parameter in os build-config optional #2907

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/balena-cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -3048,6 +3048,7 @@ because we need to access the raw devices directly.

Examples:

$ balena os initialize ../path/rpi.img
$ balena os initialize ../path/rpi.img --type raspberry-pi

### Arguments
Expand Down
5 changes: 1 addition & 4 deletions src/commands/internal/osinit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,6 @@ export default class OsinitCmd extends Command {
image: Args.string({
required: true,
}),
type: Args.string({
required: true,
}),
config: Args.string({
required: true,
}),
Expand All @@ -58,7 +55,7 @@ export default class OsinitCmd extends Command {
const { getManifest, osProgressHandler } = await import(
'../../utils/helpers'
);
const manifest = await getManifest(params.image, params.type);
const manifest = await getManifest(params.image);

const { initialize } = await import('balena-device-init');
const initializeEmitter = await initialize(params.image, manifest, config);
Expand Down
14 changes: 13 additions & 1 deletion src/commands/os/build-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export default class OsBuildConfigCmd extends Command {
description: 'os image',
required: true,
}),
// TODO: Drop this arg on the next major
'device-type': Args.string({
description: 'device type',
required: true,
Expand All @@ -63,6 +64,12 @@ export default class OsBuildConfigCmd extends Command {

const { writeFile } = (await import('fs')).promises;

// the "device-type" arg will be removed on the next major - warn user
if (params['device-type'] != null) {
const { deviceTypeArgDeprecation } = await import('../../utils/messages');
console.log(deviceTypeArgDeprecation('device-type'));
}

const config = await this.buildConfig(
params.image,
params['device-type'],
Expand All @@ -74,7 +81,12 @@ export default class OsBuildConfigCmd extends Command {
console.info(`Config file "${options.output}" created successfully.`);
}

async buildConfig(image: string, deviceTypeSlug: string, advanced: boolean) {
async buildConfig(
image: string,
// TODO: Drop this parameter on the next major
deviceTypeSlug: string | undefined,
advanced: boolean,
) {
advanced = advanced || false;

const { getManifest } = await import('../../utils/helpers');
Expand Down
1 change: 1 addition & 0 deletions src/commands/os/configure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ export default class OsConfigureCmd extends Command {

const deviceTypeManifest = await helpers.getManifest(
params.image,
// TODO: Drop this in the next major in favor of calling checkManifestMatchesDeviceType() directly
deviceTypeSlug,
);

Expand Down
14 changes: 7 additions & 7 deletions src/commands/os/initialize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export default class OsInitializeCmd extends Command {
`;

public static examples = [
'$ balena os initialize ../path/rpi.img',
'$ balena os initialize ../path/rpi.img --type raspberry-pi',
];

Expand All @@ -63,6 +64,11 @@ export default class OsInitializeCmd extends Command {
console.info(`Initializing device ${INIT_WARNING_MESSAGE}`);

const manifest = await getManifest(params.image, options.type);
// the "type" arg will be removed on the next major - warn user
if (options.type != null) {
const { deviceTypeArgDeprecation } = await import('../../utils/messages');
console.log(deviceTypeArgDeprecation('type'));
}

const answers = await getCliForm().run(manifest.initialization?.options, {
override: {
Expand All @@ -81,13 +87,7 @@ export default class OsInitializeCmd extends Command {
await safeUmount(answers.drive);
}

await sudo([
'internal',
'osinit',
params.image,
options.type,
JSON.stringify(answers),
]);
await sudo(['internal', 'osinit', params.image, JSON.stringify(answers)]);

if (answers.drive != null) {
const { safeUmount } = await import('../../utils/umount');
Expand Down
1 change: 0 additions & 1 deletion src/utils/common-flags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,6 @@ export const deviceType = Flags.string({
description:
'device type (Check available types with `balena device-type list`)',
char: 't',
required: true,
});

export const json = Flags.boolean({
Expand Down
85 changes: 52 additions & 33 deletions src/utils/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ 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
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,
Expand Down Expand Up @@ -103,48 +103,67 @@ export async function runCommand<T>(commandArgs: string[]): Promise<T> {
return run(commandArgs) as Promise<T>;
}

export async function checkManifestMatchesDeviceType(
manifest: BalenaSdk.DeviceTypeJson.DeviceType,
deviceType: string,
) {
if (
manifest.slug !== deviceType &&
manifest.slug !==
(await getBalenaSdk().models.deviceType.get(deviceType)).slug
) {
const { ExpectedError } = await import('../errors');
throw new ExpectedError(
`The device type of the provided OS image ${manifest.slug}, does not match the expected device type ${deviceType}`,
);
}
}

export async function getManifest(
image: string,
deviceType: string,
// TODO: Drop this parameter in the next major
fallbackDeviceType?: string,
): Promise<BalenaSdk.DeviceTypeJson.DeviceType> {
const init = await import('balena-device-init');
const sdk = getBalenaSdk();
const manifest = await init.getImageManifest(image);
if (manifest != null) {
const config = manifest.configuration?.config;
if (config?.partition != null) {
const { getBootPartition } = await import('balena-config-json');
// Find the device-type.json property that holds the boot partition number for
// this device type (config.partition or config.partition.primary) and overwrite it
// with the boot partition number that was found by inspecting the image.
// since it's deprecated & no longer updated for newer releases.
if (typeof config.partition === 'number') {
config.partition = await getBootPartition(image);
} else if (config.partition.primary != null) {
config.partition.primary = await getBootPartition(image);
}
// TODO: Add handling for when we no longer include a `config.partition` at all.
if (manifest == null) {
// TODO: Change this in the next major to throw when not being able to find the manifest
// on the provided image, after confirming that this works for all supported OS versions.
if (fallbackDeviceType != null) {
console.error(
`[warn] Error while finding a device-type.json on the provided image path. Attempting to fetch from the API.`,
);
const sdk = getBalenaSdk();
return await sdk.models.config.getDeviceTypeManifestBySlug(
fallbackDeviceType,
);
}
} else {
// TODO: Change this in the next major to throw, after confirming that this works for all supported OS versions.
console.error(
`[warn] Error while finding a device-type.json on the provided image path. Attempting to fetch from the API.`,
);
}
if (
manifest != null &&
manifest.slug !== deviceType &&
manifest.slug !== (await sdk.models.deviceType.get(deviceType)).slug
) {
const { ExpectedError } = await import('../errors');
throw new ExpectedError(
`The device type of the provided OS image ${manifest.slug}, does not match the expected device type ${deviceType}`,
`Could not find the manifest on the provided image path '${image}'. Please double check that this is a valid balenaOS image.`,
);
}
return (
manifest ??
(await sdk.models.config.getDeviceTypeManifestBySlug(deviceType))
);

const config = manifest.configuration?.config;
if (config?.partition != null) {
const { getBootPartition } = await import('balena-config-json');
// Find the device-type.json property that holds the boot partition number for
// this device type (config.partition or config.partition.primary) and overwrite it
// with the boot partition number that was found by inspecting the image.
// since it's deprecated & no longer updated for newer releases.
if (typeof config.partition === 'number') {
config.partition = await getBootPartition(image);
} else if (config.partition.primary != null) {
config.partition.primary = await getBootPartition(image);
}
// TODO: Add handling for when we no longer include a `config.partition` at all.
}
// TODO: Drop this in the next major along with the fallbackDeviceType argument
// and move the checkManifestMatchesDeviceType() to the caller side when still necessary.
if (fallbackDeviceType != null) {
await checkManifestMatchesDeviceType(manifest, fallbackDeviceType);
}
return manifest;
}

export const areDeviceTypesCompatible = async (
Expand Down
6 changes: 6 additions & 0 deletions src/utils/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,12 @@ If you have a particular use for buildArg, which is not satisfied by build-time
secrets, please contact us via support or the forums: https://forums.balena.io/
\n`;

export const deviceTypeArgDeprecation = (paramName: string) => `\
WARNING: You have specified a '--${paramName}' option, which is now deprecated, and
may be removed in the future. The balena-cli will now try to auto-detect
the device type of the provided balenaOS image.
\n`;

export function getNodeEngineVersionWarn(
version: string,
validVersions: string,
Expand Down
Loading