Application management code in its own module

This commit is contained in:
Petros Aggelatos 2013-12-29 18:07:58 +00:00 committed by Pablo Carranza Vélez
parent 614b24c796
commit 637d68921f
3 changed files with 105 additions and 36 deletions

View File

@ -1,10 +1,8 @@
Promise = require 'bluebird'
fs = Promise.promisifyAll require 'fs'
url = require 'url'
knex = require './db'
utils = require './utils'
express = require 'express'
request = Promise.promisify require 'request'
application = require './application'
api = express()
@ -24,22 +22,9 @@ api.post('/v1/blink', (req, res) ->
)
api.post('/v1/update', (req, res) ->
console.log("Got application update")
application.update()
res.send(204)
Promise.all([
knex('config').select('value').where(key: 'apiKey')
knex('config').select('value').where(key: 'uuid')
]).then(([[apiKey], [uuid]]) ->
apiKey = apiKey.value
uuid = uuid.value
request(
method: 'GET'
url: url.resolve(process.env.API_ENDPOINT, "/ewa/application?$filter=device/uuid eq '#{uuid}'&apikey=#{apiKey}")
json: true
).spread((request, body) ->
for app in body.d
console.log("Got application", app)
)
)
)
module.exports = api

View File

@ -46,8 +46,14 @@ Promise.all([newUuid, oldUuid]).then(([newUuid, [oldUuid]]) ->
console.log('Starting Apps..')
knex('app').select().then((apps) ->
Promise.all(apps.map(application.start))
Promise.all(apps.map((app) -> app.imageId).map(application.restart))
).catch((error) ->
console.log(error)
console.error("Error starting apps:", error)
).then(->
console.log('Starting periodic check for updates..')
setInterval(->
application.update()
, 15 * 60 * 1000) # Every 15 mins
application.update()
)
)

View File

@ -1,32 +1,59 @@
Promise = require 'bluebird'
Docker = require 'dockerode'
JSONStream = require 'JSONStream'
_ = require 'lodash'
es = require 'event-stream'
url = require 'url'
http = require 'http'
knex = require './db'
path = require 'path'
Docker = require 'dockerode'
Promise = require 'bluebird'
request = Promise.promisify require 'request'
JSONStream = require 'JSONStream'
docker = Promise.promisifyAll(new Docker(socketPath: '/hostrun/docker.sock'))
# Hack dockerode to promisify internal classes' prototype
# Hack dockerode to promisify internal classes' prototypes
Promise.promisifyAll(docker.getImage().__proto__)
Promise.promisifyAll(docker.getContainer().__proto__)
exports.start = (app) ->
docker.getImage(app.imageId).inspectAsync().catch(->
exports.kill = kill = (app) ->
docker.listContainersAsync(all: 1).then((containers) ->
Promise.all(
containers
.filter((container) ->
return container.Image is "#{app}:latest"
)
.map((container) -> docker.getContainer(container.Id))
.map((container) ->
console.log("Stopping and deleting container:", container)
container.stopAsync().then(->
container.removeAsync()
)
)
)
)
exports.start = start = (app) ->
docker.getImage(app).inspectAsync().catch((error) ->
console.log(error)
deferred = Promise.defer()
options =
method: 'POST'
path: "/v1.8/images/create?fromImage=#{app.imageId}"
path: "/v1.8/images/create?fromImage=#{app}"
socketPath: '/hostrun/docker.sock'
req = http.request(options, (res) ->
if res.statusCode isnt 200
return deferred.reject()
res.pipe(JSONStream.parse('error'))
.pipe(es.mapSync((error) ->
deferred.reject(error)
))
if res.headers['content-type'] is 'application/json'
res.pipe(JSONStream.parse('error'))
.pipe(es.mapSync((error) ->
deferred.reject(error)
))
else
res.pipe(es.wait((error, text) -> deferred.reject(text)))
res.on('end', ->
deferred.resolve()
if res.statusCode is 200
deferred.resolve()
else
deferred.reject(res.statusCode)
)
)
req.end()
@ -34,5 +61,56 @@ exports.start = (app) ->
return deferred.promise
).then(->
docker.runAsync(app.imageId, ['/bin/bash', '-c', '/start web'], process.stdout, true)
console.log("Creating container:", app)
docker.createContainerAsync(
Image: app
Cmd: ['/bin/bash', '-c', '/start web']
)
).then((container) ->
container.startAsync()
)
exports.restart = restart = (app) ->
kill(app).then(->
start(app)
)
exports.update = ->
Promise.all([
knex('config').select('value').where(key: 'apiKey')
knex('config').select('value').where(key: 'uuid')
knex('app').select()
]).then(([[apiKey], [uuid], apps]) ->
apiKey = apiKey.value
uuid = uuid.value
request(
method: 'GET'
url: url.resolve(process.env.API_ENDPOINT, "/ewa/application?$filter=device/uuid eq '#{uuid}'&apikey=#{apiKey}")
json: true
).spread((request, body) ->
console.log("Remote apps")
remoteApps = ("registry.resin.io:5000/#{path.basename(app.git_repository, '.git')}/#{app.commit}" for app in body.d)
console.log(remoteApps)
console.log("Local apps")
localApps = (app.imageId for app in apps)
console.log(localApps)
console.log("Apps to be removed")
toBeRemoved = _.difference(localApps, remoteApps)
console.log(toBeRemoved)
console.log("Apps to be installed")
toBeInstalled = _.difference(remoteApps, localApps)
console.log(toBeInstalled)
Promise.all(toBeRemoved.map(kill)).then(->
Promise.all(toBeInstalled.map(start))
).then(->
knex('app').whereIn('imageId', toBeRemoved).delete().then(->
knex('app').insert(({imageId: app} for app in toBeInstalled))
)
)
)
)