From 4c4ce1834b6bc21c8648c143c93aad96f164ada6 Mon Sep 17 00:00:00 2001 From: Tsu-ba-me Date: Sat, 11 Jun 2022 00:13:48 -0400 Subject: [PATCH] feat(striker-ui-api): add fetch server screenshot endpoint logic --- striker-ui-api/src/lib/accessModule.ts | 14 +- striker-ui-api/src/lib/consts/SERVER_PATHS.ts | 3 + striker-ui-api/src/lib/mkfifo.ts | 18 +++ .../buildGetRequestHandler.ts | 2 +- .../server/getServerDetail.ts | 139 ++++++++++++++++++ .../src/lib/request_handlers/server/index.ts | 1 + striker-ui-api/src/routes/file.ts | 2 +- striker-ui-api/src/routes/server.ts | 11 +- 8 files changed, 182 insertions(+), 8 deletions(-) create mode 100644 striker-ui-api/src/lib/mkfifo.ts create mode 100644 striker-ui-api/src/lib/request_handlers/server/getServerDetail.ts diff --git a/striker-ui-api/src/lib/accessModule.ts b/striker-ui-api/src/lib/accessModule.ts index 2c58ad9a..8998b1e7 100644 --- a/striker-ui-api/src/lib/accessModule.ts +++ b/striker-ui-api/src/lib/accessModule.ts @@ -5,8 +5,8 @@ import SERVER_PATHS from './consts/SERVER_PATHS'; const execAnvilAccessModule = ( args: string[], options: SpawnSyncOptions = { - timeout: 10000, encoding: 'utf-8', + timeout: 10000, }, ) => { const { error, stdout, stderr } = spawnSync( @@ -31,7 +31,7 @@ const execAnvilAccessModule = ( output = stdout; console.warn( - `Failed to parse anvil-access-module output [${output}]; error: [${stdoutParseError}]`, + `Failed to parse anvil-access-module output [${output}]; CAUSE: [${stdoutParseError}]`, ); } @@ -63,6 +63,14 @@ const execModuleSubroutine = ( args.push('--sub-params', JSON.stringify(subParams)); } + console.log( + `...${subModuleName}->${subName} with params: ${JSON.stringify( + subParams, + null, + 2, + )}`, + ); + const { stdout } = execAnvilAccessModule(args, spawnSyncOptions); return { @@ -102,8 +110,6 @@ const dbJobAnvilSyncShared = ( subParams.job_host_uuid = jobHostUUID; } - console.log(JSON.stringify(subParams, null, 2)); - return execModuleSubroutine('insert_or_update_jobs', { subParams }).stdout; }; diff --git a/striker-ui-api/src/lib/consts/SERVER_PATHS.ts b/striker-ui-api/src/lib/consts/SERVER_PATHS.ts index 8fd3fe82..dea1f4d1 100644 --- a/striker-ui-api/src/lib/consts/SERVER_PATHS.ts +++ b/striker-ui-api/src/lib/consts/SERVER_PATHS.ts @@ -6,12 +6,15 @@ const EMPTY_SERVER_PATHS: ServerPath = { incoming: {}, }, }, + tmp: {}, usr: { bin: { + mkfifo: {}, sed: {}, }, sbin: { 'anvil-access-module': {}, + 'anvil-get-server-screenshot': {}, 'anvil-provision-server': {}, 'anvil-sync-shared': {}, 'striker-parse-os-list': {}, diff --git a/striker-ui-api/src/lib/mkfifo.ts b/striker-ui-api/src/lib/mkfifo.ts new file mode 100644 index 00000000..0f5b0a1d --- /dev/null +++ b/striker-ui-api/src/lib/mkfifo.ts @@ -0,0 +1,18 @@ +import { spawnSync } from 'child_process'; + +import SERVER_PATHS from './consts/SERVER_PATHS'; + +export const mkfifo = (...args: string[]) => { + const { error, stderr } = spawnSync(SERVER_PATHS.usr.bin.mkfifo.self, args, { + encoding: 'utf-8', + timeout: 3000, + }); + + if (error) { + throw error; + } + + if (stderr) { + throw new Error(stderr); + } +}; diff --git a/striker-ui-api/src/lib/request_handlers/buildGetRequestHandler.ts b/striker-ui-api/src/lib/request_handlers/buildGetRequestHandler.ts index ea27f892..2ddd6e32 100644 --- a/striker-ui-api/src/lib/request_handlers/buildGetRequestHandler.ts +++ b/striker-ui-api/src/lib/request_handlers/buildGetRequestHandler.ts @@ -23,7 +23,7 @@ const buildGetRequestHandler = }), )); } catch (queryError) { - console.log(`Query error: ${queryError}`); + console.log(`Failed to execute query; CAUSE: ${queryError}`); response.status(500).send(); diff --git a/striker-ui-api/src/lib/request_handlers/server/getServerDetail.ts b/striker-ui-api/src/lib/request_handlers/server/getServerDetail.ts new file mode 100644 index 00000000..f98973ac --- /dev/null +++ b/striker-ui-api/src/lib/request_handlers/server/getServerDetail.ts @@ -0,0 +1,139 @@ +import assert from 'assert'; +import { RequestHandler } from 'express'; +import { createReadStream, existsSync, rmSync, statSync } from 'fs'; +import path from 'path'; + +import { REP_UUID } from '../../consts/REG_EXP_PATTERNS'; +import SERVER_PATHS from '../../consts/SERVER_PATHS'; + +import { dbQuery, sub } from '../../accessModule'; +import { mkfifo } from '../../mkfifo'; +import { sanitizeQS } from '../../sanitizeQS'; + +export const getServerDetail: RequestHandler = (request, response) => { + const { serverUUID } = request.params; + const { ss, resize } = request.query; + + const isScreenshot = sanitizeQS(ss, { + returnType: 'boolean', + }); + + console.log(`serverUUID=[${serverUUID}],isScreenshot=[${isScreenshot}]`); + + try { + assert( + REP_UUID.test(serverUUID), + `Server UUID must be a valid UUID; got [${serverUUID}]`, + ); + } catch (assertError) { + console.log( + `Failed to assert value when trying to get server detail; CAUSE: ${assertError}.`, + ); + + response.status(500).send(); + + return; + } + + if (isScreenshot) { + let requestHostUUID: string, serverHostUUID: string; + + try { + requestHostUUID = sub('host_uuid', { + subModuleName: 'Get', + }).stdout; + } catch (subError) { + console.log(`Failed to get local host UUID; CAUSE: ${subError}`); + + response.status(500).send(); + + return; + } + + console.log(`requestHostUUID=[${requestHostUUID}]`); + + try { + [[serverHostUUID]] = dbQuery(` + SELECT server_host_uuid + FROM servers + WHERE server_uuid = '${serverUUID}';`).stdout; + } catch (queryError) { + console.log(`Failed to get server host UUID; CAUSE: ${queryError}`); + + response.status(500).send(); + + return; + } + + console.log(`serverHostUUID=[${serverHostUUID}]`); + + const imageFileName = `${serverUUID}_screenshot`; + const imageFilePath = path.join(SERVER_PATHS.tmp.self, imageFileName); + + try { + if (existsSync(imageFilePath)) { + if (!statSync(imageFilePath).isFIFO()) { + rmSync(imageFilePath); + mkfifo(imageFilePath); + } + } else { + mkfifo(imageFilePath); + } + + const namedPipeReadStream = createReadStream(imageFilePath, { + encoding: 'utf-8', + }); + + namedPipeReadStream.once('data', (data) => { + response.status(200).send({ screenshot: data.toString().trim() }); + + namedPipeReadStream.close(); + }); + } catch (prepPipeError) { + console.log(`Failed to prepare named pipe; CAUSE: ${prepPipeError}`); + + response.status(500).send(); + + return; + } + + let resizeArgs = sanitizeQS(resize, { + returnType: 'string', + }); + + if (!/^\d+x\d+$/.test(resizeArgs)) { + resizeArgs = ''; + } + + try { + sub('insert_or_update_jobs', { + subParams: { + file: __filename, + line: 0, + job_command: + SERVER_PATHS.usr.sbin['anvil-get-server-screenshot'].self, + job_data: `server-uuid=${serverUUID} +request-host-uuid=${requestHostUUID} +resize=${resizeArgs}`, + job_name: `get_server_screenshot::${serverUUID}`, + job_title: 'job_0356', + job_description: 'job_0357', + job_progress: 0, + job_host_uuid: serverHostUUID, + }, + }).stdout; + } catch (subError) { + console.log( + `Failed to queue fetch server screenshot job; CAUSE: ${subError}`, + ); + + response.status(500).send(); + + return; + } + } else { + // For getting sever detail data. + + response.status(200).send(); + } +}; diff --git a/striker-ui-api/src/lib/request_handlers/server/index.ts b/striker-ui-api/src/lib/request_handlers/server/index.ts index 28aabe98..c5a696d2 100644 --- a/striker-ui-api/src/lib/request_handlers/server/index.ts +++ b/striker-ui-api/src/lib/request_handlers/server/index.ts @@ -1,2 +1,3 @@ export { createServer } from './createServer'; export { getServer } from './getServer'; +export { getServerDetail } from './getServerDetail'; diff --git a/striker-ui-api/src/routes/file.ts b/striker-ui-api/src/routes/file.ts index fa5ec726..1d5e1440 100644 --- a/striker-ui-api/src/routes/file.ts +++ b/striker-ui-api/src/routes/file.ts @@ -174,7 +174,7 @@ router try { ({ stdout: queryStdout } = dbWrite(query)); } catch (queryError) { - console.log(`Query error: ${queryError}`); + console.log(`Failed to execute query; CAUSE: ${queryError}`); response.status(500).send(); } diff --git a/striker-ui-api/src/routes/server.ts b/striker-ui-api/src/routes/server.ts index 45c12243..802838c4 100644 --- a/striker-ui-api/src/routes/server.ts +++ b/striker-ui-api/src/routes/server.ts @@ -1,9 +1,16 @@ import express from 'express'; -import { createServer, getServer } from '../lib/request_handlers/server'; +import { + createServer, + getServer, + getServerDetail, +} from '../lib/request_handlers/server'; const router = express.Router(); -router.get('/', getServer).post('/', createServer); +router + .get('/', getServer) + .get('/:serverUUID', getServerDetail) + .post('/', createServer); export default router;