Add default binds to containers created with API, add /v1/containers/update endpoint, and add a /data bind with an internal id

This commit is contained in:
Pablo Carranza Velez 2016-07-20 20:01:49 +00:00
parent d652e13005
commit b97fe634d5
5 changed files with 98 additions and 43 deletions

View File

@ -170,6 +170,7 @@ module.exports = (application) ->
unparsedRouter.delete '/v1/images/*', dockerUtils.deleteImage
unparsedRouter.get '/v1/images', dockerUtils.listImages
parsedRouter.post '/v1/containers/create', dockerUtils.createContainer
parsedRouter.post '/v1/containers/update', dockerUtils.updateContainer
parsedRouter.post '/v1/containers/:id/start', dockerUtils.startContainer
unparsedRouter.post '/v1/containers/:id/stop', dockerUtils.stopContainer
unparsedRouter.delete '/v1/containers/:id', dockerUtils.deleteContainer

View File

@ -176,21 +176,8 @@ shouldMountKmod = (image) ->
return false
application.start = start = (app) ->
volumes =
'/data': {}
'/lib/modules': {}
'/lib/firmware': {}
'/host/var/lib/connman': {}
'/host/run/dbus': {}
binds = [
config.dataPath + '/' + app.appId + ':/data'
'/lib/modules:/lib/modules'
'/lib/firmware:/lib/firmware'
'/run/dbus:/host_run/dbus'
'/run/dbus:/host/run/dbus'
'/etc/resolv.conf:/etc/resolv.conf:rw'
'/var/lib/connman:/host/var/lib/connman'
]
volumes = utils.defaultVolumes
binds = utils.defaultBinds(app.appId)
Promise.try ->
# Parse the env vars before trying to access them, that's because they have to be stringified for knex..
JSON.parse(app.env)

View File

@ -46,6 +46,12 @@ knex.init = Promise.all([
knex.schema.createTable 'image', (t) ->
t.increments('id').primary()
t.string('repoTag')
knex.schema.hasTable('container')
.then (exists) ->
if not exists
knex.schema.createTable 'container', (t) ->
t.increments('id').primary()
t.string('containerId')
])

View File

@ -244,57 +244,81 @@ do ->
res.status(500).send(err?.message or err or 'Unknown error')
docker.modem.dialAsync = Promise.promisify(docker.modem.dial)
exports.createContainer = (req, res) ->
createContainer = (options, internalId) ->
Promise.using writeLockImages(), ->
knex('image').select().where('repoTag', req.body.Image)
knex('image').select().where('repoTag', options.Image)
.then (images) ->
throw new Error('Only images created via the Supervisor can be used for creating containers.') if images.length == 0
optsf =
path: '/containers/create?'
method: 'POST'
options: req.body
statusCodes:
200: true
201: true
404: 'no such container'
406: 'impossible to attach'
500: 'server error'
docker.modem.dialAsync(optsf)
.then (data) ->
res.json(data)
.catch (err) ->
res.status(500).send(err?.message or err or 'Unknown error')
exports.startContainer = (req, res) ->
docker.getContainer(req.params.id).startAsync(req.body)
knex.transaction (trx) ->
Promise.try ->
return internalId if internalId?
trx.insert({}, 'id').into('container')
.then ([ id ]) ->
return id
.then (id) ->
options.HostConfig ?= {}
options.Volumes ?= {}
_.assign(options.Volumes, utils.defaultVolumes)
options.HostConfig.Binds = utils.defaultBinds("containers/#{id}")
optsf =
path: '/containers/create?'
method: 'POST'
options: options
statusCodes:
200: true
201: true
404: 'no such container'
406: 'impossible to attach'
500: 'server error'
docker.modem.dialAsync(optsf)
.then (data) ->
containerId = data.Id
trx('container').update({ containerId }).where({ id })
.then ->
return data
exports.createContainer = (req, res) ->
createContainer(req.body)
.then (data) ->
res.json(data)
.catch (err) ->
res.status(500).send(err?.message or err or 'Unknown error')
exports.stopContainer = (req, res) ->
container = docker.getContainer(req.params.id)
startContainer = (containerId, options) ->
docker.getContainer(containerId).startAsync(options)
exports.startContainer = (req, res) ->
startContainer(req.params.id, req.body)
.then (data) ->
res.json(data)
.catch (err) ->
res.status(500).send(err?.message or err or 'Unknown error')
stopContainer = (containerId, options) ->
container = docker.getContainer(containerId)
knex('app').select()
.then (apps) ->
throw new Error('Cannot stop an app container') if _.any(apps, containerId: req.params.id)
throw new Error('Cannot stop an app container') if _.any(apps, { containerId })
container.inspectAsync()
.then (cont) ->
throw new Error('Cannot stop supervisor container') if cont.Name == '/resin_supervisor' or _.any(cont.Names, (n) -> n == '/resin_supervisor')
container.stopAsync(sanitizeQuery(req.query))
container.stopAsync(options)
exports.stopContainer = (req, res) ->
stopContainer(req.params.id, sanitizeQuery(req.query))
.then (data) ->
res.json(data)
.catch (err) ->
res.status(500).send(err?.message or err or 'Unknown error')
exports.deleteContainer = (req, res) ->
container = docker.getContainer(req.params.id)
deleteContainer = (containerId, options) ->
container = docker.getContainer(containerId)
knex('app').select()
.then (apps) ->
throw new Error('Cannot remove an app container') if _.any(apps, containerId: req.params.id)
throw new Error('Cannot remove an app container') if _.any(apps, { containerId })
container.inspectAsync()
.then (cont) ->
throw new Error('Cannot remove supervisor container') if cont.Name == '/resin_supervisor' or _.any(cont.Names, (n) -> n == '/resin_supervisor')
container.removeAsync(sanitizeQuery(req.query))
container.removeAsync(options)
exports.deleteContainer = (req, res) ->
deleteContainer(req.params.id, sanitizeQuery(req.query))
.then (data) ->
res.json(data)
.catch (err) ->
@ -306,3 +330,21 @@ do ->
res.json(containers)
.catch (err) ->
res.status(500).send(err?.message or err or 'Unknown error')
exports.updateContainer = (req, res) ->
{ oldContainerId } = req.query
return res.status(400).send('Missing oldContainerId') if !oldContainerId?
knex('container').select().where({ containerId: oldContainerId })
.then ([ oldContainer ]) ->
return res.status(404).send('Old container not found') if !oldContainer?
stopContainer(oldContainerId, t: 10)
.then ->
deleteContainer(oldContainerId, v: true)
.then ->
createContainer(req.body, oldContainer.id)
.then ->
startContainer(data.Id)
.then (data) ->
res.json(data)
.catch (err) ->
res.status(500).send(err?.message or err or 'Unknown error')

View File

@ -204,3 +204,22 @@ exports.getOSVersion = (path) ->
.catch (err) ->
console.log('Could not get OS Version: ', err, err.stack)
return undefined
exports.defaultVolumes = {
'/data': {}
'/lib/modules': {}
'/lib/firmware': {}
'/host/var/lib/connman': {}
'/host/run/dbus': {}
}
exports.defaultBinds = (dataPath) ->
return [
config.dataPath + '/' + dataPath + ':/data'
'/lib/modules:/lib/modules'
'/lib/firmware:/lib/firmware'
'/run/dbus:/host_run/dbus'
'/run/dbus:/host/run/dbus'
'/etc/resolv.conf:/etc/resolv.conf:rw'
'/var/lib/connman:/host/var/lib/connman'
]