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. # v1 endpoins only work for single-container apps as they assume the app has a single service.
class ApplicationManagerRouter class ApplicationManagerRouter
constructor: (@applications) -> constructor: (@applications) ->
{ @proxyvisor, @eventTracker, @deviceState, @_lockingIfNecessary } = @applications { @proxyvisor, @eventTracker, @deviceState, @_lockingIfNecessary, @logger } = @applications
@router = express.Router() @router = express.Router()
@router.use(bodyParser.urlencoded(extended: true)) @router.use(bodyParser.urlencoded(extended: true))
@router.use(bodyParser.json()) @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) => @router.post '/v1/restart', (req, res) =>
appId = checkInt(req.body.appId) appId = checkInt(req.body.appId)
force = checkTruthy(req.body.force) force = checkTruthy(req.body.force)
@eventTracker.track('Restart container (v1)', { appId }) @eventTracker.track('Restart container (v1)', { appId })
if !appId? if !appId?
return res.status(400).send('Missing app id') return res.status(400).send('Missing app id')
@applications.getCurrentApp(appId) doRestart(appId, force)
.then (app) => .then ->
service = app?.services?[0] res.status(200).send('OK')
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')
.catch (err) -> .catch (err) ->
res.status(503).send(err?.message or err or 'Unknown error') res.status(503).send(err?.message or err or 'Unknown error')
@ -135,7 +161,7 @@ class ApplicationManagerRouter
.catch (err) -> .catch (err) ->
res.status(503).send(err?.message or err or 'Unknown error') 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) appId = checkInt(req.body.appId)
force = checkTruthy(req.body.force) force = checkTruthy(req.body.force)
if !appId? if !appId?
@ -143,44 +169,16 @@ class ApplicationManagerRouter
If you've recently moved this device from another app, If you've recently moved this device from another app,
please push an app and wait for it to be installed first." please push an app and wait for it to be installed first."
return res.status(400).send(errMsg) return res.status(400).send(errMsg)
@_lockingIfNecessary appId, { force }, => doPurge(appId, force)
@applications.getCurrentApp(appId) .then ->
.then (app) => res.status(200).json(Data: 'OK', Error: '')
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: '')
.catch (err) -> .catch (err) ->
res.status(503).send(err?.message or err or 'Unknown error') 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 { force } = req.body
{ appId } = req.params { appId } = req.params
@_lockingIfNecessary appId, { force }, => doPurge(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 })
.then -> .then ->
res.status(200).send('OK') res.status(200).send('OK')
.catch (err) -> .catch (err) ->
@ -207,20 +205,10 @@ class ApplicationManagerRouter
.catch (err) -> .catch (err) ->
res.status(503).send(err?.message or err or 'Unknown error') 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 { force } = req.body
{ appId } = req.params { appId } = req.params
@_lockingIfNecessary appId, { force }, => doRestart(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 })
.then -> .then ->
res.status(200).send('OK') res.status(200).send('OK')
.catch (err) -> .catch (err) ->
@ -251,26 +239,6 @@ module.exports = class ApplicationManager extends EventEmitter
@images.removeByDockerId(step.current.image) @images.removeByDockerId(step.current.image)
updateMetadata: (step) => updateMetadata: (step) =>
@services.updateMetadata(step.current, step.target) @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 } = {}) => restart: (step, { force = false, skipLock = false } = {}) =>
@_lockingIfNecessary step.current.appId, { force, skipLock: skipLock or step.options?.skipLock }, => @_lockingIfNecessary step.current.appId, { force, skipLock: skipLock or step.options?.skipLock }, =>
Promise.try => Promise.try =>