Issue #382: Validate delta timeout variables

Also take validation functions into a module, and use that in all cases where
we need to check for an integer or string.

Signed-off-by: Pablo Carranza Velez <pablo@resin.io>
This commit is contained in:
Pablo Carranza Velez 2017-01-18 12:28:24 -03:00
parent 0e76b540ea
commit 0d870954ef
3 changed files with 28 additions and 26 deletions

View File

@ -15,6 +15,7 @@ TypedError = require 'typed-error'
fs = Promise.promisifyAll(require('fs')) fs = Promise.promisifyAll(require('fs'))
JSONStream = require 'JSONStream' JSONStream = require 'JSONStream'
proxyvisor = require './proxyvisor' proxyvisor = require './proxyvisor'
{ checkInt } = require './lib/validation'
class UpdatesLockedError extends TypedError class UpdatesLockedError extends TypedError
ImageNotFoundError = (err) -> ImageNotFoundError = (err) ->
@ -196,8 +197,8 @@ fetch = (app, setDeviceUpdateState = true) ->
if conf['RESIN_SUPERVISOR_DELTA'] == '1' if conf['RESIN_SUPERVISOR_DELTA'] == '1'
logSystemEvent(logTypes.downloadAppDelta, app) logSystemEvent(logTypes.downloadAppDelta, app)
requestTimeout = conf['RESIN_SUPERVISOR_DELTA_REQUEST_TIMEOUT'] ? 30 * 60 * 1000 requestTimeout = checkInt(conf['RESIN_SUPERVISOR_DELTA_REQUEST_TIMEOUT'], positive: true) ? 30 * 60 * 1000
totalTimeout = conf['RESIN_SUPERVISOR_DELTA_TOTAL_TIMEOUT'] ? 24 * 60 * 60 * 1000 totalTimeout = checkInt(conf['RESIN_SUPERVISOR_DELTA_TOTAL_TIMEOUT'], positive: true) ? 24 * 60 * 60 * 1000
dockerUtils.rsyncImageWithProgress(app.imageId, { requestTimeout, totalTimeout }, onProgress) dockerUtils.rsyncImageWithProgress(app.imageId, { requestTimeout, totalTimeout }, onProgress)
else else
logSystemEvent(logTypes.downloadApp, app) logSystemEvent(logTypes.downloadApp, app)
@ -395,7 +396,7 @@ application.poll = ->
# Callback function to set the API poll interval dynamically. # Callback function to set the API poll interval dynamically.
apiPollInterval = (val) -> apiPollInterval = (val) ->
config.appUpdatePollInterval = config.checkInt(val) ? 60000 config.appUpdatePollInterval = checkInt(val, positive: true) ? 60000
console.log('New API poll interval: ' + val) console.log('New API poll interval: ' + val)
clearInterval(updateStatus.intervalHandle) clearInterval(updateStatus.intervalHandle)
application.poll() application.poll()
@ -443,8 +444,7 @@ wrapAsError = (err) ->
waitToKill = (app, timeout) -> waitToKill = (app, timeout) ->
startTime = Date.now() startTime = Date.now()
pollInterval = 100 pollInterval = 100
timeout = parseInt(timeout) timeout = checkInt(timeout, positive: true) ? 60000
timeout = 60000 if isNaN(timeout)
checkFileOrTimeout = -> checkFileOrTimeout = ->
fs.statAsync(killmePath(app)) fs.statAsync(killmePath(app))
.catch (err) -> .catch (err) ->

View File

