Finish log to display setting. Add logging to host config. Save host config before rebooting. Allow applying boot config to RPi3.

This commit is contained in:
Pablo Carranza Velez 2016-03-17 13:48:00 -03:00
parent 2c5bc8b90a
commit eddc58ee86
4 changed files with 94 additions and 17 deletions

View File

@ -34,6 +34,10 @@ type VPNBody struct {
Enable bool
}
type LogToDisplayBody struct {
Enable bool
}
func jsonResponse(writer http.ResponseWriter, response interface{}, status int) {
jsonBody, err := json.Marshal(response)
if err != nil {
@ -67,12 +71,6 @@ func parsePurgeBody(request *http.Request) (appId string, err error) {
return
}
func responseSender(writer http.ResponseWriter) func(interface{}, string, int) {
return func(data interface{}, errorMsg string, statusCode int) {
jsonResponse(writer, APIResponse{data, errorMsg}, statusCode)
}
}
func responseSenders(writer http.ResponseWriter) (sendResponse func(interface{}, string, int), sendError func(error)) {
sendResponse = func(data interface{}, errorMsg string, statusCode int) {
jsonResponse(writer, APIResponse{data, errorMsg}, statusCode)
@ -221,3 +219,52 @@ func VPNControl(writer http.ResponseWriter, request *http.Request) {
log.Printf("%sd\n", actionDescr)
sendResponse("OK", "", http.StatusAccepted)
}
//LogToDisplayControl is used to control tty-replacement service status with dbus
func LogToDisplayControl(writer http.ResponseWriter, request *http.Request) {
sendResponse, sendError := responseSenders(writer)
serviceName := "tty-replacement.service"
var body LogToDisplayBody
if err := parseJSONBody(&body, request); err != nil {
log.Println(err)
sendResponse("Error", err.Error(), http.StatusBadRequest)
return
}
if systemd.Dbus == nil {
sendError(fmt.Errorf("Systemd dbus unavailable, cannot set log to display state."))
return
}
if activeState, err := systemd.Dbus.GetUnitProperty(serviceName, "ActiveState"); err != nil {
sendError(fmt.Errorf("Unable to get log to display status: %v", err))
return
} else {
status := activeState.Value.String() == `"active"`
enable := body.Enable
if status == enable {
// Nothing to do, return Data = false to signal nothing was changed
sendResponse(false, "", http.StatusOK)
return
} else if enable {
if _, err := systemd.Dbus.StartUnit(serviceName, "fail", nil); err != nil {
sendError(fmt.Errorf("Unable to start service: %v", err))
return
}
if _, _, err = systemd.Dbus.EnableUnitFiles([]string{serviceName}, false, false); err != nil {
sendError(fmt.Errorf("Unable to enable service: %v", err))
return
}
} else {
if _, err := systemd.Dbus.StopUnit(serviceName, "fail", nil); err != nil {
sendError(fmt.Errorf("Unable to stop service: %v", err))
return
}
if _, err = systemd.Dbus.DisableUnitFiles([]string{serviceName}, false); err != nil {
sendError(fmt.Errorf("Unable to disable service: %v", err))
return
}
}
sendResponse(true, "", http.StatusOK)
}
}

View File

@ -25,6 +25,7 @@ func setupApi(router *mux.Router) {
apiv1.HandleFunc("/reboot", RebootHandler).Methods("POST")
apiv1.HandleFunc("/shutdown", ShutdownHandler).Methods("POST")
apiv1.HandleFunc("/vpncontrol", VPNControl).Methods("POST")
apiv1.HandleFunc("/set-log-to-display", LogToDisplayControl).Methods("POST")
}
func startApi(listenAddress string, router *mux.Router) {

View File

@ -84,6 +84,19 @@ logSystemEvent = (logType, app, error) ->
utils.mixpanelTrack(logType.eventName, {app, error})
return
logMessage = (msg) ->
logger.log(msg, isSystem: true)
utils.mixpanelTrack(msg)
logSpecialAction = (action, value, success) ->
if success
msg = "Applied config variable #{action} = #{value}"
else
msg = "Applying config variable #{action} = #{value}"
logMessage(msg)
application = {}
application.kill = kill = (app, updateDB = true) ->
@ -340,12 +353,14 @@ executeSpecialActionsAndHostConfig = (env) ->
if env[key]? && specialActionCallback?
# This makes the Special Action Envs only trigger their functions once.
if !_.has(executedSpecialActionEnvVars, key) or executedSpecialActionEnvVars[key] != env[key]
logSpecialAction(key, env[key])
specialActionCallback(env[key])
executedSpecialActionEnvVars[key] = env[key]
logSpecialAction(key, env[key], true)
hostConfigVars = _.pick env, (val, key) ->
return _.startsWith(key, device.hostConfigEnvVarPrefix)
if !_.isEmpty(hostConfigVars)
device.setHostConfig(hostConfigVars)
device.setHostConfig(hostConfigVars, logMessage)
wrapAsError = (err) ->
return err if _.isError(err)
@ -460,6 +475,8 @@ getEnvAndFormatRemoteApps = (deviceId, remoteApps, uuid, apiKey) ->
utils.extendEnvVars(app.environment_variable, uuid)
.then (fullEnv) ->
env = _.omit(fullEnv, _.keys(specialActionEnvVars))
env = _.omitBy env, (v, k) ->
_.startsWith(k, device.hostConfigEnvVarPrefix)
return [
{
appId: '' + app.id
@ -528,7 +545,7 @@ application.update = update = (force) ->
Promise.map appsWithChangedEnvs, (appId) ->
Promise.using lockUpdates(remoteApps[appId], force), ->
executeSpecialActionsAndHostConfig(remoteAppEnvs[appId])
.then ->
.tap ->
# If an env var shouldn't cause a restart but requires an action, we should still
# save the new env to the DB
if !_.includes(toBeUpdated, appId) and !_.includes(toBeInstalled, appId)
@ -538,6 +555,8 @@ application.update = update = (force) ->
throw new Error('App not found')
app.env = JSON.stringify(remoteAppEnvs[appId])
knex('app').update(app).where({ appId })
.then (needsReboot) ->
device.reboot() if needsReboot
.catch (err) ->
logSystemEvent(logTypes.updateAppError, remoteApps[appId], err)
.return(allAppIds)

View File

@ -35,7 +35,7 @@ exports.getID = do ->
throw new Error('Could not find this device?!')
return devices[0].id
rebootDevice = ->
exports.reboot = rebootDevice = ->
request.postAsync(config.gosuperAddress + '/v1/reboot')
exports.hostConfigEnvVarPrefix = hostConfigEnvVarPrefix = 'RESIN_HOST_'
@ -70,26 +70,30 @@ parseBootConfigFromEnv = (env) ->
parsedEnv = _.omit(parsedEnv, forbiddenConfigKeys)
return parsedEnv
exports.setHostConfig = (env) ->
Promise.join setBootConfig(env), setLogToDisplay(env), (bootConfigApplied, logToDisplayChanged) ->
rebootDevice() if bootConfigApplied or logToDisplayChanged
exports.setHostConfig = (env, logMessage) ->
Promise.join setBootConfig(env, logMessage), setLogToDisplay(env, logMessage), (bootConfigApplied, logToDisplayChanged) ->
return true if bootConfigApplied or logToDisplayChanged
return false
setLogToDisplay = (env) ->
setLogToDisplay = (env, logMessage) ->
if env['RESIN_HOST_LOG_TO_DISPLAY']?
request.postAsync(config.gosuperAddress + '/v1/set-log-to-display')
enable = env['RESIN_HOST_LOG_TO_DISPLAY'] != '0'
request.postAsync(config.gosuperAddress + '/v1/set-log-to-display', {json: true, body: Enable: enable})
.spread (response, body) ->
if response.statusCode != 200
console.log('Error setting log to display:', body, "Status:", response.statusCode)
logMessage("Error setting log to display: #{body}, Status:, #{response.statusCode}")
return false
else
if body.Data == true
logMessage("#{enable ? "Enabled" : "Disabled"} logs to display")
return body.Data
else
return false
setBootConfig = (env) ->
setBootConfig = (env, logMessage) ->
device.getDeviceType()
.then (deviceType) ->
throw new Error('This is not a Raspberry Pi') if !_.startsWith(deviceType, 'raspberry-pi')
throw new Error('This is not a Raspberry Pi') if !_.startsWith(deviceType, 'raspberry')
Promise.join parseBootConfigFromEnv(env), fs.readFileAsync(bootConfigPath, 'utf8'), (configFromApp, configTxt ) ->
throw new Error('No boot config to change') if _.isEmpty(configFromApp)
configFromFS = {}
@ -111,6 +115,8 @@ setBootConfig = (env) ->
toBeChanged = _.filter toBeChanged, (key) ->
configFromApp[key] != configFromFS[key]
throw new Error('Nothing to change') if _.isEmpty(toBeChanged) and _.isEmpty(toBeAdded)
logMessage("Applying boot config: #{configFromApp}")
# 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) ->
@ -129,7 +135,11 @@ setBootConfig = (env) ->
.then ->
execAsync('sync')
.then ->
logMessage("Applied boot config: #{configFromApp}")
return true
.catch (err) ->
logMessage("Error setting boot config: #{err}")
throw err
.catch (err) ->
console.log('Will not set boot config: ', err)
return false