mirror of
https://github.com/balena-os/balena-supervisor.git
synced 2025-05-17 16:22:57 +00:00
Auto-merge for PR #669 via VersionBot
Pin a device to a commit when preload has a pinDevice field
This commit is contained in:
commit
b9a16c067b
@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file
|
|||||||
automatically by Versionist. DO NOT EDIT THIS FILE MANUALLY!
|
automatically by Versionist. DO NOT EDIT THIS FILE MANUALLY!
|
||||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
|
|
||||||
|
## v7.11.0 - 2018-06-13
|
||||||
|
|
||||||
|
* Pin a device to a commit when preload has a pinDevice field #669 [Cameron Diver]
|
||||||
|
|
||||||
## v7.10.2 - 2018-06-11
|
## v7.10.2 - 2018-06-11
|
||||||
|
|
||||||
* Fix typo in EEXIST error predicate #677 [Cameron Diver]
|
* Fix typo in EEXIST error predicate #677 [Cameron Diver]
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "resin-supervisor",
|
"name": "resin-supervisor",
|
||||||
"description": "This is resin.io's Supervisor, a program that runs on IoT devices and has the task of running user Apps (which are Docker containers), and updating them as Resin's API informs it to.",
|
"description": "This is resin.io's Supervisor, a program that runs on IoT devices and has the task of running user Apps (which are Docker containers), and updating them as Resin's API informs it to.",
|
||||||
"version": "7.10.2",
|
"version": "7.11.0",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
@ -198,6 +198,20 @@ module.exports = class APIBinder
|
|||||||
@config.set(configToUpdate)
|
@config.set(configToUpdate)
|
||||||
.then =>
|
.then =>
|
||||||
@eventTracker.track('Device bootstrap success')
|
@eventTracker.track('Device bootstrap success')
|
||||||
|
# Check if we need to pin the device, regardless of if we provisioned
|
||||||
|
.then =>
|
||||||
|
@config.get('pinDevice')
|
||||||
|
.then(JSON.parse)
|
||||||
|
.tapCatch ->
|
||||||
|
console.log('Warning: Malformed pinDevice value in supervisor database')
|
||||||
|
.catchReturn(null)
|
||||||
|
.then (pinValue) =>
|
||||||
|
if pinValue?
|
||||||
|
if !pinValue.app? or !pinValue.commit?
|
||||||
|
console.log("Malformed pinDevice fields in supervisor database: #{pinValue}")
|
||||||
|
return
|
||||||
|
console.log('Attempting to pin device to preloaded release...')
|
||||||
|
@pinDevice(pinValue)
|
||||||
|
|
||||||
_provisionOrRetry: (retryDelay) =>
|
_provisionOrRetry: (retryDelay) =>
|
||||||
@eventTracker.track('Device bootstrap')
|
@eventTracker.track('Device bootstrap')
|
||||||
@ -214,9 +228,10 @@ module.exports = class APIBinder
|
|||||||
'provisioned'
|
'provisioned'
|
||||||
'bootstrapRetryDelay'
|
'bootstrapRetryDelay'
|
||||||
'apiKey'
|
'apiKey'
|
||||||
|
'pinDevice'
|
||||||
])
|
])
|
||||||
.tap (conf) =>
|
.tap (conf) =>
|
||||||
if !conf.provisioned or conf.apiKey?
|
if !conf.provisioned or conf.apiKey? or conf.pinDevice?
|
||||||
@_provisionOrRetry(conf.bootstrapRetryDelay)
|
@_provisionOrRetry(conf.bootstrapRetryDelay)
|
||||||
|
|
||||||
provisionDependentDevice: (device) =>
|
provisionDependentDevice: (device) =>
|
||||||
@ -263,6 +278,34 @@ module.exports = class APIBinder
|
|||||||
body: updatedFields
|
body: updatedFields
|
||||||
.timeout(conf.apiTimeout)
|
.timeout(conf.apiTimeout)
|
||||||
|
|
||||||
|
pinDevice: ({ app, commit }) =>
|
||||||
|
@config.get('deviceId')
|
||||||
|
.then (deviceId) =>
|
||||||
|
@resinApi.get
|
||||||
|
resource: 'release'
|
||||||
|
options:
|
||||||
|
filter:
|
||||||
|
belongs_to__application: app
|
||||||
|
commit: commit
|
||||||
|
status: 'success'
|
||||||
|
select: 'id'
|
||||||
|
.then (release) =>
|
||||||
|
releaseId = _.get(release, '[0].id')
|
||||||
|
if !releaseId?
|
||||||
|
throw new Error('Cannot continue pinning preloaded device! No release found!')
|
||||||
|
@resinApi.patch
|
||||||
|
resource: 'device'
|
||||||
|
id: deviceId
|
||||||
|
body:
|
||||||
|
should_be_running__release: releaseId
|
||||||
|
.then =>
|
||||||
|
# Set the config value for pinDevice to null, so that we know the
|
||||||
|
# task has been completed
|
||||||
|
@config.remove('pinDevice')
|
||||||
|
.tapCatch (e) ->
|
||||||
|
console.log('Could not pin device to release!')
|
||||||
|
console.log('Error: ', e)
|
||||||
|
|
||||||
_sendLogsRequest: (uuid, data) =>
|
_sendLogsRequest: (uuid, data) =>
|
||||||
reqBody = _.map(data, (msg) -> _.mapKeys(msg, (v, k) -> _.snakeCase(k)))
|
reqBody = _.map(data, (msg) -> _.mapKeys(msg, (v, k) -> _.snakeCase(k)))
|
||||||
@config.get('resinApiEndpoint')
|
@config.get('resinApiEndpoint')
|
||||||
|
@ -151,6 +151,8 @@ module.exports = class Config extends EventEmitter
|
|||||||
lockOverride: { source: 'db', mutable: true, default: 'false' }
|
lockOverride: { source: 'db', mutable: true, default: 'false' }
|
||||||
legacyAppsPresent: { source: 'db', mutable: true, default: 'false' }
|
legacyAppsPresent: { source: 'db', mutable: true, default: 'false' }
|
||||||
nativeLogger: { source: 'db', mutable: true, default: 'true' }
|
nativeLogger: { source: 'db', mutable: true, default: 'true' }
|
||||||
|
# A JSON value, which is either null, or { app: number, commit: string }
|
||||||
|
pinDevice: { source: 'db', mutable: true, default: 'null' }
|
||||||
}
|
}
|
||||||
|
|
||||||
@configJsonCache = {}
|
@configJsonCache = {}
|
||||||
|
@ -313,11 +313,17 @@ module.exports = class DeviceState extends EventEmitter
|
|||||||
fs.readFileAsync(appsPath, 'utf8')
|
fs.readFileAsync(appsPath, 'utf8')
|
||||||
.then(JSON.parse)
|
.then(JSON.parse)
|
||||||
.then (stateFromFile) =>
|
.then (stateFromFile) =>
|
||||||
|
commitToPin = null
|
||||||
|
appToPin = null
|
||||||
if !_.isEmpty(stateFromFile)
|
if !_.isEmpty(stateFromFile)
|
||||||
if _.isArray(stateFromFile)
|
if _.isArray(stateFromFile)
|
||||||
# This is a legacy apps.json
|
# This is a legacy apps.json
|
||||||
stateFromFile = @_convertLegacyAppsJson(stateFromFile)
|
stateFromFile = @_convertLegacyAppsJson(stateFromFile)
|
||||||
images = _.flatMap stateFromFile.apps, (app, appId) =>
|
images = _.flatMap stateFromFile.apps, (app, appId) =>
|
||||||
|
# multi-app warning!
|
||||||
|
# The following will need to be changed once running multiple applications is possible
|
||||||
|
commitToPin = app.commit
|
||||||
|
appToPin = appId
|
||||||
_.map app.services, (service, serviceId) =>
|
_.map app.services, (service, serviceId) =>
|
||||||
svc = {
|
svc = {
|
||||||
imageName: service.image
|
imageName: service.image
|
||||||
@ -341,6 +347,16 @@ module.exports = class DeviceState extends EventEmitter
|
|||||||
@setTarget({
|
@setTarget({
|
||||||
local: stateFromFile
|
local: stateFromFile
|
||||||
})
|
})
|
||||||
|
.then =>
|
||||||
|
if stateFromFile.pinDevice
|
||||||
|
# multi-app warning!
|
||||||
|
# The following will need to be changed once running multiple applications is possible
|
||||||
|
if commitToPin? and appToPin?
|
||||||
|
@config.set
|
||||||
|
pinDevice: JSON.stringify {
|
||||||
|
commit: commitToPin,
|
||||||
|
app: appToPin,
|
||||||
|
}
|
||||||
.catch (err) =>
|
.catch (err) =>
|
||||||
@eventTracker.track('Loading preloaded apps failed', { error: err })
|
@eventTracker.track('Loading preloaded apps failed', { error: err })
|
||||||
|
|
||||||
|
@ -235,6 +235,19 @@ describe 'deviceState', ->
|
|||||||
@deviceState.applications.images.save.restore()
|
@deviceState.applications.images.save.restore()
|
||||||
@deviceState.deviceConfig.getCurrent.restore()
|
@deviceState.deviceConfig.getCurrent.restore()
|
||||||
|
|
||||||
|
it 'stores info for pinning a device after loading an apps.json with a pinDevice field', ->
|
||||||
|
stub(@deviceState.applications.images, 'save').returns(Promise.resolve())
|
||||||
|
stub(@deviceState.deviceConfig, 'getCurrent').returns(Promise.resolve(mockedInitialConfig))
|
||||||
|
@deviceState.loadTargetFromFile(process.env.ROOT_MOUNTPOINT + '/apps-pin.json')
|
||||||
|
.then =>
|
||||||
|
@deviceState.applications.images.save.restore()
|
||||||
|
@deviceState.deviceConfig.getCurrent.restore()
|
||||||
|
|
||||||
|
@config.get('pinDevice').then (pinnedString) ->
|
||||||
|
pinned = JSON.parse(pinnedString)
|
||||||
|
expect(pinned).to.have.property('app').that.equals('1234')
|
||||||
|
expect(pinned).to.have.property('commit').that.equals('abcdef')
|
||||||
|
|
||||||
it 'emits a change event when a new state is reported', ->
|
it 'emits a change event when a new state is reported', ->
|
||||||
@deviceState.reportCurrentState({ someStateDiff: 'someValue' })
|
@deviceState.reportCurrentState({ someStateDiff: 'someValue' })
|
||||||
expect(@deviceState).to.emit('change')
|
expect(@deviceState).to.emit('change')
|
||||||
|
26
test/data/apps-pin.json
Normal file
26
test/data/apps-pin.json
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"name": "aDevice",
|
||||||
|
"config": {
|
||||||
|
"RESIN_HOST_CONFIG_gpu_mem": "256",
|
||||||
|
"RESIN_HOST_LOG_TO_DISPLAY": "0"
|
||||||
|
},
|
||||||
|
"apps": {
|
||||||
|
"1234": {
|
||||||
|
"name": "superapp",
|
||||||
|
"commit": "abcdef",
|
||||||
|
"releaseId": 1,
|
||||||
|
"services": {
|
||||||
|
"23": {
|
||||||
|
"imageId": 12345,
|
||||||
|
"serviceName": "someservice",
|
||||||
|
"image": "registry2.resin.io/superapp/abcdef",
|
||||||
|
"labels": {
|
||||||
|
"io.resin.something": "bar"
|
||||||
|
},
|
||||||
|
"environment": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pinDevice": true
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user