Merge pull request #172 from resin-io/151-compose

Add endpoints for docker-compose up and down
This commit is contained in:
Pablo Carranza Vélez 2016-06-28 14:43:35 -03:00 committed by GitHub
commit 52ef519ebc
16 changed files with 245 additions and 41 deletions

View File

@ -1,3 +1,5 @@
* Add endpoints for docker-compose up and down [Pablo]
# v1.11.6
* Fixed deltas for older docker daemon versions [petrosagg]

View File

@ -1,11 +1,22 @@
FROM resin/amd64-alpine-node:0.10.44-slim
ENV DOCKER_COMPOSE_VERSION 1.7.1
ENV DOCKER_COMPOSE_SHA256 0b8184817097eb670b92cbdac6cb9f7f2e9fe384c0b1060cb9b3d1a475fcbea6
# Supervisor apt dependencies
RUN apk add --update \
btrfs-progs \
ca-certificates \
curl \
rsync \
supervisor \
&& curl -sLO http://resin-packages.s3.amazonaws.com/docker-compose/${DOCKER_COMPOSE_VERSION}/docker-compose-linux-alpine-amd64-${DOCKER_COMPOSE_VERSION}.tar.gz \
&& echo "$DOCKER_COMPOSE_SHA256 docker-compose-linux-alpine-amd64-${DOCKER_COMPOSE_VERSION}.tar.gz" > docker-compose-linux-alpine-amd64-${DOCKER_COMPOSE_VERSION}.tar.gz.sha256 \
&& sha256sum -c docker-compose-linux-alpine-amd64-${DOCKER_COMPOSE_VERSION}.tar.gz.sha256 \
&& tar xzf docker-compose-linux-alpine-amd64-${DOCKER_COMPOSE_VERSION}.tar.gz \
&& mv docker-compose-linux-alpine-amd64-${DOCKER_COMPOSE_VERSION}/docker-compose-linux-alpine-amd64 /usr/bin/docker-compose \
&& rm -rf docker-compose-linux-alpine-amd64-${DOCKER_COMPOSE_VERSION}* \
&& apk del curl \
&& rm -rf /var/cache/apk/*
# Copy supervisord configuration files

View File

@ -1,11 +1,22 @@
FROM resin/armhf-alpine-node:0.10.44-slim
ENV DOCKER_COMPOSE_VERSION 1.7.1
ENV DOCKER_COMPOSE_SHA256 3e5d0a36f06d9f7a93eb20c1dee67da623b07a322168538ea80d65c8581f5567
# Supervisor apt dependencies
RUN apk add --update \
btrfs-progs \
ca-certificates \
curl \
rsync \
supervisor \
&& curl -sLO http://resin-packages.s3.amazonaws.com/docker-compose/${DOCKER_COMPOSE_VERSION}/docker-compose-linux-alpine-armhf-${DOCKER_COMPOSE_VERSION}.tar.gz \
&& echo "$DOCKER_COMPOSE_SHA256 docker-compose-linux-alpine-armhf-${DOCKER_COMPOSE_VERSION}.tar.gz" > docker-compose-linux-alpine-armhf-${DOCKER_COMPOSE_VERSION}.tar.gz.sha256 \
&& sha256sum -c docker-compose-linux-alpine-armhf-${DOCKER_COMPOSE_VERSION}.tar.gz.sha256 \
&& tar xzf docker-compose-linux-alpine-armhf-${DOCKER_COMPOSE_VERSION}.tar.gz \
&& mv docker-compose-linux-alpine-armhf-${DOCKER_COMPOSE_VERSION}/docker-compose-linux-alpine-armhf /usr/bin/docker-compose \
&& rm -rf docker-compose-linux-alpine-armhf-${DOCKER_COMPOSE_VERSION}* \
&& apk del curl \
&& rm -rf /var/cache/apk/*
# Copy supervisord configuration files

View File

@ -1,11 +1,22 @@
FROM resin/i386-alpine-node:0.10.44-slim
ENV DOCKER_COMPOSE_VERSION 1.7.1
ENV DOCKER_COMPOSE_SHA256 160ba547bfd4dc967ec4f1927550f2d832316fad492e0e6f8d374da89ddac779
# Supervisor apt dependencies
RUN apk add --update \
btrfs-progs \
ca-certificates \
curl \
rsync \
supervisor \
&& curl -sLO http://resin-packages.s3.amazonaws.com/docker-compose/${DOCKER_COMPOSE_VERSION}/docker-compose-linux-alpine-i386-${DOCKER_COMPOSE_VERSION}.tar.gz \
&& echo "$DOCKER_COMPOSE_SHA256 docker-compose-linux-alpine-i386-${DOCKER_COMPOSE_VERSION}.tar.gz" > docker-compose-linux-alpine-i386-${DOCKER_COMPOSE_VERSION}.tar.gz.sha256 \
&& sha256sum -c docker-compose-linux-alpine-i386-${DOCKER_COMPOSE_VERSION}.tar.gz.sha256 \
&& tar xzf docker-compose-linux-alpine-i386-${DOCKER_COMPOSE_VERSION}.tar.gz \
&& mv docker-compose-linux-alpine-i386-${DOCKER_COMPOSE_VERSION}/docker-compose-linux-alpine-i386 /usr/bin/docker-compose \
&& rm -rf docker-compose-linux-alpine-i386-${DOCKER_COMPOSE_VERSION}* \
&& apk del curl \
&& rm -rf /var/cache/apk/*
# Copy supervisord configuration files

View File

@ -1,11 +1,22 @@
FROM resin/armhf-alpine-node:0.10.44-slim
ENV DOCKER_COMPOSE_VERSION 1.7.1
ENV DOCKER_COMPOSE_SHA256 3e5d0a36f06d9f7a93eb20c1dee67da623b07a322168538ea80d65c8581f5567
# Supervisor apt dependencies
RUN apk add --update \
btrfs-progs \
ca-certificates \
curl \
rsync \
supervisor \
&& curl -sLO http://resin-packages.s3.amazonaws.com/docker-compose/${DOCKER_COMPOSE_VERSION}/docker-compose-linux-alpine-armhf-${DOCKER_COMPOSE_VERSION}.tar.gz \
&& echo "$DOCKER_COMPOSE_SHA256 docker-compose-linux-alpine-armhf-${DOCKER_COMPOSE_VERSION}.tar.gz" > docker-compose-linux-alpine-armhf-${DOCKER_COMPOSE_VERSION}.tar.gz.sha256 \
&& sha256sum -c docker-compose-linux-alpine-armhf-${DOCKER_COMPOSE_VERSION}.tar.gz.sha256 \
&& tar xzf docker-compose-linux-alpine-armhf-${DOCKER_COMPOSE_VERSION}.tar.gz \
&& mv docker-compose-linux-alpine-armhf-${DOCKER_COMPOSE_VERSION}/docker-compose-linux-alpine-armhf /usr/bin/docker-compose \
&& rm -rf docker-compose-linux-alpine-armhf-${DOCKER_COMPOSE_VERSION}* \
&& apk del curl \
&& rm -rf /var/cache/apk/*
# Copy supervisord configuration files

View File

@ -2,14 +2,25 @@ FROM resin/amd64-node:0.10.40-slim
COPY 01_nodoc /etc/dpkg/dpkg.cfg.d/
ENV DOCKER_COMPOSE_VERSION 1.7.1
ENV DOCKER_COMPOSE_SHA256 37df85ee18bf0e2a8d71cbfb8198b1c06cc388f19118be7bdfc4d6db112af834
# Supervisor apt dependencies
RUN apt-get -q update \
&& apt-get install -qqy \
btrfs-tools \
ca-certificates \
curl \
rsync \
supervisor \
--no-install-recommends \
&& curl -sLO http://resin-packages.s3.amazonaws.com/docker-compose/${DOCKER_COMPOSE_VERSION}/docker-compose-linux-amd64-${DOCKER_COMPOSE_VERSION}.tar.gz \
&& echo $DOCKER_COMPOSE_SHA256 docker-compose-linux-amd64-${DOCKER_COMPOSE_VERSION}.tar.gz > docker-compose-linux-amd64-${DOCKER_COMPOSE_VERSION}.tar.gz.sha256 \
&& sha256sum -c docker-compose-linux-amd64-${DOCKER_COMPOSE_VERSION}.tar.gz.sha256 \
&& tar xzf docker-compose-linux-amd64-${DOCKER_COMPOSE_VERSION}.tar.gz \
&& mv docker-compose-linux-amd64-${DOCKER_COMPOSE_VERSION}/docker-compose-linux-amd64 /usr/bin/docker-compose \
&& rm -rf docker-compose-linux-amd64-${DOCKER_COMPOSE_VERSION}* \
&& apt-get purge -qqy curl \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/

View File

@ -2,14 +2,25 @@ FROM resin/armel-node:0.10.40-slim
COPY 01_nodoc /etc/dpkg/dpkg.cfg.d/
ENV DOCKER_COMPOSE_VERSION 1.7.1
ENV DOCKER_COMPOSE_SHA256 a1025fed97536e2698798ea277a014ec5e1eae816a8cf3155ecbe9679e3e7bac
# Supervisor apt dependencies
RUN apt-get -q update \
&& apt-get install -qqy \
btrfs-tools \
ca-certificates \
curl \
rsync \
supervisor \
--no-install-recommends \
&& curl -sLO http://resin-packages.s3.amazonaws.com/docker-compose/${DOCKER_COMPOSE_VERSION}/docker-compose-linux-armel-${DOCKER_COMPOSE_VERSION}.tar.gz \
&& echo $DOCKER_COMPOSE_SHA256 docker-compose-linux-armel-${DOCKER_COMPOSE_VERSION}.tar.gz > docker-compose-linux-armel-${DOCKER_COMPOSE_VERSION}.tar.gz.sha256 \
&& sha256sum -c docker-compose-linux-armel-${DOCKER_COMPOSE_VERSION}.tar.gz.sha256 \
&& tar xzf docker-compose-linux-armel-${DOCKER_COMPOSE_VERSION}.tar.gz \
&& mv docker-compose-linux-armel-${DOCKER_COMPOSE_VERSION}/docker-compose-linux-armel /usr/bin/docker-compose \
&& rm -rf docker-compose-linux-armel-${DOCKER_COMPOSE_VERSION}* \
&& apt-get purge -qqy curl \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/

View File

@ -2,14 +2,25 @@ FROM resin/armv7hf-node:0.10.40-slim
COPY 01_nodoc /etc/dpkg/dpkg.cfg.d/
ENV DOCKER_COMPOSE_VERSION 1.7.1
ENV DOCKER_COMPOSE_SHA256 3f0b8c69c66a2daa5fbb0c127cb76ca95d7125827a9c43dd3c36f9bc2ed6e0e5
# Supervisor apt dependencies
RUN apt-get -q update \
&& apt-get install -qqy \
btrfs-tools \
ca-certificates \
curl \
rsync \
supervisor \
--no-install-recommends \
&& curl -sLO http://resin-packages.s3.amazonaws.com/docker-compose/${DOCKER_COMPOSE_VERSION}/docker-compose-linux-armhf-${DOCKER_COMPOSE_VERSION}.tar.gz \
&& echo $DOCKER_COMPOSE_SHA256 docker-compose-linux-armhf-${DOCKER_COMPOSE_VERSION}.tar.gz > docker-compose-linux-armhf-${DOCKER_COMPOSE_VERSION}.tar.gz.sha256 \
&& sha256sum -c docker-compose-linux-armhf-${DOCKER_COMPOSE_VERSION}.tar.gz.sha256 \
&& tar xzf docker-compose-linux-armhf-${DOCKER_COMPOSE_VERSION}.tar.gz \
&& mv docker-compose-linux-armhf-${DOCKER_COMPOSE_VERSION}/docker-compose-linux-armhf /usr/bin/docker-compose \
&& rm -rf docker-compose-linux-armhf-${DOCKER_COMPOSE_VERSION}* \
&& apt-get purge -qqy curl \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/

View File

@ -2,14 +2,25 @@ FROM resin/i386-node:0.10.40-slim
COPY 01_nodoc /etc/dpkg/dpkg.cfg.d/
ENV DOCKER_COMPOSE_VERSION 1.7.1
ENV DOCKER_COMPOSE_SHA256 b926fd9a2a9d89358f1353867706f94558a62caaf3aa72bf10bcbbe31e1a44f0
# Supervisor apt dependencies
RUN apt-get -q update \
&& apt-get install -qqy \
btrfs-tools \
ca-certificates \
curl \
rsync \
supervisor \
--no-install-recommends \
&& curl -sLO http://resin-packages.s3.amazonaws.com/docker-compose/${DOCKER_COMPOSE_VERSION}/docker-compose-linux-i386-${DOCKER_COMPOSE_VERSION}.tar.gz \
&& echo $DOCKER_COMPOSE_SHA256 docker-compose-linux-i386-${DOCKER_COMPOSE_VERSION}.tar.gz > docker-compose-linux-i386-${DOCKER_COMPOSE_VERSION}.tar.gz.sha256 \
&& sha256sum -c docker-compose-linux-i386-${DOCKER_COMPOSE_VERSION}.tar.gz.sha256 \
&& tar xzf docker-compose-linux-i386-${DOCKER_COMPOSE_VERSION}.tar.gz \
&& mv docker-compose-linux-i386-${DOCKER_COMPOSE_VERSION}/docker-compose-linux-i386 /usr/bin/docker-compose \
&& rm -rf docker-compose-linux-i386-${DOCKER_COMPOSE_VERSION}* \
&& apt-get purge -qqy curl \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/

View File

@ -2,14 +2,25 @@ FROM resin/rpi-node:0.10.40-slim
COPY 01_nodoc /etc/dpkg/dpkg.cfg.d/
ENV DOCKER_COMPOSE_VERSION 1.7.1
ENV DOCKER_COMPOSE_SHA256 3f0b8c69c66a2daa5fbb0c127cb76ca95d7125827a9c43dd3c36f9bc2ed6e0e5
# Supervisor apt dependencies
RUN apt-get -q update \
&& apt-get install -qqy \
btrfs-tools \
ca-certificates \
curl \
rsync \
supervisor \
--no-install-recommends \
&& curl -sLO http://resin-packages.s3.amazonaws.com/docker-compose/${DOCKER_COMPOSE_VERSION}/docker-compose-linux-armhf-${DOCKER_COMPOSE_VERSION}.tar.gz \
&& echo $DOCKER_COMPOSE_SHA256 docker-compose-linux-armhf-${DOCKER_COMPOSE_VERSION}.tar.gz > docker-compose-linux-armhf-${DOCKER_COMPOSE_VERSION}.tar.gz.sha256 \
&& sha256sum -c docker-compose-linux-armhf-${DOCKER_COMPOSE_VERSION}.tar.gz.sha256 \
&& tar xzf docker-compose-linux-armhf-${DOCKER_COMPOSE_VERSION}.tar.gz \
&& mv docker-compose-linux-armhf-${DOCKER_COMPOSE_VERSION}/docker-compose-linux-armhf /usr/bin/docker-compose \
&& rm -rf docker-compose-linux-armhf-${DOCKER_COMPOSE_VERSION}* \
&& apt-get purge -qqy curl \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/

View File

@ -30,7 +30,8 @@
"resin-register-device": "^2.0.0",
"rwlock": "^5.0.0",
"sqlite3": "3.0.9",
"typed-error": "~0.1.0"
"typed-error": "~0.1.0",
"yamljs": "^0.2.7"
},
"engines": {
"node": "0.10.22"

View File

@ -1,6 +1,5 @@
Promise = require 'bluebird'
utils = require './utils'
knex = require './db'
express = require 'express'
bodyParser = require 'body-parser'
bufferEq = require 'buffer-equal-constant-time'
@ -9,6 +8,7 @@ config = require './config'
device = require './device'
dockerUtils = require './docker-utils'
_ = require 'lodash'
compose = require './compose'
module.exports = (application) ->
api = express()
@ -57,10 +57,8 @@ module.exports = (application) ->
if !appId?
return res.status(400).send('Missing app id')
Promise.using application.lockUpdates(appId, true), ->
knex('app').select().where({ appId })
.then ([ app ]) ->
if !app?
throw new Error('App not found')
utils.getKnexApp(appId)
.then (app) ->
application.kill(app)
.then ->
new Promise (resolve, reject) ->
@ -70,6 +68,8 @@ module.exports = (application) ->
.pipe(res)
.finally ->
application.start(app)
.catch utils.AppNotFoundError, (e) ->
return res.status(400).send(e.message)
.catch (err) ->
res.status(503).send(err?.message or err or 'Unknown error')
@ -88,15 +88,15 @@ module.exports = (application) ->
if !appId?
return res.status(400).send('Missing app id')
Promise.using application.lockUpdates(appId, force), ->
knex('app').select().where({ appId })
.then ([ app ]) ->
if !app?
throw new Error('App not found')
utils.getKnexApp(appId)
.then (app) ->
application.kill(app)
.then ->
application.start(app)
.then ->
res.status(200).send('OK')
.catch utils.AppNotFoundError, (e) ->
return res.status(400).send(e.message)
.catch (err) ->
res.status(503).send(err?.message or err or 'Unknown error')
@ -107,13 +107,13 @@ module.exports = (application) ->
if !appId?
return res.status(400).send('Missing app id')
Promise.using application.lockUpdates(appId, force), ->
knex('app').select().where({ appId })
.then ([ app ]) ->
if !app?
throw new Error('App not found')
utils.getKnexApp(appId)
.tap (app) ->
application.kill(app, true, false)
.then ->
res.json(_.pick(app, 'containerId'))
.then (app) ->
res.json(_.pick(app, 'containerId'))
.catch utils.AppNotFoundError, (e) ->
return res.status(400).send(e.message)
.catch (err) ->
res.status(503).send(err?.message or err or 'Unknown error')
@ -123,13 +123,13 @@ module.exports = (application) ->
if !appId?
return res.status(400).send('Missing app id')
Promise.using application.lockUpdates(appId), ->
knex('app').select().where({ appId })
.then ([ app ]) ->
if !app?
throw new Error('App not found')
utils.getKnexApp(appId)
.tap (app) ->
application.start(app)
.then ->
res.json(_.pick(app, 'containerId'))
.then (app) ->
res.json(_.pick(app, 'containerId'))
.catch utils.AppNotFoundError, (e) ->
return res.status(400).send(e.message)
.catch (err) ->
res.status(503).send(err?.message or err or 'Unknown error')
@ -140,14 +140,14 @@ module.exports = (application) ->
return res.status(400).send('Missing app id')
Promise.using application.lockUpdates(appId, true), ->
columns = [ 'appId', 'containerId', 'commit', 'imageId', 'env' ]
knex('app').select(columns).where({ appId })
.then ([ app ]) ->
if !app?
throw new Error('App not found')
utils.getKnexApp(appId, columns)
.then (app) ->
# Don't return keys on the endpoint
app.env = _.omit(JSON.parse(app.env), config.privateAppEnvVars)
# Don't return data that will be of no use to the user
res.json(app)
.catch utils.AppNotFoundError, (e) ->
return res.status(400).send(e.message)
.catch (err) ->
res.status(503).send(err?.message or err or 'Unknown error')
@ -175,6 +175,42 @@ module.exports = (application) ->
unparsedRouter.delete '/v1/containers/:id', dockerUtils.deleteContainer
unparsedRouter.get '/v1/containers', dockerUtils.listContainers
unparsedRouter.post '/v1/apps/:appId/compose/up', (req, res) ->
appId = req.params.appId
onStatus = (status) ->
status = JSON.stringify(status) if _.isObject(status)
res.write(status)
utils.getKnexApp(appId)
.then (app) ->
res.status(200)
compose.up(application.composePath(appId), onStatus)
.catch (err) ->
console.log('Error on compose up:', err, err.stack)
.finally ->
res.end()
.catch utils.AppNotFoundError, (e) ->
return res.status(400).send(e.message)
.catch (err) ->
res.status(503).send(err?.message or err or 'Unknown error')
unparsedRouter.post '/v1/apps/:appId/compose/down', (req, res) ->
appId = req.params.appId
onStatus = (status) ->
status = JSON.stringify(status) if _.isObject(status)
res.write(status)
utils.getKnexApp(appId)
.then (app) ->
res.status(200)
compose.down(application.composePath(appId), onStatus)
.catch (err) ->
console.log('Error on compose down:', err, err.stack)
.finally ->
res.end()
.catch utils.AppNotFoundError, (e) ->
return res.status(400).send(e.message)
.catch (err) ->
res.status(503).send(err?.message or err or 'Unknown error')
api.use(unparsedRouter)
api.use(parsedRouter)

View File

@ -311,6 +311,9 @@ killmePath = (app) ->
appId = app.appId ? app
return "/mnt/root#{config.dataPath}/#{appId}/resin-kill-me"
application.composePath = (appId) ->
return "/mnt/root#{config.dataPath}/#{appId}/docker-compose.yml"
# At boot, all apps should be unlocked *before* start to prevent a deadlock
application.unlockAndStart = unlockAndStart = (app) ->
lockFile.unlockAsync(lockPath(app))
@ -389,13 +392,6 @@ wrapAsError = (err) ->
return err if _.isError(err)
return new Error(err.message ? err)
select = (appId) ->
knex('app').select().where({ appId })
.then ([ app ]) ->
if !app?
throw new Error('App not found')
return app
# Wait for app to signal it's ready to die, or timeout to complete.
# timeout defaults to 1 minute.
waitToKill = (app, timeout) ->
@ -432,7 +428,7 @@ updateStrategies =
.then ->
Promise.using lockUpdates(localApp, force), ->
logSystemEvent(logTypes.updateApp, app) if localApp.imageId == app.imageId
select(localApp.appId)
utils.getKnexApp(localApp.appId)
.then(kill)
.then ->
start(app)
@ -442,7 +438,7 @@ updateStrategies =
'kill-then-download': ({ localApp, app, needsDownload, force }) ->
Promise.using lockUpdates(localApp, force), ->
logSystemEvent(logTypes.updateApp, app) if localApp.imageId == app.imageId
select(localApp.appId)
utils.getKnexApp(localApp.appId)
.then(kill)
.then ->
fetch(app) if needsDownload
@ -453,7 +449,7 @@ updateStrategies =
throw err
'hand-over': ({ localApp, app, needsDownload, force, timeout }) ->
Promise.using lockUpdates(localApp, force), ->
select(localApp.appId)
utils.getKnexApp(localApp.appId)
.then (localApp) ->
Promise.try ->
fetch(app) if needsDownload
@ -574,10 +570,8 @@ application.update = update = (force) ->
# If an env var shouldn't cause a restart but requires an action, we should still
# save the new env to the DB
if !_.includes(toBeUpdated, appId) and !_.includes(toBeInstalled, appId)
knex('app').select().where({ appId })
.then ([ app ]) ->
if !app?
throw new Error('App not found')
utils.getKnexApp(appId)
.then (app) ->
app.env = JSON.stringify(remoteAppEnvs[appId])
knex('app').update(app).where({ appId })
.then (needsReboot) ->
@ -592,7 +586,7 @@ application.update = update = (force) ->
Promise.using lockUpdates(localApps[appId], force), ->
# We get the app from the DB again in case someone restarted it
# (which would have changed its containerId)
select(appId)
utils.getKnexApp(appId)
.then(kill)
.then ->
knex('app').where('appId', appId).delete()

54
src/compose.coffee Normal file
View File

@ -0,0 +1,54 @@
Promise = require 'bluebird'
YAML = require 'yamljs'
_ = require 'lodash'
dockerUtils = require './docker-utils'
{ docker } = dockerUtils
fs = Promise.promisifyAll(require('fs'))
spawn = require('child_process').spawn
runComposeCommand = (composeArgs, path, onStatus) ->
onStatus ?= console.log.bind(console)
reportStatus = (status) ->
try onStatus(status)
new Promise (resolve, reject) ->
child = spawn('docker-compose', ['-f', path].concat(composeArgs), stdio: 'pipe')
.on 'error', reject
.on 'exit', (code) ->
return reject(new Error("docker-compose exited with code #{code}")) if code isnt 0
resolve()
child.stdout.on 'data', (data) ->
reportStatus(status: '' + data)
child.stderr.on 'data', (data) ->
reportStatus(status: '' + data)
.catch (err) ->
msg = err?.message or err
reportStatus(error: msg)
throw err
# Runs docker-compose up using the compose YAML at "path".
# Reports status and errors in JSON to the onStatus function.
exports.up = (path, onStatus) ->
onStatus ?= console.log.bind(console)
reportStatus = (status) ->
try onStatus(status)
fs.readFileAsync(path)
.then (data) ->
YAML.parse(data.toString())
.then (composeSpec) ->
if composeSpec.version? && composeSpec.version == '2'
services = composeSpec.services
else
services = composeSpec
throw new Error('No services found') if !_.isObject(services)
servicesArray = _.pairs(services)
Promise.each servicesArray, ([ serviceName, service ]) ->
throw new Error("Service #{serviceName} has no image specified.") if !service.image
docker.getImage(service.image).inspectAsync()
.catch ->
dockerUtils.pullAndProtectImage(service.image, reportStatus)
.then ->
runComposeCommand(['up', '-d'], path, onStatus)
# Runs docker-compose down using the compose YAML at "path".
# Reports status and errors in JSON to the onStatus function.
exports.down = _.partial(runComposeCommand, 'down')

View File

@ -200,6 +200,13 @@ do ->
.catch (err) ->
res.status(500).send(err?.message or err or 'Unknown error')
exports.pullAndProtectImage = (image, onProgress) ->
repoTag = buildRepoTag(image)
Promise.using writeLockImages(), ->
knex('image').insert({ repoTag })
.then ->
dockerProgress.pull(repoTag, onProgress)
exports.loadImage = (req, res) ->
Promise.using writeLockImages(), ->
docker.listImagesAsync()

View File

@ -10,6 +10,7 @@ url = require 'url'
randomHexString = require './lib/random-hex-string'
request = Promise.promisifyAll require 'request'
logger = require './lib/logger'
TypedError = require 'typed-error'
# Parses package.json and returns resin-supervisor's version
version = require('../package.json').version
@ -180,3 +181,13 @@ exports.vpnControl = (val) ->
console.log('VPN enabled: ' + enable)
else
console.log('Error: ' + body + ' response:' + response.statusCode)
exports.AppNotFoundError = class AppNotFoundError extends TypedError
exports.getKnexApp = (appId, columns) ->
knex('app').select(columns).where({ appId })
.then ([ app ]) ->
if !app?
throw new AppNotFoundError('App not found')
return app