mirror of
https://github.com/balena-os/balena-supervisor.git
synced 2025-01-19 19:28:59 +00:00
Actually apply config.txt changes and reboot
Keep the original statements where possible. (to ensure same config keys under different filters are not overwritten with always the same value)
This commit is contained in:
parent
8b4d1e9f75
commit
0e283e8e72
@ -153,7 +153,7 @@ application.start = start = (app) ->
|
||||
]
|
||||
device.getDeviceType()
|
||||
.then (deviceType) ->
|
||||
if deviceType.match(/^raspberry-pi/)?
|
||||
if _.startsWith(deviceType, 'raspberry-pi')
|
||||
volumes['/boot'] = {}
|
||||
binds.push('/boot:/boot')
|
||||
.catch (err) ->
|
||||
@ -305,8 +305,7 @@ executeSpecialActionsAndBootConfig = (env) ->
|
||||
specialActionCallback(env[key])
|
||||
executedSpecialActionEnvVars[key] = env[key]
|
||||
bootConfigVars = _.pick env, (val, key) ->
|
||||
configRegex = new RegExp('^/' + device.bootConfigEnvVarPrefix + '*/')
|
||||
return configRegex.exec(key)?
|
||||
return _.startsWith(key, device.bootConfigEnvVarPrefix)
|
||||
if !_.isEmpty(bootConfigVars)
|
||||
device.setBootConfig(bootConfigVars)
|
||||
|
||||
@ -386,8 +385,8 @@ application.update = update = (force) ->
|
||||
|
||||
apps = _.indexBy(apps, 'appId')
|
||||
localApps = _.mapValues apps, (app) ->
|
||||
app = _.pick(app, [ 'appId', 'commit', 'imageId', 'env' ])
|
||||
app.env = JSON.stringify(_.omit(JSON.parse(app.env), _.keys(specialActionEnvVars)))
|
||||
app = _.pick(app, [ 'appId', 'commit', 'imageId', 'env' ])
|
||||
localAppIds = _.keys(localApps)
|
||||
|
||||
toBeRemoved = _.difference(localAppIds, remoteAppIds)
|
||||
|
@ -6,7 +6,8 @@ utils = require './utils'
|
||||
device = exports
|
||||
config = require './config'
|
||||
configPath = '/boot/config.json'
|
||||
request = require 'request'
|
||||
request = Promise.promisifyAll(require('request'))
|
||||
execAsync = Promise.promisify(require('child_process').exec)
|
||||
|
||||
exports.getID = do ->
|
||||
deviceIdPromise = null
|
||||
@ -35,22 +36,63 @@ exports.getID = do ->
|
||||
return devices[0].id
|
||||
|
||||
rebootDevice = ->
|
||||
request.post(config.gosuperAddress + '/v1/reboot', -> console.log('Rebooting.'))
|
||||
request.postAsync(config.gosuperAddress + '/v1/reboot')
|
||||
|
||||
exports.bootConfigEnvVarPrefix = 'RESIN_HOST_CONFIG_'
|
||||
exports.bootConfigEnvVarPrefix = bootConfigEnvVarPrefix = 'RESIN_HOST_CONFIG_'
|
||||
bootConfigPath = '/mnt/root/boot/config.txt'
|
||||
configRegex = new RegExp('(' + _.escapeRegExp(bootConfigEnvVarPrefix) + ')(.+)')
|
||||
parseBootConfigFromEnv = (env) ->
|
||||
# We ensure env doesn't have garbage
|
||||
parsedEnv = _.pick env, (val, key) ->
|
||||
return _.startsWith(bootConfigEnvVarPrefix)
|
||||
throw new Error('No boot config to change') if _.isEmpty(parsedEnv)
|
||||
parsedEnv = _.mapKeys parsedEnv, (val, key) ->
|
||||
key.replace(configRegex, '$2')
|
||||
return parsedEnv
|
||||
|
||||
exports.setBootConfig = (env) ->
|
||||
configChanged = false
|
||||
# TODO:
|
||||
# Translate env to config.txt-compatible statements
|
||||
# Read and parse config.txt
|
||||
# Detect if variables are present
|
||||
# If not there or different:
|
||||
# mark configChanged as true
|
||||
# Replace those and create new ones as necessary
|
||||
# Create config.txt.new
|
||||
# Move config.txt.new to config.txt
|
||||
# rebootDevice()
|
||||
device.getDeviceType()
|
||||
.then (deviceType) ->
|
||||
throw new Error('This is not a Raspberry Pi') if !_.startsWith(deviceType, 'raspberry-pi')
|
||||
Promise.join parseBootConfigFromEnv(env), fs.readFileAsync(bootConfigPath, 'utf8'), (configFromApp, configTxt ) ->
|
||||
configFromFS = {}
|
||||
configPositions = []
|
||||
configStatements = configTxt.split(/\r?\n/)
|
||||
_.each configStatements, (configStr) ->
|
||||
keyValue = /^([^#=]+)=(.+)/.exec(configStr)
|
||||
if keyValue?
|
||||
configPositions.push(keyValue[1])
|
||||
configFromFS[keyValue[1]] = keyValue[2]
|
||||
else
|
||||
# This will ensure config.txt filters are in order
|
||||
configPositions.push(configStr)
|
||||
# configFromApp and configFromFS now have compatible formats
|
||||
keysFromApp = _.keys(configFromApp)
|
||||
keysFromFS = _.keys(configFromFS)
|
||||
toBeAdded = _.difference(keysFromApp, keysFromFS)
|
||||
toBeChanged = _.intersection(keysFromApp, keysFromFS)
|
||||
toBeChanged = _.filter toBeChanged, (key) ->
|
||||
configFromApp[key] != configFromFS[key]
|
||||
throw new Error('Nothing to change') if _.isEmpty(toBeChanged) and _.isEmpty(toBeAdded)
|
||||
# We add the keys to be added first so they are out of any filters
|
||||
outputConfig = _.map toBeAdded, (key) -> "#{key}=#{configFromApp[key]}"
|
||||
outputConfig = outputConfig.concat _.map configPositions, (key, index) ->
|
||||
configStatement = null
|
||||
if _.includes(toBeChanged, key)
|
||||
configStatement = "#{key}=#{configFromApp[key]}"
|
||||
else
|
||||
configStatement = configStatements[index]
|
||||
return configStatement
|
||||
# Here's the dangerous part:
|
||||
fs.writeFileAsync(bootConfigPath + '.new', outputConfig.join('\n'))
|
||||
.then ->
|
||||
fs.renameAsync(bootConfigPath + '.new', bootConfigPath)
|
||||
.then ->
|
||||
execAsync('sync')
|
||||
.then ->
|
||||
rebootDevice()
|
||||
.catch (err) ->
|
||||
console.log('Will not set boot config: ', err)
|
||||
|
||||
exports.getDeviceType = do ->
|
||||
deviceTypePromise = null
|
||||
|
Loading…
Reference in New Issue
Block a user