mirror of
https://github.com/balena-os/balena-supervisor.git
synced 2025-02-01 08:47:56 +00:00
Merge pull request #1440 from balena-io/1437-patch-empty-config
Preventing removing all configurations if device has no backends
This commit is contained in:
commit
ac69f04c10
@ -447,9 +447,7 @@ export class APIBinder {
|
||||
const defaultConfig = deviceConfig.getDefaults();
|
||||
|
||||
const currentState = await this.deviceState.getCurrentForComparison();
|
||||
const targetConfig = await deviceConfig.formatConfigKeys(
|
||||
targetConfigUnformatted,
|
||||
);
|
||||
const targetConfig = deviceConfig.formatConfigKeys(targetConfigUnformatted);
|
||||
|
||||
if (!currentState.local.config) {
|
||||
throw new InternalInconsistencyError(
|
||||
|
@ -1,11 +1,17 @@
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { Extlinux } from './extlinux';
|
||||
import { ExtraUEnv } from './extra-uEnv';
|
||||
import { ConfigTxt } from './config-txt';
|
||||
import { ConfigFs } from './config-fs';
|
||||
|
||||
export default [
|
||||
export const allBackends = [
|
||||
new Extlinux(),
|
||||
new ExtraUEnv(),
|
||||
new ConfigTxt(),
|
||||
new ConfigFs(),
|
||||
];
|
||||
|
||||
export function matchesAnyBootConfig(envVar: string): boolean {
|
||||
return allBackends.some((a) => a.isBootConfigVar(envVar));
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import * as config from '../config';
|
||||
import * as constants from '../lib/constants';
|
||||
import { getMetaOSRelease } from '../lib/os-release';
|
||||
import { EnvVarObject } from '../lib/types';
|
||||
import Backends from './backends';
|
||||
import { allBackends as Backends } from './backends';
|
||||
import { ConfigOptions, ConfigBackend } from './backends/backend';
|
||||
|
||||
export async function getSupportedBackends(): Promise<ConfigBackend[]> {
|
||||
@ -51,37 +51,7 @@ export function bootConfigToEnv(
|
||||
.value();
|
||||
}
|
||||
|
||||
export function formatConfigKeys(
|
||||
configBackend: ConfigBackend | null,
|
||||
allowedKeys: string[],
|
||||
conf: { [key: string]: any },
|
||||
): { [key: string]: any } {
|
||||
const isConfigType = configBackend != null;
|
||||
const namespaceRegex = /^BALENA_(.*)/;
|
||||
const legacyNamespaceRegex = /^RESIN_(.*)/;
|
||||
const confFromNamespace = filterNamespaceFromConfig(namespaceRegex, conf);
|
||||
const confFromLegacyNamespace = filterNamespaceFromConfig(
|
||||
legacyNamespaceRegex,
|
||||
conf,
|
||||
);
|
||||
const noNamespaceConf = _.pickBy(conf, (_v, k) => {
|
||||
return !_.startsWith(k, 'RESIN_') && !_.startsWith(k, 'BALENA_');
|
||||
});
|
||||
const confWithoutNamespace = _.defaults(
|
||||
confFromNamespace,
|
||||
confFromLegacyNamespace,
|
||||
noNamespaceConf,
|
||||
);
|
||||
|
||||
return _.pickBy(confWithoutNamespace, (_v, k) => {
|
||||
return (
|
||||
_.includes(allowedKeys, k) ||
|
||||
(isConfigType && configBackend!.isBootConfigVar(k))
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function filterNamespaceFromConfig(
|
||||
export function filterNamespaceFromConfig(
|
||||
namespace: RegExp,
|
||||
conf: { [key: string]: any },
|
||||
): { [key: string]: any } {
|
||||
|
@ -2,17 +2,17 @@ import * as _ from 'lodash';
|
||||
import { inspect } from 'util';
|
||||
|
||||
import * as config from './config';
|
||||
import { SchemaTypeKey } from './config/schema-type';
|
||||
import * as db from './db';
|
||||
import * as logger from './logger';
|
||||
|
||||
import { ConfigOptions, ConfigBackend } from './config/backends/backend';
|
||||
import * as configUtils from './config/utils';
|
||||
import * as dbus from './lib/dbus';
|
||||
import { UnitNotLoadedError } from './lib/errors';
|
||||
import { EnvVarObject } from './lib/types';
|
||||
import { UnitNotLoadedError } from './lib/errors';
|
||||
import { checkInt, checkTruthy } from './lib/validation';
|
||||
import { DeviceStatus } from './types/state';
|
||||
import * as configUtils from './config/utils';
|
||||
import { SchemaTypeKey } from './config/schema-type';
|
||||
import { matchesAnyBootConfig } from './config/backends';
|
||||
import { ConfigOptions, ConfigBackend } from './config/backends/backend';
|
||||
|
||||
const vpnServiceName = 'openvpn';
|
||||
|
||||
@ -229,7 +229,7 @@ export async function setTarget(
|
||||
): Promise<void> {
|
||||
const $db = trx ?? db.models.bind(db);
|
||||
|
||||
const formatted = await formatConfigKeys(target);
|
||||
const formatted = formatConfigKeys(target);
|
||||
// check for legacy keys
|
||||
if (formatted['OVERRIDE_LOCK'] != null) {
|
||||
formatted['SUPERVISOR_OVERRIDE_LOCK'] = formatted['OVERRIDE_LOCK'];
|
||||
@ -298,18 +298,30 @@ export async function getCurrent(): Promise<Dictionary<string>> {
|
||||
return currentConf;
|
||||
}
|
||||
|
||||
export async function formatConfigKeys(
|
||||
conf: Dictionary<string>,
|
||||
): Promise<Dictionary<any>> {
|
||||
const backends = await getConfigBackends();
|
||||
const formattedKeys: Dictionary<any> = {};
|
||||
for (const backend of backends) {
|
||||
_.assign(
|
||||
formattedKeys,
|
||||
configUtils.formatConfigKeys(backend, validKeys, conf),
|
||||
);
|
||||
}
|
||||
return formattedKeys;
|
||||
export function formatConfigKeys(conf: {
|
||||
[key: string]: any;
|
||||
}): Dictionary<any> {
|
||||
const namespaceRegex = /^BALENA_(.*)/;
|
||||
const legacyNamespaceRegex = /^RESIN_(.*)/;
|
||||
const confFromNamespace = configUtils.filterNamespaceFromConfig(
|
||||
namespaceRegex,
|
||||
conf,
|
||||
);
|
||||
const confFromLegacyNamespace = configUtils.filterNamespaceFromConfig(
|
||||
legacyNamespaceRegex,
|
||||
conf,
|
||||
);
|
||||
const noNamespaceConf = _.pickBy(conf, (_v, k) => {
|
||||
return !_.startsWith(k, 'RESIN_') && !_.startsWith(k, 'BALENA_');
|
||||
});
|
||||
const confWithoutNamespace = _.defaults(
|
||||
confFromNamespace,
|
||||
confFromLegacyNamespace,
|
||||
noNamespaceConf,
|
||||
);
|
||||
return _.pickBy(confWithoutNamespace, (_v, k) => {
|
||||
return _.includes(validKeys, k) || matchesAnyBootConfig(k);
|
||||
});
|
||||
}
|
||||
|
||||
export function getDefaults() {
|
||||
|
@ -80,9 +80,7 @@ export async function loadTargetFromFile(
|
||||
}
|
||||
|
||||
const deviceConf = await deviceConfig.getCurrent();
|
||||
const formattedConf = await deviceConfig.formatConfigKeys(
|
||||
preloadState.config,
|
||||
);
|
||||
const formattedConf = deviceConfig.formatConfigKeys(preloadState.config);
|
||||
preloadState.config = { ...formattedConf, ...deviceConf };
|
||||
const localState = {
|
||||
local: { name: '', ...preloadState },
|
||||
|
@ -168,19 +168,22 @@ describe('Device Backend Config', () => {
|
||||
it('accepts RESIN_ and BALENA_ variables', async () => {
|
||||
return expect(
|
||||
deviceConfig.formatConfigKeys({
|
||||
FOO: 'bar',
|
||||
BAR: 'baz',
|
||||
RESIN_HOST_CONFIG_foo: 'foobaz',
|
||||
BALENA_HOST_CONFIG_foo: 'foobar',
|
||||
RESIN_HOST_CONFIG_other: 'val',
|
||||
BALENA_HOST_CONFIG_baz: 'bad',
|
||||
BALENA_SUPERVISOR_POLL_INTERVAL: '100',
|
||||
FOO: 'bar', // should be removed
|
||||
BAR: 'baz', // should be removed
|
||||
RESIN_SUPERVISOR_LOCAL_MODE: 'false', // any device
|
||||
BALENA_SUPERVISOR_OVERRIDE_LOCK: 'false', // any device
|
||||
BALENA_SUPERVISOR_POLL_INTERVAL: '100', // any device
|
||||
RESIN_HOST_CONFIG_dtparam: 'i2c_arm=on","spi=on","audio=on', // config.txt backend
|
||||
RESIN_HOST_CONFIGFS_ssdt: 'spidev1.0', // configfs backend
|
||||
BALENA_HOST_EXTLINUX_isolcpus: '1,2,3', // extlinux backend
|
||||
}),
|
||||
).to.eventually.deep.equal({
|
||||
HOST_CONFIG_foo: 'foobar',
|
||||
HOST_CONFIG_other: 'val',
|
||||
HOST_CONFIG_baz: 'bad',
|
||||
).to.deep.equal({
|
||||
SUPERVISOR_LOCAL_MODE: 'false',
|
||||
SUPERVISOR_OVERRIDE_LOCK: 'false',
|
||||
SUPERVISOR_POLL_INTERVAL: '100',
|
||||
HOST_CONFIG_dtparam: 'i2c_arm=on","spi=on","audio=on',
|
||||
HOST_CONFIGFS_ssdt: 'spidev1.0',
|
||||
HOST_EXTLINUX_isolcpus: '1,2,3',
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -3,7 +3,6 @@ import * as _ from 'lodash';
|
||||
|
||||
import { expect } from './lib/chai-config';
|
||||
import * as config from '../src/config';
|
||||
import { validKeys } from '../src/device-config';
|
||||
import * as configUtils from '../src/config/utils';
|
||||
import { ExtraUEnv } from '../src/config/backends/extra-uEnv';
|
||||
import { Extlinux } from '../src/config/backends/extlinux';
|
||||
@ -40,28 +39,6 @@ describe('Config Utilities', () => {
|
||||
).to.deep.equal(configObj.envVars);
|
||||
});
|
||||
});
|
||||
|
||||
it('formats keys from config', () => {
|
||||
// Pick any backend to use for test
|
||||
// note: some of the values used will be specific to this backend
|
||||
const backend = BACKENDS['extlinux'];
|
||||
const formattedKeys = configUtils.formatConfigKeys(backend, validKeys, {
|
||||
FOO: 'bar',
|
||||
BAR: 'baz',
|
||||
RESIN_HOST_CONFIG_foo: 'foobaz',
|
||||
BALENA_HOST_CONFIG_foo: 'foobar',
|
||||
RESIN_HOST_CONFIG_other: 'val',
|
||||
BALENA_HOST_CONFIG_baz: 'bad',
|
||||
BALENA_SUPERVISOR_POLL_INTERVAL: '100', // any device
|
||||
BALENA_HOST_EXTLINUX_isolcpus: '1,2,3', // specific to backend
|
||||
RESIN_HOST_EXTLINUX_fdt: '/boot/mycustomdtb.dtb', // specific to backend
|
||||
});
|
||||
expect(formattedKeys).to.deep.equal({
|
||||
HOST_EXTLINUX_isolcpus: '1,2,3',
|
||||
HOST_EXTLINUX_fdt: '/boot/mycustomdtb.dtb',
|
||||
SUPERVISOR_POLL_INTERVAL: '100',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const BACKENDS: Record<string, ConfigBackend> = {
|
||||
|
Loading…
x
Reference in New Issue
Block a user