mirror of
https://github.com/balena-os/balena-supervisor.git
synced 2025-02-18 17:00:25 +00:00
Initial version of self-updates, adds an "/v1/update-supervisor" endpoint that can be posted to in order to trigger a supervisor update, which it then fetches as the resin/rpi-supervisor repo of the registry endpoint.
This commit is contained in:
parent
d47ba654b7
commit
a0f9219cb3
@ -12,7 +12,7 @@
|
||||
"express": "~3.2.6",
|
||||
"lodash": "~2.4.1",
|
||||
"csr-gen": "~0.2.1",
|
||||
"dockerode": "~0.2.5",
|
||||
"dockerode": "~2.0.0",
|
||||
"knex": "~0.5.1",
|
||||
"bluebird": "~1.1.1",
|
||||
"JSONStream": "~0.7.1",
|
||||
|
@ -3,6 +3,7 @@ fs = Promise.promisifyAll require 'fs'
|
||||
utils = require './utils'
|
||||
express = require 'express'
|
||||
application = require './application'
|
||||
supervisor = require './supervisor-update'
|
||||
|
||||
api = express()
|
||||
|
||||
@ -25,4 +26,9 @@ api.post '/v1/update', (req, res) ->
|
||||
application.update()
|
||||
res.send(204)
|
||||
|
||||
api.post '/v1/update-supervisor', (req, res) ->
|
||||
console.log('Got supervisor update')
|
||||
supervisor.update()
|
||||
res.send(204)
|
||||
|
||||
module.exports = api
|
||||
|
71
src/supervisor-update.coffee
Normal file
71
src/supervisor-update.coffee
Normal file
@ -0,0 +1,71 @@
|
||||
es = require 'event-stream'
|
||||
Docker = require 'dockerode'
|
||||
Promise = require 'bluebird'
|
||||
JSONStream = require 'JSONStream'
|
||||
config = require './config'
|
||||
|
||||
DOCKER_SOCKET = '/run/docker.sock'
|
||||
|
||||
docker = Promise.promisifyAll(new Docker(socketPath: DOCKER_SOCKET))
|
||||
# Hack dockerode to promisify internal classes' prototypes
|
||||
Promise.promisifyAll(docker.getImage().__proto__)
|
||||
Promise.promisifyAll(docker.getContainer().__proto__)
|
||||
|
||||
supervisorTag = 'resin/rpi-supervisor'
|
||||
updateImage = config.REGISTRY_ENDPOINT + '/' + supervisorTag
|
||||
|
||||
supervisorUpdating = Promise.resolve()
|
||||
exports.update = ->
|
||||
# Make sure only one attempt to update the full supervisor is running at a time, ignoring any errors from previous update attempts
|
||||
supervisorUpdating = supervisorUpdating.catch(->).then ->
|
||||
console.log('Fetching updated supervisor:', updateImage)
|
||||
docker.createImageAsync(fromImage: updateImage)
|
||||
.then (stream) ->
|
||||
deferred = Promise.defer()
|
||||
|
||||
if stream.headers['content-type'] is 'application/json'
|
||||
stream.pipe(JSONStream.parse('error'))
|
||||
.pipe es.mapSync (error) ->
|
||||
deferred.reject(error)
|
||||
else
|
||||
stream.pipe es.wait (error, text) -> deferred.reject(text)
|
||||
|
||||
stream.on 'end', -> deferred.resolve()
|
||||
|
||||
return deferred.promise
|
||||
.then ->
|
||||
console.log('Tagging updated supervisor:', updateImage)
|
||||
docker.getImage(updateImage).tagAsync(
|
||||
repo: supervisorTag
|
||||
force: true
|
||||
)
|
||||
.then ->
|
||||
console.log('Creating updated supervisor container:', supervisorTag)
|
||||
docker.createContainerAsync(
|
||||
Image: supervisorTag
|
||||
Cmd: ['/start']
|
||||
Volumes:
|
||||
'/boot/config.json': '/mnt/mmcblk0p1/config.json',
|
||||
'/data': '/var/lib/docker/data',
|
||||
'/run/docker.sock': '/var/run/docker.sock'
|
||||
Env: [
|
||||
'API_ENDPOINT=' + config.API_ENDPOINT
|
||||
'REGISTRY_ENDPOINT=' + config.REGISTRY_ENDPOINT
|
||||
]
|
||||
)
|
||||
.then (container) ->
|
||||
console.log('Starting updated supervisor container:', supervisorTag)
|
||||
container.startAsync(
|
||||
Privileged: true
|
||||
Binds: [
|
||||
'/mnt/mmcblk0p1/config.json:/boot/config.json'
|
||||
'/var/run/docker.sock:/run/docker.sock'
|
||||
'/var/lib/docker/data:/data'
|
||||
]
|
||||
)
|
||||
.then ->
|
||||
# We've started the new container, so we're done here! #pray
|
||||
process.exit()
|
||||
.catch (err) ->
|
||||
console.error('Error updating supervisor:', err)
|
||||
throw err
|
Loading…
x
Reference in New Issue
Block a user