mirror of
https://github.com/balena-os/balena-supervisor.git
synced 2025-05-28 21:34:19 +00:00
deviceConfig: allow BALENA_ config variables
They will take precedence over any existing RESIN_ variables. We strip both namespaces now whenever we get the target values. This also fixes preloading with a legacy config (the interface to get the config keys from the legacy apps.json was broken). Change-type: minor Signed-off-by: Pablo Carranza Velez <pablo@balena.io>
This commit is contained in:
parent
658639ea65
commit
24cbfbb860
@ -54,15 +54,31 @@ export function bootConfigToEnv(
|
|||||||
.value();
|
.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,
|
configBackend: DeviceConfigBackend | null,
|
||||||
allowedKeys: string[],
|
allowedKeys: string[],
|
||||||
conf: { [key: string]: any },
|
conf: { [key: string]: any },
|
||||||
): { [key: string]: any } {
|
): { [key: string]: any } {
|
||||||
|
|
||||||
const isConfigType = configBackend != null;
|
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));
|
return _.includes(allowedKeys, k) || (isConfigType && configBackend!.isBootConfigVar(k));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -12,22 +12,22 @@ module.exports = class DeviceConfig
|
|||||||
constructor: ({ @db, @config, @logger }) ->
|
constructor: ({ @db, @config, @logger }) ->
|
||||||
@rebootRequired = false
|
@rebootRequired = false
|
||||||
@configKeys = {
|
@configKeys = {
|
||||||
appUpdatePollInterval: { envVarName: 'RESIN_SUPERVISOR_POLL_INTERVAL', varType: 'int', defaultValue: '60000' }
|
appUpdatePollInterval: { envVarName: 'SUPERVISOR_POLL_INTERVAL', varType: 'int', defaultValue: '60000' }
|
||||||
localMode: { envVarName: 'RESIN_SUPERVISOR_LOCAL_MODE', varType: 'bool', defaultValue: 'false' }
|
localMode: { envVarName: 'SUPERVISOR_LOCAL_MODE', varType: 'bool', defaultValue: 'false' }
|
||||||
connectivityCheckEnabled: { envVarName: 'RESIN_SUPERVISOR_CONNECTIVITY_CHECK', varType: 'bool', defaultValue: 'true' }
|
connectivityCheckEnabled: { envVarName: 'SUPERVISOR_CONNECTIVITY_CHECK', varType: 'bool', defaultValue: 'true' }
|
||||||
loggingEnabled: { envVarName: 'RESIN_SUPERVISOR_LOG_CONTROL', varType: 'bool', defaultValue: 'true' }
|
loggingEnabled: { envVarName: 'SUPERVISOR_LOG_CONTROL', varType: 'bool', defaultValue: 'true' }
|
||||||
delta: { envVarName: 'RESIN_SUPERVISOR_DELTA', varType: 'bool', defaultValue: 'false' }
|
delta: { envVarName: 'SUPERVISOR_DELTA', varType: 'bool', defaultValue: 'false' }
|
||||||
deltaRequestTimeout: { envVarName: 'RESIN_SUPERVISOR_DELTA_REQUEST_TIMEOUT', varType: 'int', defaultValue: '30000' }
|
deltaRequestTimeout: { envVarName: 'SUPERVISOR_DELTA_REQUEST_TIMEOUT', varType: 'int', defaultValue: '30000' }
|
||||||
deltaApplyTimeout: { envVarName: 'RESIN_SUPERVISOR_DELTA_APPLY_TIMEOUT', varType: 'int', defaultValue: '' }
|
deltaApplyTimeout: { envVarName: 'SUPERVISOR_DELTA_APPLY_TIMEOUT', varType: 'int', defaultValue: '' }
|
||||||
deltaRetryCount: { envVarName: 'RESIN_SUPERVISOR_DELTA_RETRY_COUNT', varType: 'int', defaultValue: '30' }
|
deltaRetryCount: { envVarName: 'SUPERVISOR_DELTA_RETRY_COUNT', varType: 'int', defaultValue: '30' }
|
||||||
deltaRetryInterval: { envVarName: 'RESIN_SUPERVISOR_DELTA_RETRY_INTERVAL', varType: 'int', defaultValue: '10000' }
|
deltaRetryInterval: { envVarName: 'SUPERVISOR_DELTA_RETRY_INTERVAL', varType: 'int', defaultValue: '10000' }
|
||||||
deltaVersion: { envVarName: 'RESIN_SUPERVISOR_DELTA_VERSION', varType: 'int', defaultValue: '2' }
|
deltaVersion: { envVarName: 'SUPERVISOR_DELTA_VERSION', varType: 'int', defaultValue: '2' }
|
||||||
lockOverride: { envVarName: 'RESIN_SUPERVISOR_OVERRIDE_LOCK', varType: 'bool', defaultValue: 'false' }
|
lockOverride: { envVarName: 'SUPERVISOR_OVERRIDE_LOCK', varType: 'bool', defaultValue: 'false' }
|
||||||
persistentLogging: { envVarName: 'RESIN_SUPERVISOR_PERSISTENT_LOGGING', varType: 'bool', defaultValue: 'false', rebootRequired: true }
|
persistentLogging: { envVarName: 'SUPERVISOR_PERSISTENT_LOGGING', varType: 'bool', defaultValue: 'false', rebootRequired: true }
|
||||||
}
|
}
|
||||||
@validKeys = [
|
@validKeys = [
|
||||||
'RESIN_SUPERVISOR_VPN_CONTROL',
|
'SUPERVISOR_VPN_CONTROL',
|
||||||
'RESIN_OVERRIDE_LOCK',
|
'OVERRIDE_LOCK',
|
||||||
].concat(_.map(@configKeys, 'envVarName'))
|
].concat(_.map(@configKeys, 'envVarName'))
|
||||||
@actionExecutors = {
|
@actionExecutors = {
|
||||||
changeConfig: (step) =>
|
changeConfig: (step) =>
|
||||||
@ -40,7 +40,7 @@ module.exports = class DeviceConfig
|
|||||||
.tapCatch (err) =>
|
.tapCatch (err) =>
|
||||||
@logger.logConfigChange(step.humanReadableTarget, { err })
|
@logger.logConfigChange(step.humanReadableTarget, { err })
|
||||||
setVPNEnabled: (step, { initial = false } = {}) =>
|
setVPNEnabled: (step, { initial = false } = {}) =>
|
||||||
logValue = { RESIN_SUPERVISOR_VPN_CONTROL: step.target }
|
logValue = { SUPERVISOR_VPN_CONTROL: step.target }
|
||||||
if !initial
|
if !initial
|
||||||
@logger.logConfigChange(logValue)
|
@logger.logConfigChange(logValue)
|
||||||
@setVPNEnabled(step.target)
|
@setVPNEnabled(step.target)
|
||||||
@ -80,9 +80,9 @@ module.exports = class DeviceConfig
|
|||||||
@getConfigBackend()
|
@getConfigBackend()
|
||||||
]
|
]
|
||||||
.then ([ conf, configBackend ]) =>
|
.then ([ conf, configBackend ]) =>
|
||||||
conf = configUtils.filterConfigKeys(configBackend, @validKeys, conf)
|
conf = configUtils.filterAndFormatConfigKeys(configBackend, @validKeys, conf)
|
||||||
if initial or !conf.RESIN_SUPERVISOR_VPN_CONTROL?
|
if initial or !conf.SUPERVISOR_VPN_CONTROL?
|
||||||
conf.RESIN_SUPERVISOR_VPN_CONTROL = 'true'
|
conf.SUPERVISOR_VPN_CONTROL = 'true'
|
||||||
for own k, { envVarName, defaultValue } of @configKeys
|
for own k, { envVarName, defaultValue } of @configKeys
|
||||||
conf[envVarName] ?= defaultValue
|
conf[envVarName] ?= defaultValue
|
||||||
return conf
|
return conf
|
||||||
@ -98,17 +98,22 @@ module.exports = class DeviceConfig
|
|||||||
@getBootConfig(configBackend)
|
@getBootConfig(configBackend)
|
||||||
(vpnStatus, bootConfig) =>
|
(vpnStatus, bootConfig) =>
|
||||||
currentConf = {
|
currentConf = {
|
||||||
RESIN_SUPERVISOR_VPN_CONTROL: (vpnStatus ? 'true').toString()
|
SUPERVISOR_VPN_CONTROL: (vpnStatus ? 'true').toString()
|
||||||
}
|
}
|
||||||
for own key, { envVarName } of @configKeys
|
for own key, { envVarName } of @configKeys
|
||||||
currentConf[envVarName] = (conf[key] ? '').toString()
|
currentConf[envVarName] = (conf[key] ? '').toString()
|
||||||
return _.assign(currentConf, bootConfig)
|
return _.assign(currentConf, bootConfig)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
filterAndFormatConfigKeys: (conf) =>
|
||||||
|
@getConfigBackend()
|
||||||
|
.then (configBackend) =>
|
||||||
|
configUtils.filterAndFormatConfigKeys(configBackend, @validKeys, conf)
|
||||||
|
|
||||||
getDefaults: =>
|
getDefaults: =>
|
||||||
Promise.try =>
|
Promise.try =>
|
||||||
return _.extend({
|
return _.extend({
|
||||||
RESIN_SUPERVISOR_VPN_CONTROL: 'true'
|
SUPERVISOR_VPN_CONTROL: 'true'
|
||||||
}, _.mapValues(_.mapKeys(@configKeys, 'envVarName'), 'defaultValue'))
|
}, _.mapValues(_.mapKeys(@configKeys, 'envVarName'), 'defaultValue'))
|
||||||
|
|
||||||
bootConfigChangeRequired: (configBackend, current, target) =>
|
bootConfigChangeRequired: (configBackend, current, target) =>
|
||||||
@ -143,8 +148,8 @@ module.exports = class DeviceConfig
|
|||||||
checkInt(a) == checkInt(b)
|
checkInt(a) == checkInt(b)
|
||||||
}
|
}
|
||||||
# If the legacy lock override is used, place it as the new variable
|
# If the legacy lock override is used, place it as the new variable
|
||||||
if checkTruthy(target['RESIN_OVERRIDE_LOCK'])
|
if checkTruthy(target['OVERRIDE_LOCK'])
|
||||||
target['RESIN_SUPERVISOR_OVERRIDE_LOCK'] = target['RESIN_OVERRIDE_LOCK']
|
target['SUPERVISOR_OVERRIDE_LOCK'] = target['OVERRIDE_LOCK']
|
||||||
reboot = false
|
reboot = false
|
||||||
for own key, { envVarName, varType, rebootRequired } of @configKeys
|
for own key, { envVarName, varType, rebootRequired } of @configKeys
|
||||||
if !match[varType](current[envVarName], target[envVarName])
|
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
|
# Check if we need to perform special case actions for the VPN
|
||||||
if !checkTruthy(offlineMode) &&
|
if !checkTruthy(offlineMode) &&
|
||||||
!_.isEmpty(target['RESIN_SUPERVISOR_VPN_CONTROL']) &&
|
!_.isEmpty(target['SUPERVISOR_VPN_CONTROL']) &&
|
||||||
@checkBoolChanged(current, target, 'RESIN_SUPERVISOR_VPN_CONTROL')
|
@checkBoolChanged(current, target, 'SUPERVISOR_VPN_CONTROL')
|
||||||
steps.push({
|
steps.push({
|
||||||
action: 'setVPNEnabled'
|
action: 'setVPNEnabled'
|
||||||
target: target['RESIN_SUPERVISOR_VPN_CONTROL']
|
target: target['SUPERVISOR_VPN_CONTROL']
|
||||||
})
|
})
|
||||||
|
|
||||||
# Do we need to change the boot config?
|
# Do we need to change the boot config?
|
||||||
|
@ -306,23 +306,28 @@ module.exports = class DeviceState extends EventEmitter
|
|||||||
@emitAsync('change')
|
@emitAsync('change')
|
||||||
|
|
||||||
_convertLegacyAppsJson: (appsArray) =>
|
_convertLegacyAppsJson: (appsArray) =>
|
||||||
config = _.reduce(appsArray, (conf, app) =>
|
deviceConf = _.reduce(appsArray, (conf, app) =>
|
||||||
return _.merge({}, conf, @deviceConfig.filterConfigKeys(app.config))
|
return _.merge({}, conf, app.config)
|
||||||
, {})
|
, {})
|
||||||
apps = _.keyBy(_.map(appsArray, singleToMulticontainerApp), 'appId')
|
apps = _.keyBy(_.map(appsArray, singleToMulticontainerApp), 'appId')
|
||||||
return { apps, config }
|
@deviceConfig.filterAndFormatConfigKeys(deviceConf)
|
||||||
|
.then (filteredDeviceConf)->
|
||||||
|
return { apps, config: filteredDeviceConf }
|
||||||
|
|
||||||
loadTargetFromFile: (appsPath) ->
|
loadTargetFromFile: (appsPath) ->
|
||||||
appsPath ?= constants.appsJsonPath
|
appsPath ?= constants.appsJsonPath
|
||||||
fs.readFileAsync(appsPath, 'utf8')
|
fs.readFileAsync(appsPath, 'utf8')
|
||||||
.then(JSON.parse)
|
.then(JSON.parse)
|
||||||
|
.then (stateFromFile) =>
|
||||||
|
if _.isArray(stateFromFile)
|
||||||
|
# This is a legacy apps.json
|
||||||
|
return @_convertLegacyAppsJson(stateFromFile)
|
||||||
|
else
|
||||||
|
return stateFromFile
|
||||||
.then (stateFromFile) =>
|
.then (stateFromFile) =>
|
||||||
commitToPin = null
|
commitToPin = null
|
||||||
appToPin = null
|
appToPin = null
|
||||||
if !_.isEmpty(stateFromFile)
|
if !_.isEmpty(stateFromFile)
|
||||||
if _.isArray(stateFromFile)
|
|
||||||
# This is a legacy apps.json
|
|
||||||
stateFromFile = @_convertLegacyAppsJson(stateFromFile)
|
|
||||||
images = _.flatMap stateFromFile.apps, (app, appId) =>
|
images = _.flatMap stateFromFile.apps, (app, appId) =>
|
||||||
# multi-app warning!
|
# multi-app warning!
|
||||||
# The following will need to be changed once running multiple applications is possible
|
# The following will need to be changed once running multiple applications is possible
|
||||||
|
@ -37,7 +37,7 @@ const constants = {
|
|||||||
'io.balena.supervised': 'true',
|
'io.balena.supervised': 'true',
|
||||||
},
|
},
|
||||||
bootBlockDevice: '/dev/mmcblk0p1',
|
bootBlockDevice: '/dev/mmcblk0p1',
|
||||||
hostConfigVarPrefix: 'RESIN_HOST_',
|
hostConfigVarPrefix: 'HOST_',
|
||||||
};
|
};
|
||||||
|
|
||||||
if (process.env.DOCKER_HOST == null) {
|
if (process.env.DOCKER_HOST == null) {
|
||||||
|
@ -32,20 +32,20 @@ testTarget1 = {
|
|||||||
local: {
|
local: {
|
||||||
name: 'aDevice'
|
name: 'aDevice'
|
||||||
config: {
|
config: {
|
||||||
'RESIN_HOST_CONFIG_gpu_mem': '256'
|
'HOST_CONFIG_gpu_mem': '256'
|
||||||
'RESIN_SUPERVISOR_CONNECTIVITY_CHECK': 'true'
|
'SUPERVISOR_CONNECTIVITY_CHECK': 'true'
|
||||||
'RESIN_SUPERVISOR_DELTA': 'false'
|
'SUPERVISOR_DELTA': 'false'
|
||||||
'RESIN_SUPERVISOR_DELTA_APPLY_TIMEOUT': ''
|
'SUPERVISOR_DELTA_APPLY_TIMEOUT': ''
|
||||||
'RESIN_SUPERVISOR_DELTA_REQUEST_TIMEOUT': '30000'
|
'SUPERVISOR_DELTA_REQUEST_TIMEOUT': '30000'
|
||||||
'RESIN_SUPERVISOR_DELTA_RETRY_COUNT': '30'
|
'SUPERVISOR_DELTA_RETRY_COUNT': '30'
|
||||||
'RESIN_SUPERVISOR_DELTA_RETRY_INTERVAL': '10000'
|
'SUPERVISOR_DELTA_RETRY_INTERVAL': '10000'
|
||||||
'RESIN_SUPERVISOR_DELTA_VERSION': '2'
|
'SUPERVISOR_DELTA_VERSION': '2'
|
||||||
'RESIN_SUPERVISOR_LOCAL_MODE': 'false'
|
'SUPERVISOR_LOCAL_MODE': 'false'
|
||||||
'RESIN_SUPERVISOR_LOG_CONTROL': 'true'
|
'SUPERVISOR_LOG_CONTROL': 'true'
|
||||||
'RESIN_SUPERVISOR_OVERRIDE_LOCK': 'false'
|
'SUPERVISOR_OVERRIDE_LOCK': 'false'
|
||||||
'RESIN_SUPERVISOR_POLL_INTERVAL': '60000'
|
'SUPERVISOR_POLL_INTERVAL': '60000'
|
||||||
'RESIN_SUPERVISOR_VPN_CONTROL': 'true'
|
'SUPERVISOR_VPN_CONTROL': 'true'
|
||||||
'RESIN_SUPERVISOR_PERSISTENT_LOGGING': 'false'
|
'SUPERVISOR_PERSISTENT_LOGGING': 'false'
|
||||||
}
|
}
|
||||||
apps: {
|
apps: {
|
||||||
'1234': {
|
'1234': {
|
||||||
@ -114,20 +114,20 @@ testTargetWithDefaults2 = {
|
|||||||
local: {
|
local: {
|
||||||
name: 'aDeviceWithDifferentName'
|
name: 'aDeviceWithDifferentName'
|
||||||
config: {
|
config: {
|
||||||
'RESIN_HOST_CONFIG_gpu_mem': '512'
|
'HOST_CONFIG_gpu_mem': '512'
|
||||||
'RESIN_SUPERVISOR_CONNECTIVITY_CHECK': 'true'
|
'SUPERVISOR_CONNECTIVITY_CHECK': 'true'
|
||||||
'RESIN_SUPERVISOR_DELTA': 'false'
|
'SUPERVISOR_DELTA': 'false'
|
||||||
'RESIN_SUPERVISOR_DELTA_APPLY_TIMEOUT': ''
|
'SUPERVISOR_DELTA_APPLY_TIMEOUT': ''
|
||||||
'RESIN_SUPERVISOR_DELTA_REQUEST_TIMEOUT': '30000'
|
'SUPERVISOR_DELTA_REQUEST_TIMEOUT': '30000'
|
||||||
'RESIN_SUPERVISOR_DELTA_RETRY_COUNT': '30'
|
'SUPERVISOR_DELTA_RETRY_COUNT': '30'
|
||||||
'RESIN_SUPERVISOR_DELTA_RETRY_INTERVAL': '10000'
|
'SUPERVISOR_DELTA_RETRY_INTERVAL': '10000'
|
||||||
'RESIN_SUPERVISOR_DELTA_VERSION': '2'
|
'SUPERVISOR_DELTA_VERSION': '2'
|
||||||
'RESIN_SUPERVISOR_LOCAL_MODE': 'false'
|
'SUPERVISOR_LOCAL_MODE': 'false'
|
||||||
'RESIN_SUPERVISOR_LOG_CONTROL': 'true'
|
'SUPERVISOR_LOG_CONTROL': 'true'
|
||||||
'RESIN_SUPERVISOR_OVERRIDE_LOCK': 'false'
|
'SUPERVISOR_OVERRIDE_LOCK': 'false'
|
||||||
'RESIN_SUPERVISOR_POLL_INTERVAL': '60000'
|
'SUPERVISOR_POLL_INTERVAL': '60000'
|
||||||
'RESIN_SUPERVISOR_VPN_CONTROL': 'true'
|
'SUPERVISOR_VPN_CONTROL': 'true'
|
||||||
'RESIN_SUPERVISOR_PERSISTENT_LOGGING': 'false'
|
'SUPERVISOR_PERSISTENT_LOGGING': 'false'
|
||||||
}
|
}
|
||||||
apps: {
|
apps: {
|
||||||
'1234': {
|
'1234': {
|
||||||
@ -232,6 +232,7 @@ describe 'deviceState', ->
|
|||||||
return Service.fromComposeObject(s, { appName: 'superapp' })
|
return Service.fromComposeObject(s, { appName: 'superapp' })
|
||||||
# We serialize and parse JSON to avoid checking fields that are functions or undefined
|
# 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)))
|
expect(JSON.parse(JSON.stringify(targetState))).to.deep.equal(JSON.parse(JSON.stringify(testTarget)))
|
||||||
|
.finally =>
|
||||||
@deviceState.applications.images.save.restore()
|
@deviceState.applications.images.save.restore()
|
||||||
@deviceState.deviceConfig.getCurrent.restore()
|
@deviceState.deviceConfig.getCurrent.restore()
|
||||||
|
|
||||||
|
@ -21,7 +21,14 @@ describe 'DeviceConfig', ->
|
|||||||
@timeout(5000)
|
@timeout(5000)
|
||||||
prepare()
|
prepare()
|
||||||
@fakeDB = {}
|
@fakeDB = {}
|
||||||
@fakeConfig = {}
|
@fakeConfig = {
|
||||||
|
get: (key) ->
|
||||||
|
Promise.try ->
|
||||||
|
if key == 'deviceType'
|
||||||
|
return 'raspberrypi3'
|
||||||
|
else
|
||||||
|
throw new Error('Unknown fake config key')
|
||||||
|
}
|
||||||
@fakeLogger = {
|
@fakeLogger = {
|
||||||
logSystemMessage: spy()
|
logSystemMessage: spy()
|
||||||
}
|
}
|
||||||
@ -43,36 +50,36 @@ describe 'DeviceConfig', ->
|
|||||||
.then (conf) ->
|
.then (conf) ->
|
||||||
fs.readFile.restore()
|
fs.readFile.restore()
|
||||||
expect(conf).to.deep.equal({
|
expect(conf).to.deep.equal({
|
||||||
RESIN_HOST_CONFIG_initramfs: 'initramf.gz 0x00800000'
|
HOST_CONFIG_initramfs: 'initramf.gz 0x00800000'
|
||||||
RESIN_HOST_CONFIG_dtparam: '"i2c=on","audio=on"'
|
HOST_CONFIG_dtparam: '"i2c=on","audio=on"'
|
||||||
RESIN_HOST_CONFIG_dtoverlay: '"ads7846","lirc-rpi,gpio_out_pin=17,gpio_in_pin=13"'
|
HOST_CONFIG_dtoverlay: '"ads7846","lirc-rpi,gpio_out_pin=17,gpio_in_pin=13"'
|
||||||
RESIN_HOST_CONFIG_foobar: 'baz'
|
HOST_CONFIG_foobar: 'baz'
|
||||||
})
|
})
|
||||||
|
|
||||||
it 'properly reads a real config.txt file', ->
|
it 'properly reads a real config.txt file', ->
|
||||||
@deviceConfig.getBootConfig(rpiConfigBackend)
|
@deviceConfig.getBootConfig(rpiConfigBackend)
|
||||||
.then (conf) ->
|
.then (conf) ->
|
||||||
expect(conf).to.deep.equal({
|
expect(conf).to.deep.equal({
|
||||||
RESIN_HOST_CONFIG_dtparam: '"i2c_arm=on","spi=on","audio=on"'
|
HOST_CONFIG_dtparam: '"i2c_arm=on","spi=on","audio=on"'
|
||||||
RESIN_HOST_CONFIG_enable_uart: '1'
|
HOST_CONFIG_enable_uart: '1'
|
||||||
RESIN_HOST_CONFIG_disable_splash: '1'
|
HOST_CONFIG_disable_splash: '1'
|
||||||
RESIN_HOST_CONFIG_avoid_warnings: '1'
|
HOST_CONFIG_avoid_warnings: '1'
|
||||||
RESIN_HOST_CONFIG_gpu_mem: '16'
|
HOST_CONFIG_gpu_mem: '16'
|
||||||
})
|
})
|
||||||
|
|
||||||
# Test that the format for special values like initramfs and array variables is preserved
|
# Test that the format for special values like initramfs and array variables is preserved
|
||||||
it 'does not allow setting forbidden keys', ->
|
it 'does not allow setting forbidden keys', ->
|
||||||
current = {
|
current = {
|
||||||
RESIN_HOST_CONFIG_initramfs: 'initramf.gz 0x00800000'
|
HOST_CONFIG_initramfs: 'initramf.gz 0x00800000'
|
||||||
RESIN_HOST_CONFIG_dtparam: '"i2c=on","audio=on"'
|
HOST_CONFIG_dtparam: '"i2c=on","audio=on"'
|
||||||
RESIN_HOST_CONFIG_dtoverlay: '"ads7846","lirc-rpi,gpio_out_pin=17,gpio_in_pin=13"'
|
HOST_CONFIG_dtoverlay: '"ads7846","lirc-rpi,gpio_out_pin=17,gpio_in_pin=13"'
|
||||||
RESIN_HOST_CONFIG_foobar: 'baz'
|
HOST_CONFIG_foobar: 'baz'
|
||||||
}
|
}
|
||||||
target = {
|
target = {
|
||||||
RESIN_HOST_CONFIG_initramfs: 'initramf.gz 0x00810000'
|
HOST_CONFIG_initramfs: 'initramf.gz 0x00810000'
|
||||||
RESIN_HOST_CONFIG_dtparam: '"i2c=on","audio=on"'
|
HOST_CONFIG_dtparam: '"i2c=on","audio=on"'
|
||||||
RESIN_HOST_CONFIG_dtoverlay: '"ads7846","lirc-rpi,gpio_out_pin=17,gpio_in_pin=13"'
|
HOST_CONFIG_dtoverlay: '"ads7846","lirc-rpi,gpio_out_pin=17,gpio_in_pin=13"'
|
||||||
RESIN_HOST_CONFIG_foobar: 'baz'
|
HOST_CONFIG_foobar: 'baz'
|
||||||
}
|
}
|
||||||
promise = Promise.try =>
|
promise = Promise.try =>
|
||||||
@deviceConfig.bootConfigChangeRequired(rpiConfigBackend, current, target)
|
@deviceConfig.bootConfigChangeRequired(rpiConfigBackend, current, target)
|
||||||
@ -86,16 +93,16 @@ describe 'DeviceConfig', ->
|
|||||||
|
|
||||||
it 'does not try to change config.txt if it should not change', ->
|
it 'does not try to change config.txt if it should not change', ->
|
||||||
current = {
|
current = {
|
||||||
RESIN_HOST_CONFIG_initramfs: 'initramf.gz 0x00800000'
|
HOST_CONFIG_initramfs: 'initramf.gz 0x00800000'
|
||||||
RESIN_HOST_CONFIG_dtparam: '"i2c=on","audio=on"'
|
HOST_CONFIG_dtparam: '"i2c=on","audio=on"'
|
||||||
RESIN_HOST_CONFIG_dtoverlay: '"ads7846","lirc-rpi,gpio_out_pin=17,gpio_in_pin=13"'
|
HOST_CONFIG_dtoverlay: '"ads7846","lirc-rpi,gpio_out_pin=17,gpio_in_pin=13"'
|
||||||
RESIN_HOST_CONFIG_foobar: 'baz'
|
HOST_CONFIG_foobar: 'baz'
|
||||||
}
|
}
|
||||||
target = {
|
target = {
|
||||||
RESIN_HOST_CONFIG_initramfs: 'initramf.gz 0x00800000'
|
HOST_CONFIG_initramfs: 'initramf.gz 0x00800000'
|
||||||
RESIN_HOST_CONFIG_dtparam: '"i2c=on","audio=on"'
|
HOST_CONFIG_dtparam: '"i2c=on","audio=on"'
|
||||||
RESIN_HOST_CONFIG_dtoverlay: '"ads7846","lirc-rpi,gpio_out_pin=17,gpio_in_pin=13"'
|
HOST_CONFIG_dtoverlay: '"ads7846","lirc-rpi,gpio_out_pin=17,gpio_in_pin=13"'
|
||||||
RESIN_HOST_CONFIG_foobar: 'baz'
|
HOST_CONFIG_foobar: 'baz'
|
||||||
}
|
}
|
||||||
promise = Promise.try =>
|
promise = Promise.try =>
|
||||||
@deviceConfig.bootConfigChangeRequired(rpiConfigBackend, current, target)
|
@deviceConfig.bootConfigChangeRequired(rpiConfigBackend, current, target)
|
||||||
@ -108,17 +115,17 @@ describe 'DeviceConfig', ->
|
|||||||
stub(fsUtils, 'writeFileAtomic').resolves()
|
stub(fsUtils, 'writeFileAtomic').resolves()
|
||||||
stub(childProcess, 'execAsync').resolves()
|
stub(childProcess, 'execAsync').resolves()
|
||||||
current = {
|
current = {
|
||||||
RESIN_HOST_CONFIG_initramfs: 'initramf.gz 0x00800000'
|
HOST_CONFIG_initramfs: 'initramf.gz 0x00800000'
|
||||||
RESIN_HOST_CONFIG_dtparam: '"i2c=on","audio=on"'
|
HOST_CONFIG_dtparam: '"i2c=on","audio=on"'
|
||||||
RESIN_HOST_CONFIG_dtoverlay: '"ads7846","lirc-rpi,gpio_out_pin=17,gpio_in_pin=13"'
|
HOST_CONFIG_dtoverlay: '"ads7846","lirc-rpi,gpio_out_pin=17,gpio_in_pin=13"'
|
||||||
RESIN_HOST_CONFIG_foobar: 'baz'
|
HOST_CONFIG_foobar: 'baz'
|
||||||
}
|
}
|
||||||
target = {
|
target = {
|
||||||
RESIN_HOST_CONFIG_initramfs: 'initramf.gz 0x00800000'
|
HOST_CONFIG_initramfs: 'initramf.gz 0x00800000'
|
||||||
RESIN_HOST_CONFIG_dtparam: '"i2c=on","audio=off"'
|
HOST_CONFIG_dtparam: '"i2c=on","audio=off"'
|
||||||
RESIN_HOST_CONFIG_dtoverlay: '"lirc-rpi,gpio_out_pin=17,gpio_in_pin=13"'
|
HOST_CONFIG_dtoverlay: '"lirc-rpi,gpio_out_pin=17,gpio_in_pin=13"'
|
||||||
RESIN_HOST_CONFIG_foobar: 'bat'
|
HOST_CONFIG_foobar: 'bat'
|
||||||
RESIN_HOST_CONFIG_foobaz: 'bar'
|
HOST_CONFIG_foobaz: 'bar'
|
||||||
}
|
}
|
||||||
promise = Promise.try =>
|
promise = Promise.try =>
|
||||||
@deviceConfig.bootConfigChangeRequired(rpiConfigBackend, current, target)
|
@deviceConfig.bootConfigChangeRequired(rpiConfigBackend, current, target)
|
||||||
@ -141,6 +148,23 @@ describe 'DeviceConfig', ->
|
|||||||
childProcess.execAsync.restore()
|
childProcess.execAsync.restore()
|
||||||
@fakeLogger.logSystemMessage.reset()
|
@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', ->
|
describe 'Extlinux files', ->
|
||||||
|
|
||||||
it 'should correctly write to extlinux.conf files', ->
|
it 'should correctly write to extlinux.conf files', ->
|
||||||
@ -150,7 +174,7 @@ describe 'DeviceConfig', ->
|
|||||||
current = {
|
current = {
|
||||||
}
|
}
|
||||||
target = {
|
target = {
|
||||||
RESIN_HOST_EXTLINUX_isolcpus: '2'
|
HOST_EXTLINUX_isolcpus: '2'
|
||||||
}
|
}
|
||||||
|
|
||||||
promise = Promise.try =>
|
promise = Promise.try =>
|
||||||
|
@ -18,10 +18,10 @@ describe 'Config Utilities', ->
|
|||||||
|
|
||||||
it 'correctly transforms environments to boot config objects', ->
|
it 'correctly transforms environments to boot config objects', ->
|
||||||
bootConfig = configUtils.envToBootConfig(rpiBackend, {
|
bootConfig = configUtils.envToBootConfig(rpiBackend, {
|
||||||
RESIN_HOST_CONFIG_initramfs: 'initramf.gz 0x00800000'
|
HOST_CONFIG_initramfs: 'initramf.gz 0x00800000'
|
||||||
RESIN_HOST_CONFIG_dtparam: '"i2c=on","audio=on"'
|
HOST_CONFIG_dtparam: '"i2c=on","audio=on"'
|
||||||
RESIN_HOST_CONFIG_dtoverlay: '"ads7846","lirc-rpi,gpio_out_pin=17,gpio_in_pin=13"'
|
HOST_CONFIG_dtoverlay: '"ads7846","lirc-rpi,gpio_out_pin=17,gpio_in_pin=13"'
|
||||||
RESIN_HOST_CONFIG_foobar: 'baz'
|
HOST_CONFIG_foobar: 'baz'
|
||||||
})
|
})
|
||||||
expect(bootConfig).to.deep.equal({
|
expect(bootConfig).to.deep.equal({
|
||||||
initramfs: 'initramf.gz 0x00800000'
|
initramfs: 'initramf.gz 0x00800000'
|
||||||
|
Loading…
x
Reference in New Issue
Block a user