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>
Inject a config.json file to a mounted filesystem, e.g. the SD card of a
provisioned device or balenaOS image.
Inject a 'config.json' file to a balenaOS image file or attached SD card or
USB stick.
Note: if using a private/custom device type, please ensure you are logged in
('balena login' command). Public device types do not require logging in.
Documentation for the balenaOS 'config.json' file can be found at:
https://www.balena.io/docs/reference/OS/configuration/
Examples:
$ balena config inject my/config.json --type raspberrypi3
$ balena config inject my/config.json --type raspberrypi3 --drive /dev/disk2
$ balena config inject my/config.json
$ balena config inject my/config.json --drive /dev/disk2
### Arguments
@ -2629,7 +2629,7 @@ the path to the config.json file to inject
#### -t, --type TYPE
device type (Check available types with `balena devices supported`)
ignored - no longer required
#### -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
Read the config.json file from the mounted filesystem,
e.g. the SD card of a provisioned device or balenaOS image.
Read the 'config.json' file of a balenaOS image file or 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:
$ balena config read --type raspberrypi3
$ balena config read --type raspberrypi3 --drive /dev/disk2
$ balena config read
$ balena config read --drive /dev/disk2
$ balena config read --drive balena.img
### Options
#### -t, --type TYPE
device type (Check available types with `balena devices supported`)
ignored - no longer required
#### -d, --drive DRIVE
@ -2661,19 +2665,26 @@ produce JSON output instead of tabular output
## 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:
$ balena config reconfigure --type raspberrypi3
$ balena config reconfigure --type raspberrypi3 --advanced
$ balena config reconfigure --type raspberrypi3 --drive /dev/disk2
$ balena config reconfigure
$ balena config reconfigure --drive /dev/disk3
$ balena config reconfigure --drive balena.img --advanced
### Options
#### -t, --type TYPE
device type (Check available types with `balena devices supported`)
ignored - no longer required
#### -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
#### --version VERSION
balenaOS version, for example "2.32.0" or "2.44.0+rev1"
## config write <key> <value>
Write a key-value pair to the config.json file on the mounted filesystem,
e.g. the SD card of a provisioned device or balenaOS image.
Write a key-value pair to the 'config.json' file of a balenaOS image file or
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:
$ balena config write --type raspberrypi3 username johndoe
$ balena config write --type raspberrypi3 --drive /dev/disk2 username johndoe
$ balena config write --type raspberrypi3 files.network/settings "..."
$ balena config write ntpServers "0.resinio.pool.ntp.org 1.resinio.pool.ntp.org"
$ balena config write --drive /dev/disk2 hostname custom-hostname
$ balena config write --drive balena.img os.network.connectivity.interval 300
### Arguments
@ -2708,7 +2726,7 @@ the value of the config parameter to write
#### -t, --type TYPE
device type (Check available types with `balena devices supported`)
ignored - no longer required
#### -d, --drive DRIVE

View File

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

View File

@ -21,7 +21,7 @@ import * as cf from '../../utils/common-flags';
import { getVisuals, stripIndent } from '../../utils/lazy';
interface FlagsDef {
type: string;
type?: string;
drive?: string;
help: void;
json: boolean;
@ -29,28 +29,30 @@ interface FlagsDef {
export default class ConfigReadCmd extends Command {
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,
e.g. the SD card of a provisioned device or balenaOS image.
Read the 'config.json' file of a balenaOS image file or 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 = [
'$ balena config read --type raspberrypi3',
'$ balena config read --type raspberrypi3 --drive /dev/disk2',
'$ balena config read',
'$ balena config read --drive /dev/disk2',
'$ balena config read --drive balena.img',
];
public static usage = 'config read';
public static flags: flags.Input<FlagsDef> = {
type: cf.deviceType,
type: cf.deviceTypeIgnored,
drive: cf.driveOrImg,
help: cf.help,
json: cf.json,
};
public static authenticated = true;
public static root = true;
public async run() {
@ -63,7 +65,7 @@ export default class ConfigReadCmd extends Command {
await safeUmount(drive);
const config = await import('balena-config-json');
const configJSON = await config.read(drive, options.type);
const configJSON = await config.read(drive, '');
if (options.json) {
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';
interface FlagsDef {
type: string;
type?: string;
drive?: string;
advanced: boolean;
help: void;
version?: string;
}
export default class ConfigReconfigureCmd extends Command {
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 = [
'$ balena config reconfigure --type raspberrypi3',
'$ balena config reconfigure --type raspberrypi3 --advanced',
'$ balena config reconfigure --type raspberrypi3 --drive /dev/disk2',
'$ balena config reconfigure',
'$ balena config reconfigure --drive /dev/disk3',
'$ balena config reconfigure --drive balena.img --advanced',
];
public static usage = 'config reconfigure';
public static flags: flags.Input<FlagsDef> = {
type: cf.deviceType,
type: cf.deviceTypeIgnored,
drive: cf.driveOrImg,
advanced: flags.boolean({
description: 'show advanced commands',
char: 'v',
}),
help: cf.help,
version: flags.string({
description: 'balenaOS version, for example "2.32.0" or "2.44.0+rev1"',
}),
};
public static authenticated = true;
@ -65,10 +76,20 @@ export default class ConfigReconfigureCmd extends Command {
await safeUmount(drive);
const config = await import('balena-config-json');
const { uuid } = await config.read(drive, options.type);
const { uuid } = await config.read(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];
if (options.version) {
configureCommand.push('--version', options.version);
}
if (options.advanced) {
configureCommand.push('--advanced');
}

View File

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

View File

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

View File

@ -113,6 +113,13 @@ export const deviceType = flags.string({
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({
char: 'j',
description: 'produce JSON output instead of tabular output',

12
npm-shrinkwrap.json generated
View File

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

View File

@ -201,7 +201,7 @@
"@types/update-notifier": "^4.1.1",
"@zeit/dockerignore": "0.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-errors": "^4.7.1",
"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;
}