balena-supervisor/src/utils.coffee

142 lines
4.1 KiB
CoffeeScript
Raw Normal View History

2013-12-23 04:22:54 +00:00
Promise = require 'bluebird'
2014-06-18 16:54:36 +00:00
_ = require 'lodash'
2013-12-23 04:22:54 +00:00
fs = Promise.promisifyAll require 'fs'
2014-06-18 16:54:36 +00:00
config = require './config'
mixpanel = require 'mixpanel'
networkCheck = require 'network-checker'
blink = require('blinking')(config.ledFile)
url = require 'url'
2015-08-26 21:57:14 +00:00
Inotify = require('inotify').Inotify
inotify = new Inotify()
fs = require 'fs'
2014-04-28 10:56:17 +00:00
utils = exports
# Parses package.json and returns resin-supervisor's version
exports.supervisorVersion = require('../package.json').version
mixpanelClient = mixpanel.init(config.mixpanelToken)
2014-06-18 16:54:36 +00:00
exports.mixpanelProperties = mixpanelProperties =
username: require('/boot/config.json').username
2014-09-15 11:31:14 +00:00
exports.mixpanelTrack = (event, properties = {}) ->
# Allow passing in an error directly and having it assigned to the error property.
if properties instanceof Error
properties = error: properties
# If the properties has an error argument that is an Error object then it treats it nicely,
# rather than letting it become `{}`
if properties.error instanceof Error
properties.error =
message: properties.error.message
stack: properties.error.stack
console.log('Event:', event, JSON.stringify(properties))
2014-06-18 16:54:36 +00:00
# Mutation is bad, and it should feel bad
properties = _.assign(_.cloneDeep(properties), mixpanelProperties)
mixpanelClient.track(event, properties)
# Returns an array of the host's ip address(es) by parsing the host /proc/net/fib_trie
exports.findIpAddrs = ->
fs.readFileAsync('/mnt/fib_trie', 'utf8')
.then (fibtrie) ->
prevLine = ''
fibtrie.split('\n')
.map (line) ->
line = line.trim()
# We only care about LOCAL routes (not UNICAST or BROADCAST)
if line.match(/LOCAL$/)
2014-09-15 14:04:38 +00:00
# Then we make sure the previous line was an ending branch (and hence contains an IP - 127.0.0.0 has
# BROADCAST and LOCAL entries)
if prevLine.match(/^\|--/)
# Then we remove the ending branch bit
maybeAddr = prevLine.replace(/^\|--/, '').trim()
# And ignore loopback/docker interfaces.
# TODO: Docker interface can technically be on another address range if 172.17
if !maybeAddr.match(/^(127.0.0.1|172.17.)/)
ipAddr = maybeAddr
prevLine = line
return ipAddr
.filter(Boolean)
networkPattern =
blinks: 4
pause: 1000
exports.blink = blink
pauseConnectivityCheck = false
disableConnectivityCheck = false
2015-08-26 21:57:14 +00:00
2015-08-26 13:40:22 +00:00
# options: An object of net.connect options, with the addition of:
# timeout: 10s
checkHost = (options) ->
new Promise (resolve, reject) ->
if disableConnectivityCheck
2015-08-26 13:40:22 +00:00
resolve()
else
if pauseConnectivityCheck
resolve()
else
reject()
2015-08-26 13:40:22 +00:00
.then ->
return true
.catch ->
return networkCheck.checkHost(options)
2015-08-26 21:57:14 +00:00
# Custom monitor that uses checkHost function above.
2015-08-26 13:40:22 +00:00
customMonitor = (options, fn) ->
networkCheck.monitor(checkHost, options, fn)
# pause: A Boolean to pause the connectivity checks
exports.pauseCheck = (pause) ->
pauseConnectivityCheck = pause
# disable: A Boolean to disable the connectivity checks
2015-08-26 13:40:22 +00:00
exports.disableCheck = (disable) ->
disableConnectivityCheck = disable
2015-08-26 13:40:22 +00:00
2015-08-26 21:57:14 +00:00
# Call back for inotify triggered when the VPN status is changed.
vpnStatusInotifyCallback = (arg) ->
try
stats = fs.lstatSync(config.vpnStatusPath+'/active')
pauseConnectivityCheck=true
catch error
pauseConnectivityCheck=false
vpn_status =
path: config.vpnStatusPath
watch_for: Inotify.IN_DELETE | Inotify.IN_CREATE
callback: vpnStatusInotifyCallback
# Helper to create the vpn status path if it does not already exist
mkdirSync = (path) ->
try
2015-08-27 13:54:41 +00:00
fs.mkdirSync(path)
2015-08-26 21:57:14 +00:00
catch error
if error.code != 'EEXIST'
throw error
mkdirSync(vpn_status.path)
exports.connectivityCheck = _.once ->
parsedUrl = url.parse(config.apiEndpoint)
2015-08-26 21:57:14 +00:00
inotify.addWatch(vpn_status)
# Manually trigger the call back to detect cases when VPN was switched on before the supervisor starts.
vpnStatusInotifyCallback()
2015-08-26 13:40:22 +00:00
customMonitor
host: parsedUrl.hostname
port: parsedUrl.port ? (if parsedUrl.protocol is 'https:' then 443 else 80)
interval: 10 * 1000
(connected) ->
if connected
2014-12-11 13:29:59 +00:00
console.log('Internet Connectivity: OK')
blink.pattern.stop()
else
2014-12-11 13:29:59 +00:00
console.log('Waiting for connectivity...')
blink.pattern.start(networkPattern)