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:
Pablo Carranza Vélez 2015-09-25 01:20:17 +00:00
parent 8b4d1e9f75
commit 0e283e8e72
2 changed files with 59 additions and 18 deletions

View File

@ -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)

View File

@ -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