Make v1 restart and purge work for multicontainer apps too

Signed-off-by: Pablo Carranza Velez <pablo@resin.io>
This commit is contained in:
Pablo Carranza Velez 2018-01-23 09:23:26 -08:00
parent 2b223f55fa
commit cba3a8e5fe

View File

@ -48,27 +48,53 @@ fetchAction = (service) ->
# v1 endpoins only work for single-container apps as they assume the app has a single service.
class ApplicationManagerRouter
constructor: (@applications) ->
{ @proxyvisor, @eventTracker, @deviceState, @_lockingIfNecessary } = @applications
{ @proxyvisor, @eventTracker, @deviceState, @_lockingIfNecessary, @logger } = @applications
@router = express.Router()
@router.use(bodyParser.urlencoded(extended: true))
@router.use(bodyParser.json())
doRestart = (appId, force) =>
@_lockingIfNecessary appId, { force }, =>
@deviceState.getCurrentForComparison()
.then (currentState) =>
app = currentState.local.apps[appId]
stoppedApp = _.cloneDeep(app)
stoppedApp.services = []
currentState.local.apps[appId] = stoppedApp
@deviceState.applyIntermediateTarget(currentState, { skipLock: true })
.then =>
currentState.local.apps[appId] = app
@deviceState.applyIntermediateTarget(currentState, { skipLock: true })
doPurge = (appId, force) =>
@logger.logSystemMessage("Purging data for app #{appId}", { appId }, 'Purge data')
@_lockingIfNecessary appId, { force }, =>
@deviceState.getCurrentForComparison()
.then (currentState) =>
app = currentState.local.apps[appId]
purgedApp = _.cloneDeep(app)
purgedApp.services = []
purgedApp.volumes = {}
currentState.local.apps[appId] = purgedApp
@deviceState.applyIntermediateTarget(currentState, { skipLock: true })
.then =>
currentState.local.apps[appId] = app
@deviceState.applyIntermediateTarget(currentState, { skipLock: true })
.tap =>
@logger.logSystemMessage('Purged data', { appId }, 'Purge data success')
.catch (err) =>
@logger.logSystemMessage("Error purging data: #{err}", { appId, error: err }, 'Purge data error')
throw err
@router.post '/v1/restart', (req, res) =>
appId = checkInt(req.body.appId)
force = checkTruthy(req.body.force)
@eventTracker.track('Restart container (v1)', { appId })
if !appId?
return res.status(400).send('Missing app id')
@applications.getCurrentApp(appId)
.then (app) =>
service = app?.services?[0]
if !service?
return res.status(400).send('App not found')
if app.services.length > 1
return res.status(400).send('v1 endpoints are only allowed on single-container apps')
@applications.executeStepAction(serviceAction('restart', service.serviceId, service, service), { force })
.then ->
res.status(200).send('OK')
doRestart(appId, force)
.then ->
res.status(200).send('OK')
.catch (err) ->
res.status(503).send(err?.message or err or 'Unknown error')
@ -135,7 +161,7 @@ class ApplicationManagerRouter
.catch (err) ->
res.status(503).send(err?.message or err or 'Unknown error')
@router.post '/v1/purge', (req, res) =>
@router.post '/v1/purge', (req, res) ->
appId = checkInt(req.body.appId)
force = checkTruthy(req.body.force)
if !appId?
@ -143,44 +169,16 @@ class ApplicationManagerRouter
If you've recently moved this device from another app,
please push an app and wait for it to be installed first."
return res.status(400).send(errMsg)
@_lockingIfNecessary appId, { force }, =>
@applications.getCurrentApp(appId)
.then (app) =>
service = app?.services?[0]
if !service?
return res.status(400).send('App not found')
if app.services.length > 1
return res.status(400).send('v1 endpoints are only allowed on single-container apps')
@applications.executeStepAction(serviceAction('kill', service.serviceId, service, null, skipLock: true), { force })
.then =>
@applications.executeStepAction({
action: 'purge'
appId: app.appId
options:
skipLock: true
}, { force })
.then =>
@applications.executeStepAction(serviceAction('start', service.serviceId, null, service, skipLock: true), { force })
.then ->
res.status(200).json(Data: 'OK', Error: '')
doPurge(appId, force)
.then ->
res.status(200).json(Data: 'OK', Error: '')
.catch (err) ->
res.status(503).send(err?.message or err or 'Unknown error')
@router.post '/v2/applications/:appId/purge', (req, res) =>
@router.post '/v2/applications/:appId/purge', (req, res) ->
{ force } = req.body
{ appId } = req.params
@_lockingIfNecessary appId, { force }, =>
@deviceState.getCurrentForComparison()
.then (currentState) =>
app = currentState.local.apps[appId]
purgedApp = _.cloneDeep(app)
purgedApp.services = []
purgedApp.volumes = {}
currentState.local.apps[appId] = purgedApp
@deviceState.applyIntermediateTarget(currentState, { skipLock: true })
.then =>
currentState.local.apps[appId] = app
@deviceState.applyIntermediateTarget(currentState, { skipLock: true })
doPurge(appId, force)
.then ->
res.status(200).send('OK')
.catch (err) ->
@ -207,20 +205,10 @@ class ApplicationManagerRouter
.catch (err) ->
res.status(503).send(err?.message or err or 'Unknown error')
@router.post '/v2/applications/:appId/restart', (req, res) =>
@router.post '/v2/applications/:appId/restart', (req, res) ->
{ force } = req.body
{ appId } = req.params
@_lockingIfNecessary appId, { force }, =>
@deviceState.getCurrentForComparison()
.then (currentState) =>
app = currentState.local.apps[appId]
stoppedApp = _.cloneDeep(app)
stoppedApp.services = []
currentState.local.apps[appId] = stoppedApp
@deviceState.applyIntermediateTarget(currentState, { skipLock: true })
.then =>
currentState.local.apps[appId] = app
@deviceState.applyIntermediateTarget(currentState, { skipLock: true })
doRestart(appId, force)
.then ->
res.status(200).send('OK')
.catch (err) ->
@ -251,26 +239,6 @@ module.exports = class ApplicationManager extends EventEmitter
@images.removeByDockerId(step.current.image)
updateMetadata: (step) =>
@services.updateMetadata(step.current, step.target)
purge: (step, { force = false, skipLock = false } = {}) =>
appId = step.appId
@logger.logSystemMessage("Purging data for app #{appId}", { appId }, 'Purge data')
@_lockingIfNecessary appId, { force, skipLock: skipLock or step.options?.skipLock }, =>
@getCurrentApp(appId)
.then (app) =>
if !_.isEmpty(app?.services)
throw new Error('Attempt to purge app with running services')
if _.isEmpty(app?.volumes)
@logger.logSystemMessage('No volumes to purge', { appId }, 'Purge data noop')
return
Promise.mapSeries _.toPairs(app.volumes ? {}), ([ name, config ]) =>
@volumes.remove({ name, appId })
.then =>
@volumes.create({ name, config, appId })
.then =>
@logger.logSystemMessage('Purged data', { appId }, 'Purge data success')
.catch (err) =>
@logger.logSystemMessage("Error purging data: #{err}", { appId, error: err }, 'Purge data error')
throw err
restart: (step, { force = false, skipLock = false } = {}) =>
@_lockingIfNecessary step.current.appId, { force, skipLock: skipLock or step.options?.skipLock }, =>
Promise.try =>