UNPKG

@flowfuse/flowfuse

Version:

An open source low-code development platform

113 lines (107 loc) 5.31 kB
module.exports = async function (app) { app.addHook('preHandler', app.verifySession) app.addHook('preHandler', async (request, reply) => { if (!app.config.features.enabled('ha')) { reply.code(404).send({ code: 'not_found', error: 'Not Found' }) } }) app.addHook('preHandler', async (request, reply) => { if (request.params.projectId !== undefined) { if (request.params.projectId) { try { request.project = await app.db.models.Project.byId(request.params.projectId) if (!request.project) { reply.code(404).send({ code: 'not_found', error: 'Not Found' }) return } const teamType = await request.project.Team.getTeamType() if (!teamType.getFeatureProperty('ha', true)) { reply.code(404).send({ code: 'not_found', error: 'Not Found' }) return // eslint-disable-line no-useless-return } if (request.session.User) { request.teamMembership = await request.session.User.getTeamMembership(request.project.Team.id) if (!request.teamMembership && !request.session.User.admin) { reply.code(404).send({ code: 'not_found', error: 'Not Found' }) return // eslint-disable-line no-useless-return } } else if (request.session.ownerId !== request.params.projectId) { // AccessToken being used - but not owned by this project reply.code(404).send({ code: 'not_found', error: 'Not Found' }) return // eslint-disable-line no-useless-return } } catch (err) { reply.code(404).send({ code: 'not_found', error: 'Not Found' }) } } else { reply.code(404).send({ code: 'not_found', error: 'Not Found' }) } } }) app.get('/', { preHandler: app.needsPermission('project:read') }, async (request, reply) => { reply.send(await request.project.getHASettings() || {}) }) app.put('/', { preHandler: app.needsPermission('project:edit') }, async (request, reply) => { // For 1.8, only support setting replica count to 2 if (request.body.replicas !== 2) { reply.code(409).send({ code: 'invalid_ha_configuration', error: 'Invalid HA configuration -only 2 replicas are allowed' }) return } const existingHA = await request.project.getHASettings() || {} if (existingHA.replicas !== request.body.replicas) { // This is a change in replica count. await request.project.updateHASettings({ replicas: request.body.replicas }) await applyUpdatedInstanceSettings(reply, request.project, request.session.User) } else { reply.send(await request.project.getHASettings() || {}) } }) app.delete('/', { preHandler: app.needsPermission('project:edit') }, async (request, reply) => { const existingHA = await request.project.getHASettings() || {} if (existingHA.replicas) { // This instance already has ha configured - clear the setting // and apply await request.project.updateHASettings(undefined) await applyUpdatedInstanceSettings(reply, request.project, request.session.User) } else { reply.send({}) } }) async function applyUpdatedInstanceSettings (reply, project, user) { if (project.state !== 'suspended') { // This code is copy/paste with slight changes from projects.js // We also have projectActions.js that does suspend logic. // TODO: refactor into a Model function to suspend a project app.db.controllers.Project.setInflightState(project, 'starting') // TODO: better inflight state needed reply.send(await project.getHASettings() || {}) const targetState = project.state app.log.info(`Stopping project ${project.id}`) await app.containers.stop(project, { skipBilling: true }) await app.auditLog.Project.project.suspended(user, null, project) app.log.info(`Restarting project ${project.id}`) project.state = targetState await project.save() await project.reload() const startResult = await app.containers.start(project) startResult.started.then(async () => { await app.auditLog.Project.project.started(user, null, project) app.db.controllers.Project.clearInflightState(project) return true }).catch(_ => { app.db.controllers.Project.clearInflightState(project) }) } else { // A suspended project doesn't need to do anything more // The settings will get applied when it is next resumed reply.send(await project.getHASettings() || {}) } } }