config read/write/inject: Avoid need for internet access

Change-type: minor
This commit is contained in:
Paulo Castro 2021-11-24 23:00:38 +00:00
parent e4870916e2
commit b546e4dd97
10 changed files with 121 additions and 92 deletions

View File

@ -2608,16 +2608,16 @@ the wifi key to use (used only if --network is set to wifi)
## config inject <file> ## config inject <file>
Inject a config.json file to a mounted filesystem, e.g. the SD card of a Inject a 'config.json' file to a balenaOS image file or attached SD card or
provisioned device or balenaOS image. USB stick.
Note: if using a private/custom device type, please ensure you are logged in Documentation for the balenaOS 'config.json' file can be found at:
('balena login' command). Public device types do not require logging in. https://www.balena.io/docs/reference/OS/configuration/
Examples: Examples:
$ balena config inject my/config.json --type raspberrypi3 $ balena config inject my/config.json
$ balena config inject my/config.json --type raspberrypi3 --drive /dev/disk2 $ balena config inject my/config.json --drive /dev/disk2
### Arguments ### Arguments
@ -2629,7 +2629,7 @@ the path to the config.json file to inject
#### -t, --type TYPE #### -t, --type TYPE
device type (Check available types with `balena devices supported`) ignored - no longer required
#### -d, --drive DRIVE #### -d, --drive DRIVE
@ -2637,19 +2637,23 @@ path to OS image file (e.g. balena.img) or block device (e.g. /dev/disk2)
## config read ## config read
Read the config.json file from the mounted filesystem, Read the 'config.json' file of a balenaOS image file or attached SD card or
e.g. the SD card of a provisioned device or balenaOS image. USB stick.
Documentation for the balenaOS 'config.json' file can be found at:
https://www.balena.io/docs/reference/OS/configuration/
Examples: Examples:
$ balena config read --type raspberrypi3 $ balena config read
$ balena config read --type raspberrypi3 --drive /dev/disk2 $ balena config read --drive /dev/disk2
$ balena config read --drive balena.img
### Options ### Options
#### -t, --type TYPE #### -t, --type TYPE
device type (Check available types with `balena devices supported`) ignored - no longer required
#### -d, --drive DRIVE #### -d, --drive DRIVE
@ -2661,19 +2665,26 @@ produce JSON output instead of tabular output
## config reconfigure ## config reconfigure
Interactively reconfigure a provisioned device or OS image. Interactively reconfigure a balenaOS image file or attached media.
This command extracts the device UUID from the 'config.json' file of the
chosen balenaOS image file or attached media, and then passes the UUID as
the '--device' argument to the 'balena os configure' command.
For finer-grained or scripted control of the operation, use the
'balena config read' and 'balena os configure' commands separately.
Examples: Examples:
$ balena config reconfigure --type raspberrypi3 $ balena config reconfigure
$ balena config reconfigure --type raspberrypi3 --advanced $ balena config reconfigure --drive /dev/disk3
$ balena config reconfigure --type raspberrypi3 --drive /dev/disk2 $ balena config reconfigure --drive balena.img --advanced
### Options ### Options
#### -t, --type TYPE #### -t, --type TYPE
device type (Check available types with `balena devices supported`) ignored - no longer required
#### -d, --drive DRIVE #### -d, --drive DRIVE
@ -2683,16 +2694,23 @@ path to OS image file (e.g. balena.img) or block device (e.g. /dev/disk2)
show advanced commands show advanced commands
#### --version VERSION
balenaOS version, for example "2.32.0" or "2.44.0+rev1"
## config write <key> <value> ## config write <key> <value>
Write a key-value pair to the config.json file on the mounted filesystem, Write a key-value pair to the 'config.json' file of a balenaOS image file or
e.g. the SD card of a provisioned device or balenaOS image. attached SD card or USB stick.
Documentation for the balenaOS 'config.json' file can be found at:
https://www.balena.io/docs/reference/OS/configuration/
Examples: Examples:
$ balena config write --type raspberrypi3 username johndoe $ balena config write ntpServers "0.resinio.pool.ntp.org 1.resinio.pool.ntp.org"
$ balena config write --type raspberrypi3 --drive /dev/disk2 username johndoe $ balena config write --drive /dev/disk2 hostname custom-hostname
$ balena config write --type raspberrypi3 files.network/settings "..." $ balena config write --drive balena.img os.network.connectivity.interval 300
### Arguments ### Arguments
@ -2708,7 +2726,7 @@ the value of the config parameter to write
#### -t, --type TYPE #### -t, --type TYPE
device type (Check available types with `balena devices supported`) ignored - no longer required
#### -d, --drive DRIVE #### -d, --drive DRIVE

