diff --git a/striker-ui-api/src/lib/request_handlers/anvil/getAnvilDetail.ts b/striker-ui-api/src/lib/request_handlers/anvil/getAnvilDetail.ts index 024e007b..5746f751 100644 --- a/striker-ui-api/src/lib/request_handlers/anvil/getAnvilDetail.ts +++ b/striker-ui-api/src/lib/request_handlers/anvil/getAnvilDetail.ts @@ -8,7 +8,7 @@ const buildHostStateMessage = (postfix = 2) => `message_022${postfix}`; export const getAnvilDetail: RequestHandler< AnvilDetailParamsDictionary, - AnvilDetailResponseBody, + AnvilDetail, undefined > = async (request, response) => { const { @@ -36,7 +36,7 @@ export const getAnvilDetail: RequestHandler< }, } = anvils; - const result: AnvilDetailResponseBody = { anvil_state: 'optimal', hosts: [] }; + const result: AnvilDetail = { anvil_state: 'optimal', hosts: [] }; for (const huuid of [n1uuid, n2uuid]) { const { diff --git a/striker-ui-api/src/lib/request_handlers/anvil/getAnvilStore.ts b/striker-ui-api/src/lib/request_handlers/anvil/getAnvilStore.ts new file mode 100644 index 00000000..a5e07532 --- /dev/null +++ b/striker-ui-api/src/lib/request_handlers/anvil/getAnvilStore.ts @@ -0,0 +1,67 @@ +import assert from 'assert'; +import { RequestHandler } from 'express'; + +import { REP_UUID } from '../../consts'; + +import { query } from '../../accessModule'; +import { sanitize } from '../../sanitize'; +import { stderr } from '../../shell'; + +export const getAnvilStore: RequestHandler< + AnvilDetailParamsDictionary +> = async (request, response) => { + const { + params: { anvilUuid: rAnUuid }, + } = request; + + const anUuid = sanitize(rAnUuid, 'string', { modifierType: 'sql' }); + + try { + assert( + REP_UUID.test(anUuid), + `Param UUID must be a valid UUIDv4; got [${anUuid}]`, + ); + } catch (error) { + stderr(`Failed to assert value during get anvil storage; CAUSE: ${error}`); + + return response.status(400).send(); + } + + let rows: [uuid: string, name: string, size: string, free: string][]; + + try { + rows = await query( + `SELECT + DISTINCT ON (b.storage_group_uuid) storage_group_uuid, + b.storage_group_name, + d.scan_lvm_vg_size, + d.scan_lvm_vg_free + FROM anvils AS a + JOIN storage_groups AS b + ON a.anvil_uuid = b.storage_group_anvil_uuid + JOIN storage_group_members AS c + ON b.storage_group_uuid = c.storage_group_member_storage_group_uuid + JOIN scan_lvm_vgs AS d + ON c.storage_group_member_vg_uuid = d.scan_lvm_vg_internal_uuid + WHERE a.anvil_uuid = '${anUuid}' + ORDER BY b.storage_group_uuid, d.scan_lvm_vg_free;`, + ); + } catch (error) { + stderr(`Failed to get anvil storage summary; CAUSE: ${error}`); + + return response.status(500).send(); + } + + const rsbody: AnvilDetailStoreSummary = { + storage_groups: rows.map( + ([sgUuid, sgName, sgSize, sgFree]) => ({ + storage_group_free: sgFree, + storage_group_name: sgName, + storage_group_total: sgSize, + storage_group_uuid: sgUuid, + }), + ), + }; + + return response.json(rsbody); +}; diff --git a/striker-ui-api/src/lib/request_handlers/anvil/index.ts b/striker-ui-api/src/lib/request_handlers/anvil/index.ts index d42bccca..aaefa83b 100644 --- a/striker-ui-api/src/lib/request_handlers/anvil/index.ts +++ b/striker-ui-api/src/lib/request_handlers/anvil/index.ts @@ -3,3 +3,4 @@ export * from './getAnvilCpu'; export * from './getAnvilDetail'; export * from './getAnvilMemory'; export * from './getAnvilNetwork'; +export * from './getAnvilStore'; diff --git a/striker-ui-api/src/routes/anvil.ts b/striker-ui-api/src/routes/anvil.ts index f971e7ab..50a18a78 100644 --- a/striker-ui-api/src/routes/anvil.ts +++ b/striker-ui-api/src/routes/anvil.ts @@ -6,6 +6,7 @@ import { getAnvilDetail, getAnvilMemory, getAnvilNetwork, + getAnvilStore, } from '../lib/request_handlers/anvil'; const router = express.Router(); @@ -15,6 +16,7 @@ router .get('/:anvilUuid/cpu', getAnvilCpu) .get('/:anvilUuid/memory', getAnvilMemory) .get('/:anvilUuid/network', getAnvilNetwork) + .get('/:anvilUuid/store', getAnvilStore) .get('/:anvilUuid', getAnvilDetail); export default router; diff --git a/striker-ui-api/src/types/ApiAn.d.ts b/striker-ui-api/src/types/ApiAn.d.ts index 2d17e694..962d0589 100644 --- a/striker-ui-api/src/types/ApiAn.d.ts +++ b/striker-ui-api/src/types/ApiAn.d.ts @@ -1,3 +1,15 @@ +type AnvilDetailFileForProvisionServer = { + fileUUID: string; + fileName: string; +}; + +type AnvilDetailHostForProvisionServer = { + hostUUID: string; + hostName: string; + hostCPUCores: number; + hostMemory: string; +}; + type AnvilDetailHostMemory = { free: string; host_uuid: string; @@ -6,34 +18,25 @@ type AnvilDetailHostMemory = { total: string; }; -type AnvilDetailHostSummary = { - host_name: string; - host_uuid: string; - maintenance_mode: boolean; - state: string; - state_message: string; - state_percent: number; -}; - -type AnvilDetailParamsDictionary = { - anvilUuid: string; -}; - -type AnvilDetailResponseBody = { - anvil_state: string; - hosts: AnvilDetailHostSummary[]; +type AnvilDetailServerForProvisionServer = { + serverUUID: string; + serverName: string; + serverCPUCores: number; + serverMemory: string; }; -type AnvilDetailFileForProvisionServer = { - fileUUID: string; - fileName: string; +type AnvilDetailStore = { + storage_group_free: string; + storage_group_name: string; + storage_group_total: string; + storage_group_uuid: string; }; -type AnvilDetailHostForProvisionServer = { - hostUUID: string; - hostName: string; - hostCPUCores: number; - hostMemory: string; +type AnvilDetailStoreForProvisionServer = { + storageGroupUUID: string; + storageGroupName: string; + storageGroupSize: string; + storageGroupFree: string; }; type AnvilDetailSubnodeLink = { @@ -57,22 +60,20 @@ type AnvilDetailSubnodeNetwork = { host_uuid: string; }; -type AnvilDetailNetworkSummary = { - hosts: AnvilDetailSubnodeNetwork[]; -}; +// Types below are for typing request handlers: -type AnvilDetailServerForProvisionServer = { - serverUUID: string; - serverName: string; - serverCPUCores: number; - serverMemory: string; +type AnvilDetailHostSummary = { + host_name: string; + host_uuid: string; + maintenance_mode: boolean; + state: string; + state_message: string; + state_percent: number; }; -type AnvilDetailStoreForProvisionServer = { - storageGroupUUID: string; - storageGroupName: string; - storageGroupSize: string; - storageGroupFree: string; +type AnvilDetail = { + anvil_state: string; + hosts: AnvilDetailHostSummary[]; }; type AnvilDetailForProvisionServer = { @@ -91,6 +92,18 @@ type AnvilDetailForProvisionServer = { storageGroups: AnvilDetailStoreForProvisionServer[]; }; +type AnvilDetailNetworkSummary = { + hosts: AnvilDetailSubnodeNetwork[]; +}; + +type AnvilDetailParamsDictionary = { + anvilUuid: string; +}; + +type AnvilDetailStoreSummary = { + storage_groups: AnvilDetailStore[]; +}; + type AnvilOverview = { anvilName: string; anvilUUID: string;