mirror of
https://github.com/balena-os/balena-supervisor.git
synced 2024-12-20 22:23:13 +00:00
Fix config checks for ConfigFS backend
When trying to apply SSDT overlays in Up Board, the supervisor currently gets stuck in a loop trying to apply target state. See #1465 This was due to a bug in parsing the configuration, which lead to the method bootConfigChangeRequired returning true when no change was needed. Change-type: patch Signed-off-by: Felipe Lalanne <felipe@balena.io> Connects-to: #1465
This commit is contained in:
parent
1ac71ea552
commit
a5f3002e70
2
.gitignore
vendored
2
.gitignore
vendored
@ -10,7 +10,7 @@ tools/dind/config/
|
||||
tools/dind/config.json*
|
||||
tools/dind/apps.json
|
||||
tools/dind/backup.tgz
|
||||
test/data/config*.json
|
||||
test/data/**/config*.json
|
||||
test/data/*.sqlite
|
||||
test/data/led_file
|
||||
/coverage/
|
||||
|
@ -94,7 +94,7 @@ export class ConfigFs extends ConfigBackend {
|
||||
`AML: ${oemId.trim()} ${oemTableId.trim()} (Rev ${oemRevision.trim()})`,
|
||||
);
|
||||
} catch (e) {
|
||||
log.error('Issue while loading AML ${aml}', e);
|
||||
log.error(`Issue while loading AML ${aml}`, e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -214,7 +214,7 @@ export class ConfigFs extends ConfigBackend {
|
||||
return [value];
|
||||
} else {
|
||||
// or, it could be parsable as the content of a JSON array; "value" | "value1","value2"
|
||||
return value.split(',').map((v) => v.replace('"', '').trim());
|
||||
return value.split(',').map((v) => v.replace(/"/g, '').trim());
|
||||
}
|
||||
default:
|
||||
return value;
|
||||
|
@ -9,12 +9,15 @@ import * as logger from '../src/logger';
|
||||
import { Extlinux } from '../src/config/backends/extlinux';
|
||||
import { ConfigTxt } from '../src/config/backends/config-txt';
|
||||
import { Odmdata } from '../src/config/backends/odmdata';
|
||||
import { ConfigFs } from '../src/config/backends/config-fs';
|
||||
import * as constants from '../src/lib/constants';
|
||||
|
||||
import prepare = require('./lib/prepare');
|
||||
|
||||
const extlinuxBackend = new Extlinux();
|
||||
const configTxtBackend = new ConfigTxt();
|
||||
const odmdataBackend = new Odmdata();
|
||||
const configFsBackend = new ConfigFs();
|
||||
|
||||
describe('Device Backend Config', () => {
|
||||
let logSpy: SinonSpy;
|
||||
@ -336,94 +339,138 @@ describe('Device Backend Config', () => {
|
||||
});
|
||||
});
|
||||
|
||||
// describe('ConfigFS', () => {
|
||||
// const upboardConfig = new DeviceConfig();
|
||||
// let upboardConfigBackend: ConfigBackend | null;
|
||||
describe('ConfigFS files', () => {
|
||||
it('should correctly write to configfs.json files', async () => {
|
||||
stub(fsUtils, 'writeFileAtomic').resolves();
|
||||
stub(child_process, 'exec').resolves();
|
||||
|
||||
// before(async () => {
|
||||
// stub(child_process, 'exec').resolves();
|
||||
// stub(fs, 'exists').resolves(true);
|
||||
// stub(fs, 'mkdir').resolves();
|
||||
// stub(fs, 'readdir').resolves([]);
|
||||
// stub(fsUtils, 'writeFileAtomic').resolves();
|
||||
const current = {};
|
||||
const target = {
|
||||
HOST_CONFIGFS_ssdt: 'spidev1.0',
|
||||
};
|
||||
|
||||
// stub(fs, 'readFile').callsFake(file => {
|
||||
// if (file === 'test/data/mnt/boot/configfs.json') {
|
||||
// return Promise.resolve(
|
||||
// JSON.stringify({
|
||||
// ssdt: ['spidev1,1'],
|
||||
// }),
|
||||
// );
|
||||
// }
|
||||
// return Promise.resolve('');
|
||||
// });
|
||||
expect(
|
||||
// @ts-ignore accessing private value
|
||||
deviceConfig.bootConfigChangeRequired(
|
||||
configFsBackend,
|
||||
current,
|
||||
target,
|
||||
'up-board',
|
||||
),
|
||||
).to.equal(true);
|
||||
|
||||
// stub(config, 'get').callsFake(key => {
|
||||
// return Promise.try(() => {
|
||||
// if (key === 'deviceType') {
|
||||
// return 'up-board';
|
||||
// }
|
||||
// throw new Error('Unknown fake config key');
|
||||
// });
|
||||
// });
|
||||
// @ts-ignore accessing private value
|
||||
await deviceConfig.setBootConfig(configFsBackend, target);
|
||||
expect(child_process.exec).to.be.calledOnce;
|
||||
expect(logSpy).to.be.calledTwice;
|
||||
expect(logSpy.getCall(1).args[2]).to.equal('Apply boot config success');
|
||||
expect(fsUtils.writeFileAtomic).to.be.calledWith(
|
||||
'test/data/mnt/boot/configfs.json',
|
||||
'{"ssdt":["spidev1.0"]}',
|
||||
);
|
||||
|
||||
// // @ts-ignore accessing private value
|
||||
// upboardConfigBackend = await upboardConfig.getConfigBackend();
|
||||
// expect(upboardConfigBackend).is.not.null;
|
||||
// expect((child_process.exec as SinonSpy).callCount).to.equal(
|
||||
// 3,
|
||||
// 'exec not called enough times',
|
||||
// );
|
||||
// });
|
||||
|
||||
// after(() => {
|
||||
// (child_process.exec as SinonStub).restore();
|
||||
// (fs.exists as SinonStub).restore();
|
||||
// (fs.mkdir as SinonStub).restore();
|
||||
// (fs.readdir as SinonStub).restore();
|
||||
// (fs.readFile as SinonStub).restore();
|
||||
// (fsUtils.writeFileAtomic as SinonStub).restore();
|
||||
// (config.get as SinonStub).restore();
|
||||
// });
|
||||
|
||||
// it('should correctly load the configfs.json file', () => {
|
||||
// expect(child_process.exec).to.be.calledWith('modprobe acpi_configfs');
|
||||
// expect(child_process.exec).to.be.calledWith(
|
||||
// 'cat test/data/boot/acpi-tables/spidev1,1.aml > test/data/sys/kernel/config/acpi/table/spidev1,1/aml',
|
||||
// );
|
||||
// expect((fs.exists as SinonSpy).callCount).to.equal(2);
|
||||
// expect((fs.readFile as SinonSpy).callCount).to.equal(4);
|
||||
// });
|
||||
|
||||
// it('should correctly write the configfs.json file', async () => {
|
||||
// const current = {};
|
||||
// const target = {
|
||||
// HOST_CONFIGFS_ssdt: 'spidev1,1',
|
||||
// };
|
||||
|
||||
// (child_process.exec as SinonSpy).resetHistory();
|
||||
// (fs.exists as SinonSpy).resetHistory();
|
||||
// (fs.mkdir as SinonSpy).resetHistory();
|
||||
// (fs.readdir as SinonSpy).resetHistory();
|
||||
// (fs.readFile as SinonSpy).resetHistory();
|
||||
|
||||
// // @ts-ignore accessing private value
|
||||
// upboardConfig.bootConfigChangeRequired(upboardConfigBackend, current, target);
|
||||
// // @ts-ignore accessing private value
|
||||
// await upboardConfig.setBootConfig(upboardConfigBackend, target);
|
||||
|
||||
// expect(child_process.exec).to.be.calledOnce;
|
||||
// expect(fsUtils.writeFileAtomic).to.be.calledWith(
|
||||
// 'test/data/mnt/boot/configfs.json',
|
||||
// JSON.stringify({
|
||||
// ssdt: ['spidev1,1'],
|
||||
// }),
|
||||
// );
|
||||
// expect(logSpy).to.be.calledTwice;
|
||||
// expect(logSpy.getCall(1).args[2]).to.equal('Apply boot config success');
|
||||
// });
|
||||
// });
|
||||
|
||||
// // This will require stubbing device.reboot, gosuper.post, config.get/set
|
||||
// it('applies the target state');
|
||||
// Restore stubs
|
||||
(fsUtils.writeFileAtomic as SinonStub).restore();
|
||||
(child_process.exec as SinonStub).restore();
|
||||
});
|
||||
|
||||
it('should correctly load the configfs.json file', async () => {
|
||||
stub(child_process, 'exec').resolves();
|
||||
stub(fsUtils, 'writeFileAtomic').resolves();
|
||||
stub(fs, 'exists').resolves(true);
|
||||
stub(fs, 'mkdir').resolves();
|
||||
stub(fs, 'readdir').resolves([]);
|
||||
stub(fs, 'readFile').callsFake((file) => {
|
||||
if (file === 'test/data/mnt/boot/configfs.json') {
|
||||
return Promise.resolve(
|
||||
JSON.stringify({
|
||||
ssdt: ['spidev1.1'],
|
||||
}),
|
||||
);
|
||||
}
|
||||
return Promise.resolve('');
|
||||
});
|
||||
|
||||
await configFsBackend.initialise();
|
||||
expect(child_process.exec).to.be.calledWith('modprobe acpi_configfs');
|
||||
expect(child_process.exec).to.be.calledWith(
|
||||
`mount -t vfat -o remount,rw ${constants.bootBlockDevice} ./test/data/mnt/boot`,
|
||||
);
|
||||
expect(child_process.exec).to.be.calledWith(
|
||||
'cat test/data/boot/acpi-tables/spidev1.1.aml > test/data/sys/kernel/config/acpi/table/spidev1.1/aml',
|
||||
);
|
||||
expect((fs.exists as SinonSpy).callCount).to.equal(2);
|
||||
expect((fs.readFile as SinonSpy).callCount).to.equal(4);
|
||||
|
||||
// Restore stubs
|
||||
(fsUtils.writeFileAtomic as SinonStub).restore();
|
||||
(child_process.exec as SinonStub).restore();
|
||||
(fs.exists as SinonStub).restore();
|
||||
(fs.mkdir as SinonStub).restore();
|
||||
(fs.readdir as SinonStub).restore();
|
||||
(fs.readFile as SinonStub).restore();
|
||||
});
|
||||
|
||||
it('requires change when target is different', () => {
|
||||
expect(
|
||||
deviceConfig.bootConfigChangeRequired(
|
||||
configFsBackend,
|
||||
{ HOST_CONFIGFS_ssdt: '' },
|
||||
{ HOST_CONFIGFS_ssdt: 'spidev1.0' },
|
||||
'up-board',
|
||||
),
|
||||
).to.equal(true);
|
||||
expect(
|
||||
deviceConfig.bootConfigChangeRequired(
|
||||
configFsBackend,
|
||||
{ HOST_CONFIGFS_ssdt: '' },
|
||||
{ HOST_CONFIGFS_ssdt: '"spidev1.0"' },
|
||||
'up-board',
|
||||
),
|
||||
).to.equal(true);
|
||||
expect(
|
||||
deviceConfig.bootConfigChangeRequired(
|
||||
configFsBackend,
|
||||
{ HOST_CONFIGFS_ssdt: '"spidev1.0"' },
|
||||
{ HOST_CONFIGFS_ssdt: '"spidev1.0","spidev1.1"' },
|
||||
'up-board',
|
||||
),
|
||||
).to.equal(true);
|
||||
});
|
||||
|
||||
it('should not report change when target is equal to current', () => {
|
||||
expect(
|
||||
deviceConfig.bootConfigChangeRequired(
|
||||
configFsBackend,
|
||||
{ HOST_CONFIGFS_ssdt: '' },
|
||||
{ HOST_CONFIGFS_ssdt: '' },
|
||||
'up-board',
|
||||
),
|
||||
).to.equal(false);
|
||||
expect(
|
||||
deviceConfig.bootConfigChangeRequired(
|
||||
configFsBackend,
|
||||
{ HOST_CONFIGFS_ssdt: 'spidev1.0' },
|
||||
{ HOST_CONFIGFS_ssdt: 'spidev1.0' },
|
||||
'up-board',
|
||||
),
|
||||
).to.equal(false);
|
||||
expect(
|
||||
deviceConfig.bootConfigChangeRequired(
|
||||
configFsBackend,
|
||||
{ HOST_CONFIGFS_ssdt: 'spidev1.0' },
|
||||
{ HOST_CONFIGFS_ssdt: '"spidev1.0"' },
|
||||
'up-board',
|
||||
),
|
||||
).to.equal(false);
|
||||
expect(
|
||||
deviceConfig.bootConfigChangeRequired(
|
||||
configFsBackend,
|
||||
{ HOST_CONFIGFS_ssdt: '"spidev1.0"' },
|
||||
{ HOST_CONFIGFS_ssdt: 'spidev1.0' },
|
||||
'up-board',
|
||||
),
|
||||
).to.equal(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user