diff --git a/tgnms/fbcnms-projects/tgnms/app/features/planning/components/PlanEditor.js b/tgnms/fbcnms-projects/tgnms/app/features/planning/components/PlanEditor.js index 59dba6142..214ffc978 100644 --- a/tgnms/fbcnms-projects/tgnms/app/features/planning/components/PlanEditor.js +++ b/tgnms/fbcnms-projects/tgnms/app/features/planning/components/PlanEditor.js @@ -117,7 +117,13 @@ export default function PlanEditor({ startPlanTask.success(); } catch (err) { startPlanTask.error(); - startPlanTask.setMessage(err.message); + if (err.response?.data?.errors != null) { + startPlanTask.setMessage( + `Plan failed to launch: ${err.response.data.errors.join('\n')}`, + ); + } else { + startPlanTask.setMessage(err.message); + } } }, [onPlanLaunched, plan, startPlanTask]); @@ -200,6 +206,13 @@ export default function PlanEditor({ )} + {startPlanTask.isError && ( + + + {startPlanTask.message} + + + )} ); } diff --git a/tgnms/fbcnms-projects/tgnms/server/network_plan/__tests__/planning-test.js b/tgnms/fbcnms-projects/tgnms/server/network_plan/__tests__/planning-test.js index d7e88ee05..0c06c0f52 100644 --- a/tgnms/fbcnms-projects/tgnms/server/network_plan/__tests__/planning-test.js +++ b/tgnms/fbcnms-projects/tgnms/server/network_plan/__tests__/planning-test.js @@ -860,12 +860,6 @@ describe('POST plan/:id/launch', () => { NETWORK_PLAN_STATE.RUNNING, ); }); - test.todo( - 'if file upload fails, transitions the plan into the ERROR state', - ); - test.todo( - 'if anp api returns errors after local file upload success, transitions the plan into the ERROR state', - ); }); describe('with only FBID files', () => { test('creates and launches plan', async () => { @@ -921,9 +915,9 @@ describe('POST plan/:id/launch', () => { const {body: launchBody} = await request(setupApp()) .post(`/network_plan/plan/${plan.id}/launch`) .expect(500); - expect(launchBody.state).toBe(NETWORK_PLAN_STATE.ERROR); + expect(launchBody.state).toBe(NETWORK_PLAN_STATE.LAUNCH_ERROR); expect(nullthrows(await network_plan.findByPk(plan.id)).state).toBe( - NETWORK_PLAN_STATE.ERROR, + NETWORK_PLAN_STATE.LAUNCH_ERROR, ); }, ); @@ -1055,7 +1049,7 @@ describe('POST plan/:id/launch', () => { .post(`/network_plan/plan/${plan.id}/launch`) .expect(500); expect(nullthrows(await network_plan.findByPk(plan.id)).state).toBe( - NETWORK_PLAN_STATE.ERROR, + NETWORK_PLAN_STATE.LAUNCH_ERROR, ); }); }); diff --git a/tgnms/fbcnms-projects/tgnms/server/network_plan/planningService.js b/tgnms/fbcnms-projects/tgnms/server/network_plan/planningService.js index e4f3b98b1..9436831c4 100644 --- a/tgnms/fbcnms-projects/tgnms/server/network_plan/planningService.js +++ b/tgnms/fbcnms-projects/tgnms/server/network_plan/planningService.js @@ -338,7 +338,7 @@ export default class PlanningService { ); await this.waitForFileReadyState(anpFile); } catch (err) { - console.error(err); + throw err; } finally { if (fd != null) { fs.close(fd, err => { @@ -406,10 +406,15 @@ export default class PlanningService { state: NETWORK_PLAN_STATE.RUNNING, }; } catch (err) { + const errors = []; console.error(err); - planRow.state = NETWORK_PLAN_STATE.ERROR; + const apiMsg = err.response?.data?.error?.message; + if (apiMsg != null) { + errors.push(apiMsg); + } + planRow.state = NETWORK_PLAN_STATE.LAUNCH_ERROR; await planRow.save(); - return {state: planRow.state}; + return {state: planRow.state, message: err.message, errors}; } } @@ -565,12 +570,24 @@ export default class PlanningService { if (fbid == null) { throw new Error('Plan has not been launched yet'); } - const inputs = this.anpApi.getPlanInputFiles(fbid); + const inputs = await this.anpApi.getPlanInputFiles(fbid); return inputs; } // Fetch output files from ANP async getPlanOutputFiles(id: number) { + const fbid = await this.getPlanFBID(id); + const outputs = await this.anpApi.getPlanOutputFiles(fbid); + return outputs; + } + + async getPlanErrors(id: number): Promise<{error_message: string}> { + const fbid = await this.getPlanFBID(id); + const errors = await this.anpApi.getPlanErrors(fbid); + return errors; + } + + async getPlanFBID(id: number): Promise { const row = await network_plan.findByPk(id); if (row == null) { throw new Error(`Plan not found: ${id}`); @@ -579,8 +596,7 @@ export default class PlanningService { if (fbid == null) { throw new Error('Plan has not been launched yet'); } - const outputs = this.anpApi.getPlanOutputFiles(fbid); - return outputs; + return fbid; } async downloadFileStream(id: number) { @@ -843,23 +859,6 @@ export default class PlanningService { } } - async getPlanErrors({ - id, - }: { - id: number, - }): Promise> { - const planRow = await network_plan.findByPk(id); - if (planRow == null) { - throw new Error('Plan does not exist'); - } - const plan = planRow.toJSON(); - if (plan.fbid == null || plan.fbid.trim() === '') { - return []; - } - const response = await this.anpApi.getPlanErrors(plan.fbid); - return response; - } - /** * This is called by multer before a file is uploaded, return false or * throw an error to prevent the file being uploaded. diff --git a/tgnms/fbcnms-projects/tgnms/server/network_plan/routes.js b/tgnms/fbcnms-projects/tgnms/server/network_plan/routes.js index f8298c25f..64c5c8fc2 100644 --- a/tgnms/fbcnms-projects/tgnms/server/network_plan/routes.js +++ b/tgnms/fbcnms-projects/tgnms/server/network_plan/routes.js @@ -17,7 +17,7 @@ import { FACEBOOK_OAUTH_URL, } from '../config'; import {Api} from '../Api'; -import {NETWORK_PLAN_STATE} from '@fbcnms/tg-nms/shared/dto/NetworkPlan'; +import {ERROR_NETWORK_PLAN_STATES} from '@fbcnms/tg-nms/shared/dto/NetworkPlan'; import {createErrorHandler} from '../helpers/apiHelpers'; const multer = require('multer'); @@ -113,10 +113,7 @@ export default class NetworkPlanRoutes extends Api { return planningService .startLaunchPlan({id: parseInt(req.params.id)}) .then(result => { - if (result.state === NETWORK_PLAN_STATE.ERROR) { - if (result.message) { - this.logger.error(result.message); - } + if (ERROR_NETWORK_PLAN_STATES.has(result.state)) { return res.status(500).json(result); } return res.json(result); @@ -238,7 +235,7 @@ export default class NetworkPlanRoutes extends Api { router.get('/plan/:id/errors', (req, res) => { return planningService - .getPlanErrors({id: parseInt(req.params.id)}) + .getPlanErrors(parseInt(req.params.id)) .then(x => res.json(x)) .catch(err => res.status(500).send(err.message)); }); diff --git a/tgnms/fbcnms-projects/tgnms/shared/dto/NetworkPlan.js b/tgnms/fbcnms-projects/tgnms/shared/dto/NetworkPlan.js index fe77f8020..f8915e601 100644 --- a/tgnms/fbcnms-projects/tgnms/shared/dto/NetworkPlan.js +++ b/tgnms/fbcnms-projects/tgnms/shared/dto/NetworkPlan.js @@ -71,6 +71,11 @@ export const RUNNING_NETWORK_PLAN_STATES = new Set([ NETWORK_PLAN_STATE.RUNNING, ]); +export const ERROR_NETWORK_PLAN_STATES = new Set([ + NETWORK_PLAN_STATE.ERROR, + NETWORK_PLAN_STATE.LAUNCH_ERROR, +]); + export type NetworkPlanStateType = $Keys; export type PlanFolder = {|