diff --git a/Common/Types/Monitor/ServerMonitor/ServerMonitorRequest.ts b/Common/Types/Monitor/ServerMonitor/ServerMonitorRequest.ts new file mode 100644 index 0000000000..75694e0e38 --- /dev/null +++ b/Common/Types/Monitor/ServerMonitor/ServerMonitorRequest.ts @@ -0,0 +1,6 @@ +import ObjectID from '../../ObjectID'; + +export default interface ServerMonitorRequest { + monitorId: ObjectID; + secretKey: ObjectID; +} diff --git a/Common/Types/Monitor/ServerMonitor/ServerMonitorResponse.ts b/Common/Types/Monitor/ServerMonitor/ServerMonitorResponse.ts new file mode 100644 index 0000000000..54d59e8ffb --- /dev/null +++ b/Common/Types/Monitor/ServerMonitor/ServerMonitorResponse.ts @@ -0,0 +1,8 @@ +import BasicInfrastructureMetrics from "../../Infrastrucutre/BasicMetrics"; +import ObjectID from "../../ObjectID"; + +export interface ServerMonitorResponse { + monitorId: ObjectID; + secretKey: ObjectID; + basicInfrastructureMetrics: BasicInfrastructureMetrics +} \ No newline at end of file diff --git a/CommonServer/Services/MonitorService.ts b/CommonServer/Services/MonitorService.ts index c2660337d5..3ecdfbe6fb 100644 --- a/CommonServer/Services/MonitorService.ts +++ b/CommonServer/Services/MonitorService.ts @@ -91,10 +91,20 @@ export class Service extends DatabaseService { ); } + if(createBy.data.monitorType === MonitorType.Server) { + createBy.data.serverMonitorSecretKey = ObjectID.generate(); + } + + if(createBy.data.monitorType === MonitorType.IncomingRequest) { + createBy.data.incomingRequestSecretKey = ObjectID.generate(); + } + if (!createBy.props.tenantId) { throw new BadDataException('ProjectId required to create monitor.'); } + + const monitorStatus: MonitorStatus | null = await MonitorStatusService.findOneBy({ query: { diff --git a/Ingestor/API/ServerMonitor.ts b/Ingestor/API/ServerMonitor.ts new file mode 100644 index 0000000000..71dcc95477 --- /dev/null +++ b/Ingestor/API/ServerMonitor.ts @@ -0,0 +1,78 @@ +import Express, { + ExpressRequest, + ExpressResponse, + ExpressRouter, + NextFunction, + RequestHandler, +} from 'CommonServer/Utils/Express'; +import Response from 'CommonServer/Utils/Response'; +import BadDataException from 'Common/Types/Exception/BadDataException'; +import ProbeMonitorResponseService from 'CommonServer/Utils/Probe/ProbeMonitorResponse'; +import Dictionary from 'Common/Types/Dictionary'; +import { JSONObject } from 'Common/Types/JSON'; +import ObjectID from 'Common/Types/ObjectID'; +import IncomingMonitorRequest from 'Common/Types/Monitor/IncomingMonitor/IncomingMonitorRequest'; +import OneUptimeDate from 'Common/Types/Date'; + +const router: ExpressRouter = Express.getRouter(); + +const processServerMonitor: RequestHandler = async ( + req: ExpressRequest, + res: ExpressResponse, + next: NextFunction +): Promise => { + try { + const requestHeaders: Dictionary = + req.headers as Dictionary; + const requestBody: string | JSONObject = req.body as + | string + | JSONObject; + + const monitorSecretKeyAsString: string | undefined = req.params['secretkey']; + + if (!monitorSecretKeyAsString) { + throw new BadDataException('Monitor Secret Key is required'); + } + + const monitorId: ObjectID = ObjectID.fromString(monitorSecretKeyAsString); + + const serverMonitorRequest: ServerMonitorRequest = { + monitorId: monitorId, + requestHeaders: requestHeaders, + requestBody: requestBody, + incomingRequestReceivedAt: OneUptimeDate.getCurrentDate(), + onlyCheckForIncomingRequestReceivedAt: false, + }; + + // process probe response here. + await ProbeMonitorResponseService.processProbeResponse(incomingRequest); + + return Response.sendEmptyResponse(req, res); + } catch (err) { + return next(err); + } +}; + +router.get( + '/server-monitor/:secretkey', + async ( + req: ExpressRequest, + res: ExpressResponse, + next: NextFunction + ): Promise => { + processServerMonitor(req, res, next); + } +); + +router.post( + '/server-monitor/response/ingest', + async ( + req: ExpressRequest, + res: ExpressResponse, + next: NextFunction + ): Promise => { + processServerMonitor(req, res, next); + } +); + +export default router; diff --git a/Model/Models/Monitor.ts b/Model/Models/Monitor.ts index 595829f15f..768c895bef 100644 --- a/Model/Models/Monitor.ts +++ b/Model/Models/Monitor.ts @@ -761,4 +761,115 @@ export default class Monitor extends BaseModel { default: false, }) public disableActiveMonitoringBecauseOfManualIncident?: boolean = undefined; + + + + @ColumnAccessControl({ + create: [ + Permission.ProjectOwner, + Permission.ProjectAdmin, + Permission.ProjectMember, + Permission.CanCreateProjectMonitor, + ], + read: [ + Permission.ProjectOwner, + Permission.ProjectAdmin, + Permission.ProjectMember, + Permission.CanReadProjectMonitor, + ], + update: [ + Permission.ProjectOwner, + Permission.ProjectAdmin, + Permission.ProjectMember, + Permission.CanCreateProjectMonitor, + ], + }) + @Index() + @TableColumn({ + type: TableColumnType.Date, + required: false, + isDefaultValueColumn: false, + title: 'Server Monitor Request Received At', + description: + 'This field is for Server Monitor only. When was the last time we received a request?', + }) + @Column({ + type: ColumnType.Date, + nullable: true, + }) + public serverMonitorRequestReceivedAt?: Date = undefined; + + @ColumnAccessControl({ + create: [ + Permission.ProjectOwner, + Permission.ProjectAdmin, + Permission.ProjectMember, + Permission.CanCreateProjectMonitor, + ], + read: [ + Permission.ProjectOwner, + Permission.ProjectAdmin, + Permission.ProjectMember, + Permission.CanReadProjectMonitor, + ], + update: [ + Permission.ProjectOwner, + Permission.ProjectAdmin, + Permission.ProjectMember, + Permission.CanCreateProjectMonitor, + ], + }) + @Index() + @TableColumn({ + type: TableColumnType.ObjectID, + required: false, + isDefaultValueColumn: false, + title: 'Server Monitor Secret Key', + description: + 'This field is for Server Monitor only. Secret Key to authenticate the request.', + }) + @Column({ + type: ColumnType.ObjectID, + nullable: true, + transformer: ObjectID.getDatabaseTransformer(), + }) + public serverMonitorSecretKey?: ObjectID = undefined; + + + + @ColumnAccessControl({ + create: [ + Permission.ProjectOwner, + Permission.ProjectAdmin, + Permission.ProjectMember, + Permission.CanCreateProjectMonitor, + ], + read: [ + Permission.ProjectOwner, + Permission.ProjectAdmin, + Permission.ProjectMember, + Permission.CanReadProjectMonitor, + ], + update: [ + Permission.ProjectOwner, + Permission.ProjectAdmin, + Permission.ProjectMember, + Permission.CanCreateProjectMonitor, + ], + }) + @Index() + @TableColumn({ + type: TableColumnType.ObjectID, + required: false, + isDefaultValueColumn: false, + title: 'Incoming Request Secret Key', + description: + 'This field is for Incoming Request Monitor only. Secret Key to authenticate the request.', + }) + @Column({ + type: ColumnType.ObjectID, + nullable: true, + transformer: ObjectID.getDatabaseTransformer(), + }) + public incomingRequestSecretKey?: ObjectID = undefined; }