View File

@ -21,7 +21,7 @@ import * as cf from '../../utils/common-flags';
import { getVisuals, stripIndent } from '../../utils/lazy'; import { getVisuals, stripIndent } from '../../utils/lazy';
interface FlagsDef { interface FlagsDef {
type: string; type?: string;
drive?: string; drive?: string;
help: void; help: void;
} }
@ -32,18 +32,18 @@ interface ArgsDef {
export default class ConfigInjectCmd extends Command { export default class ConfigInjectCmd extends Command {
public static description = stripIndent` public static description = stripIndent`
Inject a configuration file into a device or OS image. Inject a config.json file to a balenaOS image or attached media.
Inject a config.json file to a mounted filesystem, e.g. the SD card of a Inject a 'config.json' file to a balenaOS image file or attached SD card or
provisioned device or balenaOS image. USB stick.
Note: if using a private/custom device type, please ensure you are logged in Documentation for the balenaOS 'config.json' file can be found at:
('balena login' command). Public device types do not require logging in. https://www.balena.io/docs/reference/OS/configuration/
`; `;
public static examples = [ public static examples = [
'$ balena config inject my/config.json --type raspberrypi3', '$ balena config inject my/config.json',
'$ balena config inject my/config.json --type raspberrypi3 --drive /dev/disk2', '$ balena config inject my/config.json --drive /dev/disk2',
]; ];
public static args = [ public static args = [
@ -57,7 +57,7 @@ export default class ConfigInjectCmd extends Command {
public static usage = 'config inject <file>'; public static usage = 'config inject <file>';
public static flags: flags.Input<FlagsDef> = { public static flags: flags.Input<FlagsDef> = {
type: cf.deviceType, type: cf.deviceTypeIgnored,
drive: cf.driveOrImg, drive: cf.driveOrImg,
help: cf.help, help: cf.help,
}; };
@ -81,7 +81,7 @@ export default class ConfigInjectCmd extends Command {
); );
const config = await import('balena-config-json'); const config = await import('balena-config-json');
await config.write(drive, options.type, configJSON); await config.write(drive, '', configJSON);
console.info('Done'); console.info('Done');
} }

View File

@ -21,7 +21,7 @@ import * as cf from '../../utils/common-flags';
import { getVisuals, stripIndent } from '../../utils/lazy'; import { getVisuals, stripIndent } from '../../utils/lazy';
interface FlagsDef { interface FlagsDef {
type: string; type?: string;
drive?: string; drive?: string;
help: void; help: void;
json: boolean; json: boolean;
@ -29,28 +29,30 @@ interface FlagsDef {
export default class ConfigReadCmd extends Command { export default class ConfigReadCmd extends Command {
public static description = stripIndent` public static description = stripIndent`
Read the configuration of a device or OS image. Read the config.json file of a balenaOS image or attached media.
Read the config.json file from the mounted filesystem, Read the 'config.json' file of a balenaOS image file or attached SD card or
e.g. the SD card of a provisioned device or balenaOS image. USB stick.
Documentation for the balenaOS 'config.json' file can be found at:
https://www.balena.io/docs/reference/OS/configuration/
`; `;
public static examples = [ public static examples = [
'$ balena config read --type raspberrypi3', '$ balena config read',
'$ balena config read --type raspberrypi3 --drive /dev/disk2', '$ balena config read --drive /dev/disk2',
'$ balena config read --drive balena.img',
]; ];
public static usage = 'config read'; public static usage = 'config read';
public static flags: flags.Input<FlagsDef> = { public static flags: flags.Input<FlagsDef> = {
type: cf.deviceType, type: cf.deviceTypeIgnored,
drive: cf.driveOrImg, drive: cf.driveOrImg,
help: cf.help, help: cf.help,
json: cf.json, json: cf.json,
}; };
public static authenticated = true;
public static root = true; public static root = true;
public async run() { public async run() {
@ -63,7 +65,7 @@ export default class ConfigReadCmd extends Command {
await safeUmount(drive); await safeUmount(drive);
const config = await import('balena-config-json'); const config = await import('balena-config-json');
const configJSON = await config.read(drive, options.type); const configJSON = await config.read(drive, '');
if (options.json) { if (options.json) {
console.log(JSON.stringify(configJSON, null, 4)); console.log(JSON.stringify(configJSON, null, 4));

View File

@ -21,34 +21,45 @@ import * as cf from '../../utils/common-flags';
import { getVisuals, stripIndent } from '../../utils/lazy'; import { getVisuals, stripIndent } from '../../utils/lazy';
interface FlagsDef { interface FlagsDef {
type: string; type?: string;
drive?: string; drive?: string;
advanced: boolean; advanced: boolean;
help: void; help: void;
version?: string;
} }
export default class ConfigReconfigureCmd extends Command { export default class ConfigReconfigureCmd extends Command {
public static description = stripIndent` public static description = stripIndent`
Interactively reconfigure a device or OS image. Interactively reconfigure a balenaOS image file or attached media.
Interactively reconfigure a provisioned device or OS image. Interactively reconfigure a balenaOS image file or attached media.
This command extracts the device UUID from the 'config.json' file of the
chosen balenaOS image file or attached media, and then passes the UUID as
the '--device' argument to the 'balena os configure' command.
For finer-grained or scripted control of the operation, use the
'balena config read' and 'balena os configure' commands separately.
`; `;
public static examples = [ public static examples = [
'$ balena config reconfigure --type raspberrypi3', '$ balena config reconfigure',
'$ balena config reconfigure --type raspberrypi3 --advanced', '$ balena config reconfigure --drive /dev/disk3',
'$ balena config reconfigure --type raspberrypi3 --drive /dev/disk2', '$ balena config reconfigure --drive balena.img --advanced',
]; ];
public static usage = 'config reconfigure'; public static usage = 'config reconfigure';
public static flags: flags.Input<FlagsDef> = { public static flags: flags.Input<FlagsDef> = {
type: cf.deviceType, type: cf.deviceTypeIgnored,
drive: cf.driveOrImg, drive: cf.driveOrImg,
advanced: flags.boolean({ advanced: flags.boolean({
description: 'show advanced commands', description: 'show advanced commands',
char: 'v', char: 'v',
}), }),
help: cf.help, help: cf.help,
version: flags.string({
description: 'balenaOS version, for example "2.32.0" or "2.44.0+rev1"',
}),
}; };
public static authenticated = true; public static authenticated = true;
@ -65,10 +76,20 @@ export default class ConfigReconfigureCmd extends Command {
await safeUmount(drive); await safeUmount(drive);
const config = await import('balena-config-json'); const config = await import('balena-config-json');
const { uuid } = await config.read(drive, options.type); const { uuid } = await config.read(drive, '');
await safeUmount(drive); await safeUmount(drive);
if (!uuid) {
const { ExpectedError } = await import('../../errors');
throw new ExpectedError(
`Error: UUID not found in 'config.json' file for '${drive}'`,
);
}
const configureCommand = ['os', 'configure', drive, '--device', uuid]; const configureCommand = ['os', 'configure', drive, '--device', uuid];
if (options.version) {
configureCommand.push('--version', options.version);
}
if (options.advanced) { if (options.advanced) {
configureCommand.push('--advanced'); configureCommand.push('--advanced');
} }

View File

@ -21,7 +21,7 @@ import * as cf from '../../utils/common-flags';
import { getVisuals, stripIndent } from '../../utils/lazy'; import { getVisuals, stripIndent } from '../../utils/lazy';
interface FlagsDef { interface FlagsDef {
type: string; type?: string;
drive?: string; drive?: string;
help: void; help: void;
} }
@ -33,16 +33,19 @@ interface ArgsDef {
export default class ConfigWriteCmd extends Command { export default class ConfigWriteCmd extends Command {
public static description = stripIndent` public static description = stripIndent`
Write a key-value pair to configuration of a device or OS image. Write a key-value pair to the config.json file of an OS image or attached media.
Write a key-value pair to the config.json file on the mounted filesystem, Write a key-value pair to the 'config.json' file of a balenaOS image file or
e.g. the SD card of a provisioned device or balenaOS image. attached SD card or USB stick.
Documentation for the balenaOS 'config.json' file can be found at:
https://www.balena.io/docs/reference/OS/configuration/
`; `;
public static examples = [ public static examples = [
'$ balena config write --type raspberrypi3 username johndoe', '$ balena config write ntpServers "0.resinio.pool.ntp.org 1.resinio.pool.ntp.org"',
'$ balena config write --type raspberrypi3 --drive /dev/disk2 username johndoe', '$ balena config write --drive /dev/disk2 hostname custom-hostname',
'$ balena config write --type raspberrypi3 files.network/settings "..."', '$ balena config write --drive balena.img os.network.connectivity.interval 300',
]; ];
public static args = [ public static args = [
@ -61,13 +64,11 @@ export default class ConfigWriteCmd extends Command {
public static usage = 'config write <key> <value>'; public static usage = 'config write <key> <value>';
public static flags: flags.Input<FlagsDef> = { public static flags: flags.Input<FlagsDef> = {
type: cf.deviceType, type: cf.deviceTypeIgnored,
drive: cf.driveOrImg, drive: cf.driveOrImg,
help: cf.help, help: cf.help,
}; };
public static authenticated = true;
public static root = true; public static root = true;
public async run() { public async run() {
@ -82,14 +83,14 @@ export default class ConfigWriteCmd extends Command {
await safeUmount(drive); await safeUmount(drive);
const config = await import('balena-config-json'); const config = await import('balena-config-json');
const configJSON = await config.read(drive, options.type); const configJSON = await config.read(drive, '');
console.info(`Setting ${params.key} to ${params.value}`); console.info(`Setting ${params.key} to ${params.value}`);
ConfigWriteCmd.updateConfigJson(configJSON, params.key, params.value); ConfigWriteCmd.updateConfigJson(configJSON, params.key, params.value);
await denyMount(drive, async () => { await denyMount(drive, async () => {
await safeUmount(drive); await safeUmount(drive);
await config.write(drive, options.type, configJSON); await config.write(drive, '', configJSON);
}); });
console.info('Done'); console.info('Done');

View File

@ -187,6 +187,8 @@ export default class OsConfigureCmd extends Command {
help: cf.help, help: cf.help,
}; };
public static authenticated = true;
public async run() { public async run() {
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>( const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
OsConfigureCmd, OsConfigureCmd,

View File

@ -113,6 +113,13 @@ export const deviceType = flags.string({
required: true, required: true,
}); });
export const deviceTypeIgnored = flags.string({
description: 'ignored - no longer required',
char: 't',
required: false,
hidden: isV13(),
});
export const json: IBooleanFlag<boolean> = flags.boolean({ export const json: IBooleanFlag<boolean> = flags.boolean({
char: 'j', char: 'j',
description: 'produce JSON output instead of tabular output', description: 'produce JSON output instead of tabular output',

12
npm-shrinkwrap.json generated
View File

@ -3634,13 +3634,13 @@
} }
}, },
"balena-config-json": { "balena-config-json": {
"version": "4.1.1", "version": "4.2.0",
"resolved": "https://registry.npmjs.org/balena-config-json/-/balena-config-json-4.1.1.tgz", "resolved": "https://registry.npmjs.org/balena-config-json/-/balena-config-json-4.2.0.tgz",
"integrity": "sha512-zpYt3SbXxe1OgmLcA8RVecrBgVH1sThYVAd9irfp/NOjKgk0bRiVjx2rG7yLROB7gcLxYDeivP4pLTTDtpylHQ==", "integrity": "sha512-k0/2y1FmZni2EAVYHfWFme/F1xchAcvHweDA9QCEHm83LU0+j6v/Hk9RZ1IhipRty2jDSEw1BorYVrYmx9+Psg==",
"requires": { "requires": {
"balena-image-fs": "^7.0.4", "balena-image-fs": "^7.0.6",
"balena-sdk": "^15.2.1", "file-disk": "^8.0.1",
"lodash": "^4.17.19" "partitioninfo": "^6.0.2"
} }
}, },
"balena-device-init": { "balena-device-init": {

View File

@ -201,7 +201,7 @@
"@types/update-notifier": "^4.1.1", "@types/update-notifier": "^4.1.1",
"@zeit/dockerignore": "0.0.3", "@zeit/dockerignore": "0.0.3",
"JSONStream": "^1.0.3", "JSONStream": "^1.0.3",
"balena-config-json": "^4.1.1", "balena-config-json": "^4.2.0",
"balena-device-init": "^6.0.0", "balena-device-init": "^6.0.0",
"balena-errors": "^4.7.1", "balena-errors": "^4.7.1",
"balena-image-fs": "^7.0.6", "balena-image-fs": "^7.0.6",

View File

@ -1,22 +0,0 @@
/**
* @license
* Copyright 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.
*/
declare module 'balena-config-json' {
export function read(image: string, type: string): Promise<any>;
export function write(image: string, type: string, config: any): Promise;
}