Do not bind mount kmod if the host is not Resin OS 1.X

Resin OS 2.X removes the use of compressed modules, which was the initial
motivation for us to bind mount kmod into user containers (as Debian distros
don't include support for compressed modules).

This is a breaking change, but we still keep bind mounting on devices that are
on 1.X to ensure we don't break apps currently relying on the feature.

Implementation note: some functions in device.coffee have been refactored to
extract (DRY) a memoization procedure for Promise-returning functions.
`device.getOSVersion()` now also memoizes its result.

Change-Type: major
Signed-off-by: Pablo Carranza Velez <pablo@resin.io>
This commit is contained in:
Pablo Carranza Velez 2016-12-20 02:44:27 -03:00
parent 7006f58267
commit 458add1759
3 changed files with 46 additions and 51 deletions

View File

@ -29,6 +29,7 @@
"lockfile": "^1.0.1",
"lodash": "^4.16.3",
"log-timestamp": "^0.1.2",
"memoizee": "^0.4.1",
"mixpanel": "0.0.20",
"mkdirp": "^0.5.1",
"network-checker": "~0.0.5",
@ -51,4 +52,4 @@
"resin-lint": "^1.3.1",
"versionist": "^2.6.2"
}
}
}

View File

@ -210,13 +210,15 @@ fetch = (app, setDeviceUpdateState = true) ->
throw err
shouldMountKmod = (image) ->
Promise.using docker.imageRootDirMounted(image), (rootDir) ->
utils.getOSVersion(rootDir + '/etc/os-release')
.then (version) ->
return version? and (version.match(/^Debian/i) or version.match(/^Raspbian/i))
.catch (err) ->
console.error('Error getting app OS release: ', err)
return false
device.getOSVersion().then (osVersion) ->
return false if not /^Resin OS 1./.test(osVersion)
Promise.using docker.imageRootDirMounted(image), (rootDir) ->
utils.getOSVersion(rootDir + '/etc/os-release')
.then (version) ->
return version? and /^(Debian|Raspbian)/i.test(version)
.catch (err) ->
console.error('Error getting app OS release: ', err)
return false
application.start = start = (app) ->
volumes = utils.defaultVolumes

View File

@ -1,5 +1,6 @@
_ = require 'lodash'
Promise = require 'bluebird'
memoizee = require 'memoizee'
knex = require './db'
utils = require './utils'
{ resinApi } = require './request'
@ -10,36 +11,31 @@ execAsync = Promise.promisify(require('child_process').exec)
fs = Promise.promisifyAll(require('fs'))
bootstrap = require './bootstrap'
exports.getID = do ->
deviceIdPromise = null
return ->
# We initialise the rejected promise just before we catch in order to avoid a useless first unhandled error warning.
deviceIdPromise ?= Promise.rejected()
# Only fetch the device id once (when successful, otherwise retry for each request)
deviceIdPromise = deviceIdPromise.catch ->
# Wait for bootstrapping to be done before querying the Resin API
# This will also block users of getID (like applyState below until this is resolved)
bootstrap.done
.then ->
Promise.all([
knex('config').select('value').where(key: 'apiKey')
knex('config').select('value').where(key: 'uuid')
])
.spread ([{ value: apiKey }], [{ value: uuid }]) ->
resinApi.get(
resource: 'device'
options:
select: 'id'
filter:
uuid: uuid
customOptions:
apikey: apiKey
)
.timeout(config.apiTimeout)
.then (devices) ->
if devices.length is 0
throw new Error('Could not find this device?!')
return devices[0].id
memoizePromise = _.partial(memoizee, _, promise: true)
exports.getID = memoizePromise ->
bootstrap.done
.then ->
Promise.all([
knex('config').select('value').where(key: 'apiKey')
knex('config').select('value').where(key: 'uuid')
])
.spread ([{ value: apiKey }], [{ value: uuid }]) ->
resinApi.get(
resource: 'device'
options:
select: 'id'
filter:
uuid: uuid
customOptions:
apikey: apiKey
)
.timeout(config.apiTimeout)
.then (devices) ->
if devices.length is 0
throw new Error('Could not find this device?!')
return devices[0].id
exports.reboot = ->
utils.gosuper.postAsync('/v1/reboot')
@ -154,17 +150,13 @@ setBootConfig = (env, oldEnv, logMessage) ->
console.log('Will not set boot config: ', err)
return false
exports.getDeviceType = do ->
deviceTypePromise = null
return ->
deviceTypePromise ?= Promise.rejected()
deviceTypePromise = deviceTypePromise.catch ->
fs.readFileAsync(configPath, 'utf8')
.then(JSON.parse)
.then (configFromFile) ->
if !configFromFile.deviceType?
throw new Error('Device type not specified in config file')
return configFromFile.deviceType
exports.getDeviceType = memoizePromise ->
fs.readFileAsync(configPath, 'utf8')
.then(JSON.parse)
.then (configFromFile) ->
if !configFromFile.deviceType?
throw new Error('Device type not specified in config file')
return configFromFile.deviceType
do ->
applyPromise = Promise.resolve()
@ -227,8 +219,8 @@ do ->
applyState()
return
exports.getOSVersion = ->
return utils.getOSVersion(config.hostOsVersionPath)
exports.getOSVersion = memoizePromise ->
utils.getOSVersion(config.hostOsVersionPath)
exports.getConfig = ->
knex('deviceConfig').select()