Merge pull request #762 from resin-io/balena-config

deviceConfig: allow BALENA_ config variables
This commit is contained in:
Pablo Carranza Vélez 2018-10-18 17:45:14 +02:00 committed by GitHub
commit a762ba9dc0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 157 additions and 104 deletions

View File

@ -324,13 +324,15 @@ module.exports = class APIBinder
targetConfig = targetState.local.config
Promise.mapSeries _.toPairs(currentConfig), ([ key, value ]) =>
# We never want to disable VPN if, for instance, it failed to start so far
if key == 'RESIN_SUPERVISOR_VPN_CONTROL'
if key == 'SUPERVISOR_VPN_CONTROL'
value = 'true'
if !targetConfig[key]? and value != defaultConfig[key]
# At some point the namespace in the API should change to BALENA_
# but for now we only have RESIN_
envVar = {
value
device: deviceId
name: key
name: 'RESIN_' + key
}
@resinApi.post
resource: 'device_config_variable'

View File

@ -54,15 +54,31 @@ export function bootConfigToEnv(
.value();
}
export function filterConfigKeys(
function filterNamespaceFromConfig(
namespace: RegExp,
conf: { [key: string]: any },
): { [key: string]: any } {
return _.mapKeys(_.pickBy(conf, (_v, k) => {
return namespace.test(k);
}), (_v,k) => {
return k.replace(namespace, '$1');
});
}
export function filterAndFormatConfigKeys(
configBackend: DeviceConfigBackend | 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 confWithoutNamespace = _.defaults(confFromNamespace, confFromLegacyNamespace);
return _.pickBy(conf, (_v, k) => {
return _.pickBy(confWithoutNamespace, (_v, k) => {
return _.includes(allowedKeys, k) || (isConfigType && configBackend!.isBootConfigVar(k));
});
}

View File

@ -12,22 +12,22 @@ module.exports = class DeviceConfig
constructor: ({ @db, @config, @logger }) ->
@rebootRequired = false
@configKeys = {
appUpdatePollInterval: { envVarName: 'RESIN_SUPERVISOR_POLL_INTERVAL', varType: 'int', defaultValue: '60000' }
localMode: { envVarName: 'RESIN_SUPERVISOR_LOCAL_MODE', varType: 'bool', defaultValue: 'false' }
connectivityCheckEnabled: { envVarName: 'RESIN_SUPERVISOR_CONNECTIVITY_CHECK', varType: 'bool', defaultValue: 'true' }
loggingEnabled: { envVarName: 'RESIN_SUPERVISOR_LOG_CONTROL', varType: 'bool', defaultValue: 'true' }
delta: { envVarName: 'RESIN_SUPERVISOR_DELTA', varType: 'bool', defaultValue: 'false' }
deltaRequestTimeout: { envVarName: 'RESIN_SUPERVISOR_DELTA_REQUEST_TIMEOUT', varType: 'int', defaultValue: '30000' }
deltaApplyTimeout: { envVarName: 'RESIN_SUPERVISOR_DELTA_APPLY_TIMEOUT', varType: 'int', defaultValue: '' }
deltaRetryCount: { envVarName: 'RESIN_SUPERVISOR_DELTA_RETRY_COUNT', varType: 'int', defaultValue: '30' }
deltaRetryInterval: { envVarName: 'RESIN_SUPERVISOR_DELTA_RETRY_INTERVAL', varType: 'int', defaultValue: '10000' }
deltaVersion: { envVarName: 'RESIN_SUPERVISOR_DELTA_VERSION', varType: 'int', defaultValue: '2' }
lockOverride: { envVarName: 'RESIN_SUPERVISOR_OVERRIDE_LOCK', varType: 'bool', defaultValue: 'false' }
persistentLogging: { envVarName: 'RESIN_SUPERVISOR_PERSISTENT_LOGGING', varType: 'bool', defaultValue: 'false', rebootRequired: true }
appUpdatePollInterval: { envVarName: 'SUPERVISOR_POLL_INTERVAL', varType: 'int', defaultValue: '60000' }
localMode: { envVarName: 'SUPERVISOR_LOCAL_MODE', varType: 'bool', defaultValue: 'false' }
connectivityCheckEnabled: { envVarName: 'SUPERVISOR_CONNECTIVITY_CHECK', varType: 'bool', defaultValue: 'true' }
loggingEnabled: { envVarName: 'SUPERVISOR_LOG_CONTROL', varType: 'bool', defaultValue: 'true' }
delta: { envVarName: 'SUPERVISOR_DELTA', varType: 'bool', defaultValue: 'false' }
deltaRequestTimeout: { envVarName: 'SUPERVISOR_DELTA_REQUEST_TIMEOUT', varType: 'int', defaultValue: '30000' }
deltaApplyTimeout: { envVarName: 'SUPERVISOR_DELTA_APPLY_TIMEOUT', varType: 'int', defaultValue: '' }
deltaRetryCount: { envVarName: 'SUPERVISOR_DELTA_RETRY_COUNT', varType: 'int', defaultValue: '30' }
deltaRetryInterval: { envVarName: 'SUPERVISOR_DELTA_RETRY_INTERVAL', varType: 'int', defaultValue: '10000' }
deltaVersion: { envVarName: 'SUPERVISOR_DELTA_VERSION', varType: 'int', defaultValue: '2' }
lockOverride: { envVarName: 'SUPERVISOR_OVERRIDE_LOCK', varType: 'bool', defaultValue: 'false' }
persistentLogging: { envVarName: 'SUPERVISOR_PERSISTENT_LOGGING', varType: 'bool', defaultValue: 'false', rebootRequired: true }
}
@validKeys = [
'RESIN_SUPERVISOR_VPN_CONTROL',
'RESIN_OVERRIDE_LOCK',
'SUPERVISOR_VPN_CONTROL',
'OVERRIDE_LOCK',
].concat(_.map(@configKeys, 'envVarName'))
@actionExecutors = {
changeConfig: (step) =>
@ -40,7 +40,7 @@ module.exports = class DeviceConfig
.tapCatch (err) =>
@logger.logConfigChange(step.humanReadableTarget, { err })
setVPNEnabled: (step, { initial = false } = {}) =>
logValue = { RESIN_SUPERVISOR_VPN_CONTROL: step.target }
logValue = { SUPERVISOR_VPN_CONTROL: step.target }
if !initial
@logger.logConfigChange(logValue)
@setVPNEnabled(step.target)
@ -80,9 +80,9 @@ module.exports = class DeviceConfig
@getConfigBackend()
]
.then ([ conf, configBackend ]) =>
conf = configUtils.filterConfigKeys(configBackend, @validKeys, conf)
if initial or !conf.RESIN_SUPERVISOR_VPN_CONTROL?
conf.RESIN_SUPERVISOR_VPN_CONTROL = 'true'
conf = configUtils.filterAndFormatConfigKeys(configBackend, @validKeys, conf)
if initial or !conf.SUPERVISOR_VPN_CONTROL?
conf.SUPERVISOR_VPN_CONTROL = 'true'
for own k, { envVarName, defaultValue } of @configKeys
conf[envVarName] ?= defaultValue
return conf
@ -98,17 +98,22 @@ module.exports = class DeviceConfig
@getBootConfig(configBackend)
(vpnStatus, bootConfig) =>
currentConf = {
RESIN_SUPERVISOR_VPN_CONTROL: (vpnStatus ? 'true').toString()
SUPERVISOR_VPN_CONTROL: (vpnStatus ? 'true').toString()
}
for own key, { envVarName } of @configKeys
currentConf[envVarName] = (conf[key] ? '').toString()
return _.assign(currentConf, bootConfig)
)
filterAndFormatConfigKeys: (conf) =>
@getConfigBackend()
.then (configBackend) =>
configUtils.filterAndFormatConfigKeys(configBackend, @validKeys, conf)
getDefaults: =>
Promise.try =>
return _.extend({
RESIN_SUPERVISOR_VPN_CONTROL: 'true'
SUPERVISOR_VPN_CONTROL: 'true'
}, _.mapValues(_.mapKeys(@configKeys, 'envVarName'), 'defaultValue'))
bootConfigChangeRequired: (configBackend, current, target) =>
@ -143,8 +148,8 @@ module.exports = class DeviceConfig
checkInt(a) == checkInt(b)
}
# If the legacy lock override is used, place it as the new variable
if checkTruthy(target['RESIN_OVERRIDE_LOCK'])
target['RESIN_SUPERVISOR_OVERRIDE_LOCK'] = target['RESIN_OVERRIDE_LOCK']
if checkTruthy(target['OVERRIDE_LOCK'])
target['SUPERVISOR_OVERRIDE_LOCK'] = target['OVERRIDE_LOCK']
reboot = false
for own key, { envVarName, varType, rebootRequired } of @configKeys
if !match[varType](current[envVarName], target[envVarName])
@ -162,11 +167,11 @@ module.exports = class DeviceConfig
# Check if we need to perform special case actions for the VPN
if !checkTruthy(offlineMode) &&
!_.isEmpty(target['RESIN_SUPERVISOR_VPN_CONTROL']) &&
@checkBoolChanged(current, target, 'RESIN_SUPERVISOR_VPN_CONTROL')
!_.isEmpty(target['SUPERVISOR_VPN_CONTROL']) &&
@checkBoolChanged(current, target, 'SUPERVISOR_VPN_CONTROL')
steps.push({
action: 'setVPNEnabled'
target: target['RESIN_SUPERVISOR_VPN_CONTROL']
target: target['SUPERVISOR_VPN_CONTROL']
})
# Do we need to change the boot config?

View File

@ -306,23 +306,28 @@ module.exports = class DeviceState extends EventEmitter
@emitAsync('change')
_convertLegacyAppsJson: (appsArray) =>
config = _.reduce(appsArray, (conf, app) =>
return _.merge({}, conf, @deviceConfig.filterConfigKeys(app.config))
deviceConf = _.reduce(appsArray, (conf, app) =>
return _.merge({}, conf, app.config)
, {})
apps = _.keyBy(_.map(appsArray, singleToMulticontainerApp), 'appId')
return { apps, config }
@deviceConfig.filterAndFormatConfigKeys(deviceConf)
.then (filteredDeviceConf)->
return { apps, config: filteredDeviceConf }
loadTargetFromFile: (appsPath) ->
appsPath ?= constants.appsJsonPath
fs.readFileAsync(appsPath, 'utf8')
.then(JSON.parse)
.then (stateFromFile) =>
if _.isArray(stateFromFile)
# This is a legacy apps.json
return @_convertLegacyAppsJson(stateFromFile)
else
return stateFromFile
.then (stateFromFile) =>
commitToPin = null
appToPin = null
if !_.isEmpty(stateFromFile)
if _.isArray(stateFromFile)
# This is a legacy apps.json
stateFromFile = @_convertLegacyAppsJson(stateFromFile)
images = _.flatMap stateFromFile.apps, (app, appId) =>
# multi-app warning!
# The following will need to be changed once running multiple applications is possible

View File

@ -37,7 +37,7 @@ const constants = {
'io.balena.supervised': 'true',
},
bootBlockDevice: '/dev/mmcblk0p1',
hostConfigVarPrefix: 'RESIN_HOST_',
hostConfigVarPrefix: 'HOST_',
};
if (process.env.DOCKER_HOST == null) {

View File

@ -32,20 +32,20 @@ testTarget1 = {
local: {
name: 'aDevice'
config: {
'RESIN_HOST_CONFIG_gpu_mem': '256'
'RESIN_SUPERVISOR_CONNECTIVITY_CHECK': 'true'
'RESIN_SUPERVISOR_DELTA': 'false'
'RESIN_SUPERVISOR_DELTA_APPLY_TIMEOUT': ''
'RESIN_SUPERVISOR_DELTA_REQUEST_TIMEOUT': '30000'
'RESIN_SUPERVISOR_DELTA_RETRY_COUNT': '30'
'RESIN_SUPERVISOR_DELTA_RETRY_INTERVAL': '10000'
'RESIN_SUPERVISOR_DELTA_VERSION': '2'
'RESIN_SUPERVISOR_LOCAL_MODE': 'false'
'RESIN_SUPERVISOR_LOG_CONTROL': 'true'
'RESIN_SUPERVISOR_OVERRIDE_LOCK': 'false'
'RESIN_SUPERVISOR_POLL_INTERVAL': '60000'
'RESIN_SUPERVISOR_VPN_CONTROL': 'true'
'RESIN_SUPERVISOR_PERSISTENT_LOGGING': 'false'
'HOST_CONFIG_gpu_mem': '256'
'SUPERVISOR_CONNECTIVITY_CHECK': 'true'
'SUPERVISOR_DELTA': 'false'
'SUPERVISOR_DELTA_APPLY_TIMEOUT': ''
'SUPERVISOR_DELTA_REQUEST_TIMEOUT': '30000'
'SUPERVISOR_DELTA_RETRY_COUNT': '30'
'SUPERVISOR_DELTA_RETRY_INTERVAL': '10000'
'SUPERVISOR_DELTA_VERSION': '2'
'SUPERVISOR_LOCAL_MODE': 'false'
'SUPERVISOR_LOG_CONTROL': 'true'
'SUPERVISOR_OVERRIDE_LOCK': 'false'
'SUPERVISOR_POLL_INTERVAL': '60000'
'SUPERVISOR_VPN_CONTROL': 'true'
'SUPERVISOR_PERSISTENT_LOGGING': 'false'
}
apps: {
'1234': {
@ -114,20 +114,20 @@ testTargetWithDefaults2 = {
local: {
name: 'aDeviceWithDifferentName'
config: {
'RESIN_HOST_CONFIG_gpu_mem': '512'
'RESIN_SUPERVISOR_CONNECTIVITY_CHECK': 'true'
'RESIN_SUPERVISOR_DELTA': 'false'
'RESIN_SUPERVISOR_DELTA_APPLY_TIMEOUT': ''
'RESIN_SUPERVISOR_DELTA_REQUEST_TIMEOUT': '30000'
'RESIN_SUPERVISOR_DELTA_RETRY_COUNT': '30'
'RESIN_SUPERVISOR_DELTA_RETRY_INTERVAL': '10000'
'RESIN_SUPERVISOR_DELTA_VERSION': '2'
'RESIN_SUPERVISOR_LOCAL_MODE': 'false'
'RESIN_SUPERVISOR_LOG_CONTROL': 'true'
'RESIN_SUPERVISOR_OVERRIDE_LOCK': 'false'
'RESIN_SUPERVISOR_POLL_INTERVAL': '60000'
'RESIN_SUPERVISOR_VPN_CONTROL': 'true'
'RESIN_SUPERVISOR_PERSISTENT_LOGGING': 'false'
'HOST_CONFIG_gpu_mem': '512'
'SUPERVISOR_CONNECTIVITY_CHECK': 'true'
'SUPERVISOR_DELTA': 'false'
'SUPERVISOR_DELTA_APPLY_TIMEOUT': ''
'SUPERVISOR_DELTA_REQUEST_TIMEOUT': '30000'
'SUPERVISOR_DELTA_RETRY_COUNT': '30'
'SUPERVISOR_DELTA_RETRY_INTERVAL': '10000'
'SUPERVISOR_DELTA_VERSION': '2'
'SUPERVISOR_LOCAL_MODE': 'false'
'SUPERVISOR_LOG_CONTROL': 'true'
'SUPERVISOR_OVERRIDE_LOCK': 'false'
'SUPERVISOR_POLL_INTERVAL': '60000'
'SUPERVISOR_VPN_CONTROL': 'true'
'SUPERVISOR_PERSISTENT_LOGGING': 'false'
}
apps: {
'1234': {
@ -232,6 +232,7 @@ describe 'deviceState', ->
return Service.fromComposeObject(s, { appName: 'superapp' })
# We serialize and parse JSON to avoid checking fields that are functions or undefined
expect(JSON.parse(JSON.stringify(targetState))).to.deep.equal(JSON.parse(JSON.stringify(testTarget)))
.finally =>
@deviceState.applications.images.save.restore()
@deviceState.deviceConfig.getCurrent.restore()

View File

@ -21,7 +21,14 @@ describe 'DeviceConfig', ->
@timeout(5000)
prepare()
@fakeDB = {}
@fakeConfig = {}
@fakeConfig = {
get: (key) ->
Promise.try ->
if key == 'deviceType'
return 'raspberrypi3'
else
throw new Error('Unknown fake config key')
}
@fakeLogger = {
logSystemMessage: spy()
}
@ -43,36 +50,36 @@ describe 'DeviceConfig', ->
.then (conf) ->
fs.readFile.restore()
expect(conf).to.deep.equal({
RESIN_HOST_CONFIG_initramfs: 'initramf.gz 0x00800000'
RESIN_HOST_CONFIG_dtparam: '"i2c=on","audio=on"'
RESIN_HOST_CONFIG_dtoverlay: '"ads7846","lirc-rpi,gpio_out_pin=17,gpio_in_pin=13"'
RESIN_HOST_CONFIG_foobar: 'baz'
HOST_CONFIG_initramfs: 'initramf.gz 0x00800000'
HOST_CONFIG_dtparam: '"i2c=on","audio=on"'
HOST_CONFIG_dtoverlay: '"ads7846","lirc-rpi,gpio_out_pin=17,gpio_in_pin=13"'
HOST_CONFIG_foobar: 'baz'
})
it 'properly reads a real config.txt file', ->
@deviceConfig.getBootConfig(rpiConfigBackend)
.then (conf) ->
expect(conf).to.deep.equal({
RESIN_HOST_CONFIG_dtparam: '"i2c_arm=on","spi=on","audio=on"'
RESIN_HOST_CONFIG_enable_uart: '1'
RESIN_HOST_CONFIG_disable_splash: '1'
RESIN_HOST_CONFIG_avoid_warnings: '1'
RESIN_HOST_CONFIG_gpu_mem: '16'
HOST_CONFIG_dtparam: '"i2c_arm=on","spi=on","audio=on"'
HOST_CONFIG_enable_uart: '1'
HOST_CONFIG_disable_splash: '1'
HOST_CONFIG_avoid_warnings: '1'
HOST_CONFIG_gpu_mem: '16'
})
# Test that the format for special values like initramfs and array variables is preserved
it 'does not allow setting forbidden keys', ->
current = {
RESIN_HOST_CONFIG_initramfs: 'initramf.gz 0x00800000'
RESIN_HOST_CONFIG_dtparam: '"i2c=on","audio=on"'
RESIN_HOST_CONFIG_dtoverlay: '"ads7846","lirc-rpi,gpio_out_pin=17,gpio_in_pin=13"'
RESIN_HOST_CONFIG_foobar: 'baz'
HOST_CONFIG_initramfs: 'initramf.gz 0x00800000'
HOST_CONFIG_dtparam: '"i2c=on","audio=on"'
HOST_CONFIG_dtoverlay: '"ads7846","lirc-rpi,gpio_out_pin=17,gpio_in_pin=13"'
HOST_CONFIG_foobar: 'baz'
}
target = {
RESIN_HOST_CONFIG_initramfs: 'initramf.gz 0x00810000'
RESIN_HOST_CONFIG_dtparam: '"i2c=on","audio=on"'
RESIN_HOST_CONFIG_dtoverlay: '"ads7846","lirc-rpi,gpio_out_pin=17,gpio_in_pin=13"'
RESIN_HOST_CONFIG_foobar: 'baz'
HOST_CONFIG_initramfs: 'initramf.gz 0x00810000'
HOST_CONFIG_dtparam: '"i2c=on","audio=on"'
HOST_CONFIG_dtoverlay: '"ads7846","lirc-rpi,gpio_out_pin=17,gpio_in_pin=13"'
HOST_CONFIG_foobar: 'baz'
}
promise = Promise.try =>
@deviceConfig.bootConfigChangeRequired(rpiConfigBackend, current, target)
@ -86,16 +93,16 @@ describe 'DeviceConfig', ->
it 'does not try to change config.txt if it should not change', ->
current = {
RESIN_HOST_CONFIG_initramfs: 'initramf.gz 0x00800000'
RESIN_HOST_CONFIG_dtparam: '"i2c=on","audio=on"'
RESIN_HOST_CONFIG_dtoverlay: '"ads7846","lirc-rpi,gpio_out_pin=17,gpio_in_pin=13"'
RESIN_HOST_CONFIG_foobar: 'baz'
HOST_CONFIG_initramfs: 'initramf.gz 0x00800000'
HOST_CONFIG_dtparam: '"i2c=on","audio=on"'
HOST_CONFIG_dtoverlay: '"ads7846","lirc-rpi,gpio_out_pin=17,gpio_in_pin=13"'
HOST_CONFIG_foobar: 'baz'
}
target = {
RESIN_HOST_CONFIG_initramfs: 'initramf.gz 0x00800000'
RESIN_HOST_CONFIG_dtparam: '"i2c=on","audio=on"'
RESIN_HOST_CONFIG_dtoverlay: '"ads7846","lirc-rpi,gpio_out_pin=17,gpio_in_pin=13"'
RESIN_HOST_CONFIG_foobar: 'baz'
HOST_CONFIG_initramfs: 'initramf.gz 0x00800000'
HOST_CONFIG_dtparam: '"i2c=on","audio=on"'
HOST_CONFIG_dtoverlay: '"ads7846","lirc-rpi,gpio_out_pin=17,gpio_in_pin=13"'
HOST_CONFIG_foobar: 'baz'
}
promise = Promise.try =>
@deviceConfig.bootConfigChangeRequired(rpiConfigBackend, current, target)
@ -108,17 +115,17 @@ describe 'DeviceConfig', ->
stub(fsUtils, 'writeFileAtomic').resolves()
stub(childProcess, 'execAsync').resolves()
current = {
RESIN_HOST_CONFIG_initramfs: 'initramf.gz 0x00800000'
RESIN_HOST_CONFIG_dtparam: '"i2c=on","audio=on"'
RESIN_HOST_CONFIG_dtoverlay: '"ads7846","lirc-rpi,gpio_out_pin=17,gpio_in_pin=13"'
RESIN_HOST_CONFIG_foobar: 'baz'
HOST_CONFIG_initramfs: 'initramf.gz 0x00800000'
HOST_CONFIG_dtparam: '"i2c=on","audio=on"'
HOST_CONFIG_dtoverlay: '"ads7846","lirc-rpi,gpio_out_pin=17,gpio_in_pin=13"'
HOST_CONFIG_foobar: 'baz'
}
target = {
RESIN_HOST_CONFIG_initramfs: 'initramf.gz 0x00800000'
RESIN_HOST_CONFIG_dtparam: '"i2c=on","audio=off"'
RESIN_HOST_CONFIG_dtoverlay: '"lirc-rpi,gpio_out_pin=17,gpio_in_pin=13"'
RESIN_HOST_CONFIG_foobar: 'bat'
RESIN_HOST_CONFIG_foobaz: 'bar'
HOST_CONFIG_initramfs: 'initramf.gz 0x00800000'
HOST_CONFIG_dtparam: '"i2c=on","audio=off"'
HOST_CONFIG_dtoverlay: '"lirc-rpi,gpio_out_pin=17,gpio_in_pin=13"'
HOST_CONFIG_foobar: 'bat'
HOST_CONFIG_foobaz: 'bar'
}
promise = Promise.try =>
@deviceConfig.bootConfigChangeRequired(rpiConfigBackend, current, target)
@ -141,6 +148,23 @@ describe 'DeviceConfig', ->
childProcess.execAsync.restore()
@fakeLogger.logSystemMessage.reset()
it 'accepts RESIN_ and BALENA_ variables', ->
@deviceConfig.filterAndFormatConfigKeys({
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',
}).then (filteredConf) ->
expect(filteredConf).to.deep.equal({
HOST_CONFIG_foo: 'foobar',
HOST_CONFIG_other: 'val',
HOST_CONFIG_baz: 'bad',
SUPERVISOR_POLL_INTERVAL: '100',
});
describe 'Extlinux files', ->
it 'should correctly write to extlinux.conf files', ->
@ -150,7 +174,7 @@ describe 'DeviceConfig', ->
current = {
}
target = {
RESIN_HOST_EXTLINUX_isolcpus: '2'
HOST_EXTLINUX_isolcpus: '2'
}
promise = Promise.try =>

View File

@ -18,10 +18,10 @@ describe 'Config Utilities', ->
it 'correctly transforms environments to boot config objects', ->
bootConfig = configUtils.envToBootConfig(rpiBackend, {
RESIN_HOST_CONFIG_initramfs: 'initramf.gz 0x00800000'
RESIN_HOST_CONFIG_dtparam: '"i2c=on","audio=on"'
RESIN_HOST_CONFIG_dtoverlay: '"ads7846","lirc-rpi,gpio_out_pin=17,gpio_in_pin=13"'
RESIN_HOST_CONFIG_foobar: 'baz'
HOST_CONFIG_initramfs: 'initramf.gz 0x00800000'
HOST_CONFIG_dtparam: '"i2c=on","audio=on"'
HOST_CONFIG_dtoverlay: '"ads7846","lirc-rpi,gpio_out_pin=17,gpio_in_pin=13"'
HOST_CONFIG_foobar: 'baz'
})
expect(bootConfig).to.deep.equal({
initramfs: 'initramf.gz 0x00800000'