@ -1,26 +1,12 @@
checkInt = (s) -> { checkInt, checkString } = require './lib/validation'
# Make sure `s` exists and is not an empty string.
if !s
return
i = parseInt(s, 10)
if isNaN(i)
return
return i
checkString = (s) ->
# Make sure `s` exists and is not an empty string, or 'null' or 'undefined'.
# This might happen if the parsing of config.json on the host using jq is wrong (it is buggy in some versions).
if !s? or s == 'null' or s == 'undefined' or s == ''
return
return s
dockerRoot = checkString(process.env.DOCKER_ROOT) ? '/mnt/root/var/lib/rce' dockerRoot = checkString(process.env.DOCKER_ROOT) ? '/mnt/root/var/lib/rce'
# Defaults needed for both gosuper and node supervisor are declared in entry.sh # Defaults needed for both gosuper and node supervisor are declared in entry.sh
module.exports = module.exports =
apiEndpoint: checkString(process.env.API_ENDPOINT) ? 'https://api.resin.io' apiEndpoint: checkString(process.env.API_ENDPOINT) ? 'https://api.resin.io'
apiTimeout: checkInt(process.env.API_TIMEOUT) ? 15 * 60 * 1000 apiTimeout: checkInt(process.env.API_TIMEOUT, positive: true) ? 15 * 60 * 1000
listenPort: checkInt(process.env.LISTEN_PORT) ? 80 listenPort: checkInt(process.env.LISTEN_PORT, positive: true) ? 80
gosuperAddress: "http://unix:#{process.env.GOSUPER_SOCKET}:" gosuperAddress: "http://unix:#{process.env.GOSUPER_SOCKET}:"
deltaHost: checkString(process.env.DELTA_ENDPOINT) ? 'https://delta.resin.io' deltaHost: checkString(process.env.DELTA_ENDPOINT) ? 'https://delta.resin.io'
registryEndpoint: checkString(process.env.REGISTRY_ENDPOINT) ? 'registry.resin.io' registryEndpoint: checkString(process.env.REGISTRY_ENDPOINT) ? 'registry.resin.io'
@ -32,15 +18,14 @@ module.exports =
supervisorImage: checkString(process.env.SUPERVISOR_IMAGE) ? 'resin/rpi-supervisor' supervisorImage: checkString(process.env.SUPERVISOR_IMAGE) ? 'resin/rpi-supervisor'
configMountPoint: checkString(process.env.CONFIG_MOUNT_POINT) ? '/mnt/mmcblk0p1/config.json' configMountPoint: checkString(process.env.CONFIG_MOUNT_POINT) ? '/mnt/mmcblk0p1/config.json'
ledFile: checkString(process.env.LED_FILE) ? '/sys/class/leds/led0/brightness' ledFile: checkString(process.env.LED_FILE) ? '/sys/class/leds/led0/brightness'
bootstrapRetryDelay: checkInt(process.env.BOOTSTRAP_RETRY_DELAY_MS) ? 30000 bootstrapRetryDelay: checkInt(process.env.BOOTSTRAP_RETRY_DELAY_MS, positive: true) ? 30000
restartSuccessTimeout: checkInt(process.env.RESTART_SUCCESS_TIMEOUT) ? 60000 restartSuccessTimeout: checkInt(process.env.RESTART_SUCCESS_TIMEOUT, positive: true) ? 60000
appUpdatePollInterval: checkInt(process.env.APPLICATION_UPDATE_POLL_INTERVAL) ? 60000 appUpdatePollInterval: checkInt(process.env.APPLICATION_UPDATE_POLL_INTERVAL, positive: true) ? 60000
successMessage: 'SUPERVISOR OK' successMessage: 'SUPERVISOR OK'
forceSecret: forceSecret:
api: checkString(process.env.RESIN_SUPERVISOR_SECRET) ? null api: checkString(process.env.RESIN_SUPERVISOR_SECRET) ? null
logsChannel: checkString(process.env.RESIN_SUPERVISOR_LOGS_CHANNEL) ? null logsChannel: checkString(process.env.RESIN_SUPERVISOR_LOGS_CHANNEL) ? null
vpnStatusPath: checkString(process.env.VPN_STATUS_PATH) ? '/mnt/root/run/openvpn/vpn_status' vpnStatusPath: checkString(process.env.VPN_STATUS_PATH) ? '/mnt/root/run/openvpn/vpn_status'
checkInt: checkInt
hostOsVersionPath: checkString(process.env.HOST_OS_VERSION_PATH) ? '/mnt/root/etc/os-release' hostOsVersionPath: checkString(process.env.HOST_OS_VERSION_PATH) ? '/mnt/root/etc/os-release'
dockerRoot: dockerRoot dockerRoot: dockerRoot
btrfsRoot: checkString(process.env.BTRFS_ROOT) ? "#{dockerRoot}/btrfs/subvolumes" btrfsRoot: checkString(process.env.BTRFS_ROOT) ? "#{dockerRoot}/btrfs/subvolumes"

17
src/lib/validation.coffee Normal file
View File

@ -0,0 +1,17 @@
exports.checkInt = (s, options = {}) ->
# Make sure `s` exists and is not an empty string.
if !s
return
i = parseInt(s, 10)
if isNaN(i)
return
if options.positive && i <= 0
return
return i
exports.checkString = (s) ->
# Make sure `s` exists and is not an empty string, or 'null' or 'undefined'.
# This might happen if the parsing of config.json on the host using jq is wrong (it is buggy in some versions).
if !s? or s == 'null' or s == 'undefined' or s == ''
return
return s