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:
Page 2014-06-06 22:46:23 +01:00 committed by Pablo Carranza Vélez
parent d47ba654b7
commit a0f9219cb3
3 changed files with 78 additions and 1 deletions

View File

@ -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",

View File

@ -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

View 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