mirror of
https://github.com/balena-os/balena-supervisor.git
synced 2024-12-23 15:32:24 +00:00
Auto-merge for PR #472 via VersionBot
When the device is about to reboot or shutdown, close the API server and avoid applying updates
This commit is contained in:
commit
bb6652c52d
@ -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!
|
||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## v6.1.2 - 2017-07-27
|
||||
|
||||
* When the device is about to reboot or shutdown, close the API server and avoid applying updates [Pablo Carranza Velez]
|
||||
|
||||
## v6.1.1 - 2017-07-27
|
||||
|
||||
* Avoid unhandled errors when in offline mode due to a missing apiEndpoint [Pablo Carranza Velez]
|
||||
|
@ -77,7 +77,7 @@ $ curl -X POST --header "Content-Type:application/json" \
|
||||
|
||||
Triggers an update check on the supervisor. Optionally, forces an update when updates are locked.
|
||||
|
||||
Responds with an empty 204 (Accepted) response.
|
||||
Responds with an empty 204 (No Content) response.
|
||||
|
||||
#### Request body
|
||||
Can be a JSON object with a `force` property. If this property is true, the update lock will be overridden.
|
||||
@ -110,7 +110,7 @@ $ curl -X POST --header "Content-Type:application/json" \
|
||||
|
||||
Reboots the device
|
||||
|
||||
When successful, responds with 204 accepted and a JSON object:
|
||||
When successful, responds with 202 accepted and a JSON object:
|
||||
```json
|
||||
{
|
||||
"Data": "OK",
|
||||
@ -144,7 +144,7 @@ $ curl -X POST --header "Content-Type:application/json" \
|
||||
|
||||
**Dangerous**. Shuts down the device.
|
||||
|
||||
When successful, responds with 204 accepted and a JSON object:
|
||||
When successful, responds with 202 accepted and a JSON object:
|
||||
```json
|
||||
{
|
||||
"Data": "OK",
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"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.",
|
||||
"version": "6.1.1",
|
||||
"version": "6.1.2",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -57,18 +57,16 @@ module.exports = (application) ->
|
||||
.then (app) ->
|
||||
application.kill(app, removeContainer: false) if app?
|
||||
.then ->
|
||||
new Promise (resolve, reject) ->
|
||||
application.logSystemMessage('Rebooting', {}, 'Reboot')
|
||||
utils.gosuper.post('/v1/reboot')
|
||||
.on('error', reject)
|
||||
.on('response', -> resolve())
|
||||
.pipe(res)
|
||||
application.logSystemMessage('Rebooting', {}, 'Reboot')
|
||||
device.reboot()
|
||||
.then (response) ->
|
||||
res.status(202).json(response)
|
||||
.catch (err) ->
|
||||
if err instanceof application.UpdatesLockedError
|
||||
status = 423
|
||||
else
|
||||
status = 500
|
||||
res.status(status).send(err?.message or err or 'Unknown error')
|
||||
res.status(status).json({ Data: '', Error: err?.message or err or 'Unknown error' })
|
||||
|
||||
parsedRouter.post '/v1/shutdown', (req, res) ->
|
||||
force = req.body.force
|
||||
@ -80,18 +78,16 @@ module.exports = (application) ->
|
||||
.then (app) ->
|
||||
application.kill(app, removeContainer: false) if app?
|
||||
.then ->
|
||||
new Promise (resolve, reject) ->
|
||||
application.logSystemMessage('Shutting down', {}, 'Shutdown')
|
||||
utils.gosuper.post('/v1/shutdown')
|
||||
.on('error', reject)
|
||||
.on('response', -> resolve())
|
||||
.pipe(res)
|
||||
application.logSystemMessage('Shutting down', {}, 'Shutdown')
|
||||
device.shutdown()
|
||||
.then (response) ->
|
||||
res.status(202).json(response)
|
||||
.catch (err) ->
|
||||
if err instanceof application.UpdatesLockedError
|
||||
status = 423
|
||||
else
|
||||
status = 500
|
||||
res.status(status).send(err?.message or err or 'Unknown error')
|
||||
res.status(status).json({ Data: '', Error: err?.message or err or 'Unknown error' })
|
||||
|
||||
parsedRouter.post '/v1/purge', (req, res) ->
|
||||
appId = req.body.appId
|
||||
|
@ -29,7 +29,8 @@ knex.init.then ->
|
||||
.then ->
|
||||
apiServer = api(application).listen(config.listenPort)
|
||||
apiServer.timeout = config.apiTimeout
|
||||
|
||||
device.events.on 'shutdown', ->
|
||||
apiServer.close()
|
||||
bootstrap.done
|
||||
.then ->
|
||||
Promise.join(
|
||||
|
@ -709,7 +709,7 @@ application.update = update = (force, scheduled = false) ->
|
||||
.tap (remoteApps) ->
|
||||
# Before running the updates, try to clean up any images that aren't in use
|
||||
# and will not be used in the target state
|
||||
return if application.localMode
|
||||
return if application.localMode or device.shuttingDown
|
||||
dockerUtils.cleanupContainersAndImages(_.map(remoteApps, 'imageId'))
|
||||
.catch (err) ->
|
||||
console.log('Cleanup failed: ', err, err.stack)
|
||||
@ -737,7 +737,7 @@ application.update = update = (force, scheduled = false) ->
|
||||
logSystemMessage("Error fetching/applying device configuration: #{err}", { error: err }, 'Set device configuration error')
|
||||
.return(allAppIds)
|
||||
.map (appId) ->
|
||||
return if application.localMode
|
||||
return if application.localMode or device.shuttingDown
|
||||
Promise.try ->
|
||||
needsDownload = _.includes(toBeDownloaded, appId)
|
||||
if _.includes(toBeRemoved, appId)
|
||||
@ -792,9 +792,9 @@ application.update = update = (force, scheduled = false) ->
|
||||
_.each(failures, (err) -> console.error('Error:', err, err.stack))
|
||||
throw new Error(joinErrorMessages(failures)) if failures.length > 0
|
||||
.then ->
|
||||
proxyvisor.sendUpdates()
|
||||
proxyvisor.sendUpdates() if !device.shuttingDown
|
||||
.then ->
|
||||
return if application.localMode
|
||||
return if application.localMode or device.shuttingDown
|
||||
updateStatus.failed = 0
|
||||
device.setUpdateState(update_pending: false, update_downloaded: false, update_failed: false)
|
||||
# We cleanup here as we want a point when we have a consistent apps/images state, rather than potentially at a
|
||||
|
@ -1,7 +1,6 @@
|
||||
_ = require 'lodash'
|
||||
Promise = require 'bluebird'
|
||||
memoizee = require 'memoizee'
|
||||
knex = require './db'
|
||||
utils = require './utils'
|
||||
{ resinApi } = require './request'
|
||||
device = exports
|
||||
@ -12,6 +11,7 @@ fs = Promise.promisifyAll(require('fs'))
|
||||
bootstrap = require './bootstrap'
|
||||
{ checkTruthy } = require './lib/validation'
|
||||
osRelease = require './lib/os-release'
|
||||
EventEmitter = require 'events'
|
||||
|
||||
# If we don't use promise: 'then', exceptions will crash the program
|
||||
memoizePromise = _.partial(memoizee, _, promise: 'then')
|
||||
@ -40,8 +40,25 @@ exports.getID = memoizePromise ->
|
||||
throw new Error('Could not find this device?!')
|
||||
return devices[0].id
|
||||
|
||||
exports.shuttingDown = false
|
||||
exports.events = new EventEmitter()
|
||||
exports.reboot = ->
|
||||
utils.gosuper.postAsync('/v1/reboot')
|
||||
utils.gosuper.postAsync('/v1/reboot', { json: true })
|
||||
.spread (res, body) ->
|
||||
if res.statusCode != 202
|
||||
throw new Error(body.Error)
|
||||
exports.shuttingDown = true
|
||||
exports.events.emit('shutdown')
|
||||
return body
|
||||
|
||||
exports.shutdown = ->
|
||||
utils.gosuper.postAsync('/v1/shutdown', { json: true })
|
||||
.spread (res, body) ->
|
||||
if res.statusCode != 202
|
||||
throw new Error(body.Error)
|
||||
exports.shuttingDown = true
|
||||
exports.events.emit('shutdown')
|
||||
return body
|
||||
|
||||
exports.hostConfigConfigVarPrefix = 'RESIN_HOST_'
|
||||
bootConfigEnvVarPrefix = 'RESIN_HOST_CONFIG_'
|
||||
|
Loading…
Reference in New Issue
Block a user