add monitor list api

This commit is contained in:
Simon Larsen
2023-05-05 13:02:23 +01:00
parent bca11364a2
commit 99c9b58c81
25 changed files with 417 additions and 365 deletions

View File

@@ -30,7 +30,10 @@ export default class StatusCode {
statusCode = parseInt(statusCode as string);
}
if (statusCode as number >= 100 && statusCode as number <= 599) {
if (
(statusCode as number) >= 100 &&
(statusCode as number) <= 599
) {
return true;
}

View File

@@ -18,7 +18,7 @@ export default class PositiveNumber {
}
}
if (positiveNumber as number < 0) {
if ((positiveNumber as number) < 0) {
throw new BadDataException('positiveNumber cannot be less than 0');
}

View File

@@ -47,7 +47,7 @@ export const ClusterKey: ObjectID = new ObjectID(
process.env['ONEUPTIME_SECRET'] || 'secret'
);
export const hasClusterKey: boolean = !!process.env['ONEUPTIME_SECRET'];
export const hasClusterKey: boolean = Boolean(process.env['ONEUPTIME_SECRET']);
export const Domain: Hostname = Hostname.fromString(
process.env['DOMAIN'] || 'localhost'

View File

@@ -1,32 +1,39 @@
import PostgresDatabase from '../Infrastructure/PostgresDatabase';
import Model from 'Model/Models/MonitorProbe';
import DatabaseService, { OnCreate } from './DatabaseService';
import CreateBy from '../Types/Database/CreateBy';
import BadDataException from 'Common/Types/Exception/BadDataException';
import MonitorProbe from 'Model/Models/MonitorProbe';
export class Service extends DatabaseService<Model> {
export class Service extends DatabaseService<MonitorProbe> {
public constructor(postgresDatabase?: PostgresDatabase) {
super(Model, postgresDatabase);
super(MonitorProbe, postgresDatabase);
}
protected override async onBeforeCreate(createBy: CreateBy<Model>): Promise<OnCreate<Model>> {
if((createBy.data.monitorId || createBy.data.monitor) && (createBy.data.probeId || createBy.data.probe)){
const monitorProbe = await this.findOneBy({
protected override async onBeforeCreate(
createBy: CreateBy<MonitorProbe>
): Promise<OnCreate<MonitorProbe>> {
if (
(createBy.data.monitorId || createBy.data.monitor) &&
(createBy.data.probeId || createBy.data.probe)
) {
const monitorProbe: MonitorProbe | null = await this.findOneBy({
query: {
monitorId: createBy.data.monitorId! || createBy.data.monitor?.id!,
probeId: createBy.data.probeId! || createBy.data.probe?.id!
monitorId:
createBy.data.monitorId! || createBy.data.monitor?.id!,
probeId: createBy.data.probeId! || createBy.data.probe?.id!,
},
select: {
_id: true
_id: true,
},
props: {
isRoot: true
}
isRoot: true,
},
});
if(monitorProbe){
throw new BadDataException('Probe is already added to this monitor.');
if (monitorProbe) {
throw new BadDataException(
'Probe is already added to this monitor.'
);
}
}

View File

@@ -14,6 +14,7 @@ import { LIMIT_PER_PROJECT } from 'Common/Types/Database/LimitMax';
import MonitorProbe from 'Model/Models/MonitorProbe';
import MonitorProbeService from './MonitorProbeService';
import MonitorType from 'Common/Types/Monitor/MonitorType';
import Probe from 'Model/Models/Probe';
export class Service extends DatabaseService<Model> {
public constructor(postgresDatabase?: PostgresDatabase) {
@@ -75,47 +76,59 @@ export class Service extends DatabaseService<Model> {
onCreate.createBy.props
);
if(createdItem.monitorType && (createdItem.monitorType === MonitorType.API || createdItem.monitorType === MonitorType.IncomingRequest || createdItem.monitorType === MonitorType.Website || createdItem.monitorType === MonitorType.Ping || createdItem.monitorType === MonitorType.IP)) {
await this.addDefaultProbesToMonitor(createdItem.projectId, createdItem.id);
if (
createdItem.monitorType &&
(createdItem.monitorType === MonitorType.API ||
createdItem.monitorType === MonitorType.IncomingRequest ||
createdItem.monitorType === MonitorType.Website ||
createdItem.monitorType === MonitorType.Ping ||
createdItem.monitorType === MonitorType.IP)
) {
await this.addDefaultProbesToMonitor(
createdItem.projectId,
createdItem.id
);
}
return createdItem;
}
public async addDefaultProbesToMonitor(projectId: ObjectID, monitorId: ObjectID) {
const globalProbes = await ProbeService.findBy({
public async addDefaultProbesToMonitor(
projectId: ObjectID,
monitorId: ObjectID
): Promise<void> {
const globalProbes: Array<Probe> = await ProbeService.findBy({
query: {
isGlobalProbe: true,
shouldAutoEnableProbeOnNewMonitors: true
shouldAutoEnableProbeOnNewMonitors: true,
},
select: {
_id: true
_id: true,
},
skip: 0,
limit: LIMIT_PER_PROJECT,
props: {
isRoot: true
}
isRoot: true,
},
});
const projectProbes = await ProbeService.findBy({
const projectProbes: Array<Probe> = await ProbeService.findBy({
query: {
isGlobalProbe: false,
shouldAutoEnableProbeOnNewMonitors: true,
projectId: projectId
projectId: projectId,
},
select: {
_id: true
_id: true,
},
skip: 0,
limit: LIMIT_PER_PROJECT,
props: {
isRoot: true
}
})
isRoot: true,
},
});
const totalProbes = [...globalProbes, ...projectProbes];
const totalProbes: Array<Probe> = [...globalProbes, ...projectProbes];
for (const probe of totalProbes) {
const monitorProbe: MonitorProbe = new MonitorProbe();
@@ -128,8 +141,8 @@ export class Service extends DatabaseService<Model> {
await MonitorProbeService.create({
data: monitorProbe,
props: {
isRoot: true
}
isRoot: true,
},
});
}
}

View File

@@ -1,9 +1,9 @@
import CronParser from 'cron-parser';
import CronParser, { CronExpression } from 'cron-parser';
export default class CronTab {
public static getNextExecutionTime(crontab: string): Date {
const interval = CronParser.parseExpression(crontab);
const nextExecutionTime = interval.next().toDate();
const interval: CronExpression = CronParser.parseExpression(crontab);
const nextExecutionTime: Date = interval.next().toDate();
return nextExecutionTime;
}
}
}
}

View File

@@ -125,7 +125,9 @@ const TableRow: FunctionComponent<ComponentProps> = (
props.item,
column.key,
''
)?.toString() || column.noValueMessage || ''
)?.toString() ||
column.noValueMessage ||
''
)
) : (
<></>

View File

@@ -301,7 +301,7 @@ const App: FunctionComponent = () => {
<NotOperationalMonitors
pageRoute={
RouteMap[
PageMap.HOME_NOT_OPERATIONAL_MONITORS
PageMap.HOME_NOT_OPERATIONAL_MONITORS
] as Route
}
currentProject={selectedProject}
@@ -321,8 +321,8 @@ const App: FunctionComponent = () => {
<OngoingScheduledEvents
pageRoute={
RouteMap[
PageMap
.HOME_ONGOING_SCHEDULED_MAINTENANCE_EVENTS
PageMap
.HOME_ONGOING_SCHEDULED_MAINTENANCE_EVENTS
] as Route
}
currentProject={selectedProject}
@@ -350,7 +350,7 @@ const App: FunctionComponent = () => {
<MonitorInoperational
pageRoute={
RouteMap[
PageMap.MONITORS_INOPERATIONAL
PageMap.MONITORS_INOPERATIONAL
] as Route
}
currentProject={selectedProject}
@@ -392,7 +392,7 @@ const App: FunctionComponent = () => {
<MonitorViewStatusTimeline
pageRoute={
RouteMap[
PageMap.MONITOR_VIEW_STATUS_TIMELINE
PageMap.MONITOR_VIEW_STATUS_TIMELINE
] as Route
}
currentProject={selectedProject}
@@ -424,7 +424,7 @@ const App: FunctionComponent = () => {
<MonitorIncidents
pageRoute={
RouteMap[
PageMap.MONITOR_VIEW_INCIDENTS
PageMap.MONITOR_VIEW_INCIDENTS
] as Route
}
currentProject={selectedProject}
@@ -442,7 +442,7 @@ const App: FunctionComponent = () => {
<MonitorViewCustomFields
pageRoute={
RouteMap[
PageMap.MONITOR_VIEW_CUSTOM_FIELDS
PageMap.MONITOR_VIEW_CUSTOM_FIELDS
] as Route
}
currentProject={selectedProject}
@@ -467,8 +467,7 @@ const App: FunctionComponent = () => {
<PageRoute
path={
RouteMap[PageMap.MONITOR_VIEW_PROBES]?.toString() ||
''
RouteMap[PageMap.MONITOR_VIEW_PROBES]?.toString() || ''
}
element={
<MonitorViewProbes
@@ -623,7 +622,7 @@ const App: FunctionComponent = () => {
<StatusPagesViewDelete
pageRoute={
RouteMap[
PageMap.STATUS_PAGE_VIEW_DELETE
PageMap.STATUS_PAGE_VIEW_DELETE
] as Route
}
currentProject={selectedProject}
@@ -641,7 +640,7 @@ const App: FunctionComponent = () => {
<StatusPagesViewBranding
pageRoute={
RouteMap[
PageMap.STATUS_PAGE_VIEW_BRANDING
PageMap.STATUS_PAGE_VIEW_BRANDING
] as Route
}
currentProject={selectedProject}
@@ -659,7 +658,7 @@ const App: FunctionComponent = () => {
<StatusPagesViewCustomHtmlCss
pageRoute={
RouteMap[
PageMap.STATUS_PAGE_VIEW_CUSTOM_HTML_CSS
PageMap.STATUS_PAGE_VIEW_CUSTOM_HTML_CSS
] as Route
}
currentProject={selectedProject}
@@ -677,7 +676,7 @@ const App: FunctionComponent = () => {
<StatusPagesViewAdvancedOptions
pageRoute={
RouteMap[
PageMap.STATUS_PAGE_VIEW_ADVANCED_OPTIONS
PageMap.STATUS_PAGE_VIEW_ADVANCED_OPTIONS
] as Route
}
currentProject={selectedProject}
@@ -695,7 +694,7 @@ const App: FunctionComponent = () => {
<StatusPageViewCustomFields
pageRoute={
RouteMap[
PageMap.STATUS_PAGE_VIEW_CUSTOM_FIELDS
PageMap.STATUS_PAGE_VIEW_CUSTOM_FIELDS
] as Route
}
currentProject={selectedProject}
@@ -727,7 +726,7 @@ const App: FunctionComponent = () => {
<StatusPagesViewEmailSubscribers
pageRoute={
RouteMap[
PageMap.STATUS_PAGE_VIEW_EMAIL_SUBSCRIBERS
PageMap.STATUS_PAGE_VIEW_EMAIL_SUBSCRIBERS
] as Route
}
currentProject={selectedProject}
@@ -745,8 +744,8 @@ const App: FunctionComponent = () => {
<StatusPageViewAuthenticationSettings
pageRoute={
RouteMap[
PageMap
.STATUS_PAGE_VIEW_AUTHENTICATION_SETTINGS
PageMap
.STATUS_PAGE_VIEW_AUTHENTICATION_SETTINGS
] as Route
}
currentProject={selectedProject}
@@ -764,7 +763,7 @@ const App: FunctionComponent = () => {
<StatusPageViewCustomSMTP
pageRoute={
RouteMap[
PageMap.STATUS_PAGE_VIEW_CUSTOM_SMTP
PageMap.STATUS_PAGE_VIEW_CUSTOM_SMTP
] as Route
}
currentProject={selectedProject}
@@ -782,7 +781,7 @@ const App: FunctionComponent = () => {
<StatusPageViewPrivateUser
pageRoute={
RouteMap[
PageMap.STATUS_PAGE_VIEW_PRIVATE_USERS
PageMap.STATUS_PAGE_VIEW_PRIVATE_USERS
] as Route
}
currentProject={selectedProject}
@@ -800,7 +799,7 @@ const App: FunctionComponent = () => {
<StatusPagesViewSMSSubscribers
pageRoute={
RouteMap[
PageMap.STATUS_PAGE_VIEW_SMS_SUBSCRIBERS
PageMap.STATUS_PAGE_VIEW_SMS_SUBSCRIBERS
] as Route
}
currentProject={selectedProject}
@@ -818,7 +817,7 @@ const App: FunctionComponent = () => {
<StatusPagesViewHeaderStyle
pageRoute={
RouteMap[
PageMap.STATUS_PAGE_VIEW_HEADER_STYLE
PageMap.STATUS_PAGE_VIEW_HEADER_STYLE
] as Route
}
currentProject={selectedProject}
@@ -836,7 +835,7 @@ const App: FunctionComponent = () => {
<StatusPagesViewFooterStyle
pageRoute={
RouteMap[
PageMap.STATUS_PAGE_VIEW_FOOTER_STYLE
PageMap.STATUS_PAGE_VIEW_FOOTER_STYLE
] as Route
}
currentProject={selectedProject}
@@ -854,7 +853,7 @@ const App: FunctionComponent = () => {
<StatusPagesViewNavBarStyle
pageRoute={
RouteMap[
PageMap.STATUS_PAGE_VIEW_NAVBAR_STYLE
PageMap.STATUS_PAGE_VIEW_NAVBAR_STYLE
] as Route
}
currentProject={selectedProject}
@@ -872,7 +871,7 @@ const App: FunctionComponent = () => {
<StatusPagesViewWebhookSubscribers
pageRoute={
RouteMap[
PageMap.STATUS_PAGE_VIEW_WEBHOOK_SUBSCRIBERS
PageMap.STATUS_PAGE_VIEW_WEBHOOK_SUBSCRIBERS
] as Route
}
currentProject={selectedProject}
@@ -890,7 +889,7 @@ const App: FunctionComponent = () => {
<StatusPagesViewEmbedded
pageRoute={
RouteMap[
PageMap.STATUS_PAGE_VIEW_EMBEDDED
PageMap.STATUS_PAGE_VIEW_EMBEDDED
] as Route
}
currentProject={selectedProject}
@@ -908,7 +907,7 @@ const App: FunctionComponent = () => {
<StatusPagesViewResources
pageRoute={
RouteMap[
PageMap.STATUS_PAGE_VIEW_RESOURCES
PageMap.STATUS_PAGE_VIEW_RESOURCES
] as Route
}
currentProject={selectedProject}
@@ -926,7 +925,7 @@ const App: FunctionComponent = () => {
<StatusPagesViewDomains
pageRoute={
RouteMap[
PageMap.STATUS_PAGE_VIEW_DOMAINS
PageMap.STATUS_PAGE_VIEW_DOMAINS
] as Route
}
currentProject={selectedProject}
@@ -943,7 +942,7 @@ const App: FunctionComponent = () => {
<StatusPagesViewGroups
pageRoute={
RouteMap[
PageMap.STATUS_PAGE_VIEW_GROUPS
PageMap.STATUS_PAGE_VIEW_GROUPS
] as Route
}
currentProject={selectedProject}
@@ -961,7 +960,7 @@ const App: FunctionComponent = () => {
<StatusPagesViewAnnouncement
pageRoute={
RouteMap[
PageMap.STATUS_PAGE_VIEW_ANNOUNCEMENTS
PageMap.STATUS_PAGE_VIEW_ANNOUNCEMENTS
] as Route
}
currentProject={selectedProject}
@@ -1029,7 +1028,7 @@ const App: FunctionComponent = () => {
<IncidentViewStateTimeline
pageRoute={
RouteMap[
PageMap.INCIDENT_VIEW_STATE_TIMELINE
PageMap.INCIDENT_VIEW_STATE_TIMELINE
] as Route
}
currentProject={selectedProject}
@@ -1046,7 +1045,7 @@ const App: FunctionComponent = () => {
<IncidentInternalNote
pageRoute={
RouteMap[
PageMap.INCIDENT_INTERNAL_NOTE
PageMap.INCIDENT_INTERNAL_NOTE
] as Route
}
currentProject={selectedProject}
@@ -1064,7 +1063,7 @@ const App: FunctionComponent = () => {
<IncidentViewCustomFields
pageRoute={
RouteMap[
PageMap.INCIDENT_VIEW_CUSTOM_FIELDS
PageMap.INCIDENT_VIEW_CUSTOM_FIELDS
] as Route
}
currentProject={selectedProject}
@@ -1098,7 +1097,7 @@ const App: FunctionComponent = () => {
<ScheduledMaintenanceEvents
pageRoute={
RouteMap[
PageMap.SCHEDULED_MAINTENANCE_EVENTS
PageMap.SCHEDULED_MAINTENANCE_EVENTS
] as Route
}
currentProject={selectedProject}
@@ -1116,7 +1115,7 @@ const App: FunctionComponent = () => {
<OngoingScheduledMaintenanceEvents
pageRoute={
RouteMap[
PageMap.ONGOING_SCHEDULED_MAINTENANCE_EVENTS
PageMap.ONGOING_SCHEDULED_MAINTENANCE_EVENTS
] as Route
}
currentProject={selectedProject}
@@ -1134,7 +1133,7 @@ const App: FunctionComponent = () => {
<ScheduledMaintenanceEventView
pageRoute={
RouteMap[
PageMap.SCHEDULED_MAINTENANCE_VIEW
PageMap.SCHEDULED_MAINTENANCE_VIEW
] as Route
}
currentProject={selectedProject}
@@ -1152,8 +1151,8 @@ const App: FunctionComponent = () => {
<ScheduledMaintenanceEventsViewCustomFields
pageRoute={
RouteMap[
PageMap
.SCHEDULED_MAINTENANCE_VIEW_CUSTOM_FIELDS
PageMap
.SCHEDULED_MAINTENANCE_VIEW_CUSTOM_FIELDS
] as Route
}
currentProject={selectedProject}
@@ -1171,7 +1170,7 @@ const App: FunctionComponent = () => {
<ScheduledMaintenanceEventViewDelete
pageRoute={
RouteMap[
PageMap.SCHEDULED_MAINTENANCE_VIEW_DELETE
PageMap.SCHEDULED_MAINTENANCE_VIEW_DELETE
] as Route
}
currentProject={selectedProject}
@@ -1189,8 +1188,8 @@ const App: FunctionComponent = () => {
<ScheduledMaintenanceEventViewStateTimeline
pageRoute={
RouteMap[
PageMap
.SCHEDULED_MAINTENANCE_VIEW_STATE_TIMELINE
PageMap
.SCHEDULED_MAINTENANCE_VIEW_STATE_TIMELINE
] as Route
}
currentProject={selectedProject}
@@ -1208,7 +1207,7 @@ const App: FunctionComponent = () => {
<ScheduledMaintenanceEventInternalNote
pageRoute={
RouteMap[
PageMap.SCHEDULED_MAINTENANCE_INTERNAL_NOTE
PageMap.SCHEDULED_MAINTENANCE_INTERNAL_NOTE
] as Route
}
currentProject={selectedProject}
@@ -1226,7 +1225,7 @@ const App: FunctionComponent = () => {
<ScheduledMaintenanceEventPublicNote
pageRoute={
RouteMap[
PageMap.SCHEDULED_MAINTENANCE_PUBLIC_NOTE
PageMap.SCHEDULED_MAINTENANCE_PUBLIC_NOTE
] as Route
}
currentProject={selectedProject}
@@ -1288,7 +1287,7 @@ const App: FunctionComponent = () => {
<SettingsMonitors
pageRoute={
RouteMap[
PageMap.SETTINGS_MONITORS_STATUS
PageMap.SETTINGS_MONITORS_STATUS
] as Route
}
currentProject={selectedProject}
@@ -1306,7 +1305,7 @@ const App: FunctionComponent = () => {
<SettingsIncidents
pageRoute={
RouteMap[
PageMap.SETTINGS_INCIDENTS_STATE
PageMap.SETTINGS_INCIDENTS_STATE
] as Route
}
currentProject={selectedProject}
@@ -1324,7 +1323,7 @@ const App: FunctionComponent = () => {
<SettingsScheduledMaintenanceState
pageRoute={
RouteMap[
PageMap.SETTINGS_SCHEDULED_MAINTENANCE_STATE
PageMap.SETTINGS_SCHEDULED_MAINTENANCE_STATE
] as Route
}
currentProject={selectedProject}
@@ -1352,7 +1351,7 @@ const App: FunctionComponent = () => {
<SettingsIncidentSeverity
pageRoute={
RouteMap[
PageMap.SETTINGS_INCIDENTS_SEVERITY
PageMap.SETTINGS_INCIDENTS_SEVERITY
] as Route
}
currentProject={selectedProject}
@@ -1422,7 +1421,7 @@ const App: FunctionComponent = () => {
<MonitorCustomFields
pageRoute={
RouteMap[
PageMap.SETTINGS_MONITOR_CUSTOM_FIELDS
PageMap.SETTINGS_MONITOR_CUSTOM_FIELDS
] as Route
}
currentProject={selectedProject}
@@ -1440,7 +1439,7 @@ const App: FunctionComponent = () => {
<StatusPageCustomFields
pageRoute={
RouteMap[
PageMap.SETTINGS_STATUS_PAGE_CUSTOM_FIELDS
PageMap.SETTINGS_STATUS_PAGE_CUSTOM_FIELDS
] as Route
}
currentProject={selectedProject}
@@ -1458,8 +1457,8 @@ const App: FunctionComponent = () => {
<ScheduledMaintenanceCustomFields
pageRoute={
RouteMap[
PageMap
.SETTINGS_SCHEDULED_MAINTENANCE_CUSTOM_FIELDS
PageMap
.SETTINGS_SCHEDULED_MAINTENANCE_CUSTOM_FIELDS
] as Route
}
currentProject={selectedProject}
@@ -1477,7 +1476,7 @@ const App: FunctionComponent = () => {
<IncidentCustomFields
pageRoute={
RouteMap[
PageMap.SETTINGS_INCIDENT_CUSTOM_FIELDS
PageMap.SETTINGS_INCIDENT_CUSTOM_FIELDS
] as Route
}
currentProject={selectedProject}
@@ -1507,7 +1506,7 @@ const App: FunctionComponent = () => {
<SettingsInvoices
pageRoute={
RouteMap[
PageMap.SETTINGS_BILLING_INVOICES
PageMap.SETTINGS_BILLING_INVOICES
] as Route
}
currentProject={selectedProject}

View File

@@ -23,7 +23,7 @@ import ComponentLoader from 'CommonUI/src/Components/ComponentLoader/ComponentLo
import ErrorMessage from 'CommonUI/src/Components/ErrorMessage/ErrorMessage';
import EmptyState from 'CommonUI/src/Components/EmptyState/EmptyState';
import ModelTable from 'CommonUI/src/Components/ModelTable/ModelTable';
import MonitorProbe from 'Model/Models/MonitorProbe'
import MonitorProbe from 'Model/Models/MonitorProbe';
import DashboardNavigation from '../../../Utils/Navigation';
import Probe from 'Model/Models/Probe';
import FieldType from 'CommonUI/src/Components/Types/FieldType';
@@ -93,109 +93,110 @@ const MonitorProbes: FunctionComponent<PageComponentProps> = (
<>
This is a manual monitor. It does not monitor
anything and so, it cannot have monitorting probes
set. You can have monitoring probes on other
monitor types.{' '}
set. You can have monitoring probes on other monitor
types.{' '}
</>
}
/>
);
}
return (
<ModelTable<MonitorProbe>
modelType={MonitorProbe}
query={{
projectId: DashboardNavigation.getProjectId()?.toString(),
monitorId: modelId.toString(),
}}
onBeforeCreate={(item: MonitorProbe): MonitorProbe => {
item.monitorId = modelId;
item.projectId = DashboardNavigation.getProjectId()!;
return (<ModelTable<MonitorProbe>
modelType={MonitorProbe}
query={{
projectId:
DashboardNavigation.getProjectId()?.toString(),
monitorId: modelId.toString(),
}}
onBeforeCreate={(item: MonitorProbe): MonitorProbe => {
item.monitorId = modelId;
item.projectId = DashboardNavigation.getProjectId()!
return item;
}}
id="probes-table"
name="Monitor > Monitor Probes"
isDeleteable={false}
isEditable={true}
isCreateable={true}
cardProps={{
icon: IconProp.Signal,
title: 'Probes',
description:
'List of probes that help you monitor this resource.',
}}
noItemsMessage={'No probes found for this resource. However, you can add some probes to monitor this resource.'}
viewPageRoute={Navigation.getCurrentRoute()}
formFields={[
{
field: {
probe: true,
return item;
}}
id="probes-table"
name="Monitor > Monitor Probes"
isDeleteable={false}
isEditable={true}
isCreateable={true}
cardProps={{
icon: IconProp.Signal,
title: 'Probes',
description:
'List of probes that help you monitor this resource.',
}}
noItemsMessage={
'No probes found for this resource. However, you can add some probes to monitor this resource.'
}
viewPageRoute={Navigation.getCurrentRoute()}
formFields={[
{
field: {
probe: true,
},
title: 'Probe',
stepId: 'incident-details',
description: 'Which probe do you want to use?',
fieldType: FormFieldSchemaType.Dropdown,
dropdownModal: {
type: Probe,
labelField: 'name',
valueField: '_id',
},
required: true,
placeholder: 'Probe',
},
title: 'Probe',
stepId: 'incident-details',
description: 'Which probe do you want to use?',
fieldType: FormFieldSchemaType.Dropdown,
dropdownModal: {
type: Probe,
labelField: 'name',
valueField: '_id',
},
required: true,
placeholder: 'Probe',
},
{
field: {
isEnabled: true,
{
field: {
isEnabled: true,
},
title: 'Enabled',
fieldType: FormFieldSchemaType.Toggle,
required: false,
},
title: 'Enabled',
fieldType: FormFieldSchemaType.Toggle,
required: false,
},
]}
showRefreshButton={true}
showFilterButton={false}
columns={[
{
field: {
probe: {
name: true,
iconFileId: true,
]}
showRefreshButton={true}
showFilterButton={false}
columns={[
{
field: {
probe: {
name: true,
iconFileId: true,
},
},
isFilterable: false,
title: 'Probe',
type: FieldType.Entity,
getElement: (item: JSONObject): ReactElement => {
return (
<ProbeElement
probe={item['probe'] as JSONObject}
/>
);
},
},
isFilterable: false,
title: 'Probe',
type: FieldType.Entity,
getElement: (item: JSONObject): ReactElement => {
return <ProbeElement probe={item['probe'] as JSONObject} />;
{
field: {
lastPingAt: true,
},
title: 'Last Monitored At',
type: FieldType.DateTime,
isFilterable: false,
noValueMessage: 'Will be picked up by this probe soon.',
},
},
{
field: {
lastPingAt: true,
{
field: {
isEnabled: true,
},
title: 'Enabled',
type: FieldType.Boolean,
isFilterable: false,
},
title: 'Last Monitored At',
type: FieldType.DateTime,
isFilterable: false,
noValueMessage: 'Will be picked up by this probe soon.',
},
{
field: {
isEnabled: true,
},
title: 'Enabled',
type: FieldType.Boolean,
isFilterable: false,
},
]}
/>)
]}
/>
);
};
return (

View File

@@ -78,13 +78,11 @@ const DashboardSideMenu: FunctionComponent<ComponentProps> = (
</SideMenuSection>
<SideMenuSection title="Advanced">
<SideMenuItem
<SideMenuItem
link={{
title: 'Probes',
to: RouteUtil.populateRouteParams(
RouteMap[
PageMap.MONITOR_VIEW_PROBES
] as Route,
RouteMap[PageMap.MONITOR_VIEW_PROBES] as Route,
props.modelId
),
}}

View File

@@ -180,7 +180,7 @@ const ProbePage: FunctionComponent<PageComponentProps> = (
placeholder:
'This probe is to monitor all the internal services.',
},
{
field: {
iconFile: true,

View File

@@ -31,7 +31,6 @@ const RouteMap: Dictionary<Route> = {
`/dashboard/${RouteParams.ProjectID}/monitor/${RouteParams.ModelID}/probes`
),
[PageMap.MONITOR_VIEW_CRITERIA]: new Route(
`/dashboard/${RouteParams.ProjectID}/monitor/${RouteParams.ModelID}/criteria`
),

View File

@@ -135,5 +135,5 @@ export default [
ProjectSSO,
StatusPageSSO,
MonitorProbe
MonitorProbe,
];

View File

@@ -429,7 +429,6 @@ export default class Probe extends BaseModel {
})
public isGlobalProbe?: boolean = undefined;
@ColumnAccessControl({
create: [
Permission.ProjectOwner,

View File

@@ -1,9 +1,9 @@
import URL from "Common/Types/API/URL";
import URL from 'Common/Types/API/URL';
import logger from 'CommonServer/Utils/Logger';
import ObjectID from "Common/Types/ObjectID";
import ObjectID from 'Common/Types/ObjectID';
if(!process.env['PROBE_API_URL']){
logger.error("PROBE_API_URL is not set");
if (!process.env['PROBE_API_URL']) {
logger.error('PROBE_API_URL is not set');
process.exit();
}
@@ -11,14 +11,16 @@ export const PROBE_API_URL: URL = URL.fromString(process.env['PROBE_API_URL']);
export const PROBE_NAME: string | null = process.env['PROBE_NAME'] || null;
export const PROBE_DESCRIPTION: string | null = process.env['PROBE_DESCRIPTION'] || null;
export const PROBE_DESCRIPTION: string | null =
process.env['PROBE_DESCRIPTION'] || null;
export const PROBE_ID: ObjectID | null = process.env['PROBE_ID'] ? new ObjectID(process.env['PROBE_ID']) : null;
export const PROBE_ID: ObjectID | null = process.env['PROBE_ID']
? new ObjectID(process.env['PROBE_ID'])
: null;
if(!process.env['PROBE_KEY']){
logger.error("PROBE_KEY is not set");
if (!process.env['PROBE_KEY']) {
logger.error('PROBE_KEY is not set');
process.exit();
}
export const PROBE_KEY: string = process.env['PROBE_KEY'];

View File

@@ -12,9 +12,8 @@ const init: Function = async (): Promise<void> => {
// init the app
await App(APP_NAME);
// Register this probe.
// Register this probe.
await Register.registerProbe();
} catch (err) {
logger.error('App Init Failed:');
logger.error(err);

View File

@@ -1,23 +1,29 @@
import API from "Common/Utils/API";
import RunCron from "../Utils/Cron";
import API from 'Common/Utils/API';
import RunCron from '../Utils/Cron';
import { EVERY_MINUTE } from 'Common/Utils/CronTime';
import { PROBE_API_URL, PROBE_KEY } from "../Config";
import LocalCache from "CommonServer/Infrastructure/LocalCache";
import URL from "Common/Types/API/URL";
import logger from "CommonServer/Utils/Logger";
import { PROBE_API_URL, PROBE_KEY } from '../Config';
import LocalCache from 'CommonServer/Infrastructure/LocalCache';
import URL from 'Common/Types/API/URL';
import logger from 'CommonServer/Utils/Logger';
RunCron('Basic:Alive', {
schedule: EVERY_MINUTE,
runOnStartup: false,
}, async ()=>{
RunCron(
'Basic:Alive',
{
schedule: EVERY_MINUTE,
runOnStartup: false,
},
async () => {
if (!LocalCache.getString('PROBE', 'PROBE_ID')) {
logger.warn('Probe is not registered yet. Skipping alive check.');
return;
}
if(!LocalCache.getString("PROBE", "PROBE_ID")){
logger.warn("Probe is not registered yet. Skipping alive check.");
return;
await API.post(
URL.fromString(PROBE_API_URL.toString()).addRoute('/alive'),
{
probeKey: PROBE_KEY,
probeId: LocalCache.getString('PROBE', 'PROBE_ID'),
}
);
}
await API.post(URL.fromString(PROBE_API_URL.toString()).addRoute("/alive"), {
"probeKey": PROBE_KEY,
"probeId": LocalCache.getString("PROBE", "PROBE_ID"),
});
});
);

View File

@@ -1,27 +1,33 @@
import API from "Common/Utils/API";
import RunCron from "../Utils/Cron";
import API from 'Common/Utils/API';
import RunCron from '../Utils/Cron';
import { EVERY_MINUTE } from 'Common/Utils/CronTime';
import { PROBE_API_URL, PROBE_KEY } from "../Config";
import LocalCache from "CommonServer/Infrastructure/LocalCache";
import URL from "Common/Types/API/URL";
import logger from "CommonServer/Utils/Logger";
import { PROBE_API_URL, PROBE_KEY } from '../Config';
import LocalCache from 'CommonServer/Infrastructure/LocalCache';
import URL from 'Common/Types/API/URL';
import logger from 'CommonServer/Utils/Logger';
RunCron('Basic:Monitor', {
schedule: EVERY_MINUTE,
runOnStartup: false,
}, async ()=>{
RunCron(
'Basic:Monitor',
{
schedule: EVERY_MINUTE,
runOnStartup: false,
},
async () => {
// get a list of monitors from probe-api
// get a list of monitors from probe-api
// for each monitor, ping and then report back to probe-api
// for each monitor, ping and then report back to probe-api
if (!LocalCache.getString('PROBE', 'PROBE_ID')) {
logger.warn('Probe is not registered yet. Skipping alive check.');
return;
}
if(!LocalCache.getString("PROBE", "PROBE_ID")){
logger.warn("Probe is not registered yet. Skipping alive check.");
return;
await API.post(
URL.fromString(PROBE_API_URL.toString()).addRoute('/alive'),
{
probeKey: PROBE_KEY,
probeId: LocalCache.getString('PROBE', 'PROBE_ID'),
}
);
}
await API.post(URL.fromString(PROBE_API_URL.toString()).addRoute("/alive"), {
"probeKey": PROBE_KEY,
"probeId": LocalCache.getString("PROBE", "PROBE_ID"),
});
});
);

View File

@@ -1,43 +1,55 @@
import API from "Common/Utils/API";
import { PROBE_API_URL, PROBE_DESCRIPTION, PROBE_ID, PROBE_KEY, PROBE_NAME } from "../Config";
import URL from "Common/Types/API/URL";
import { ClusterKey, hasClusterKey } from "CommonServer/Config";
import logger from "CommonServer/Utils/Logger";
import HTTPResponse from "Common/Types/API/HTTPResponse";
import { JSONObject } from "Common/Types/JSON";
import LocalCache from "CommonServer/Infrastructure/LocalCache";
import API from 'Common/Utils/API';
import {
PROBE_API_URL,
PROBE_DESCRIPTION,
PROBE_ID,
PROBE_KEY,
PROBE_NAME,
} from '../Config';
import URL from 'Common/Types/API/URL';
import { ClusterKey, hasClusterKey } from 'CommonServer/Config';
import logger from 'CommonServer/Utils/Logger';
import HTTPResponse from 'Common/Types/API/HTTPResponse';
import { JSONObject } from 'Common/Types/JSON';
import LocalCache from 'CommonServer/Infrastructure/LocalCache';
export default class Register {
public static async registerProbe(): Promise<void> {
if (hasClusterKey) {
const resullt: HTTPResponse<JSONObject> = await API.post(
URL.fromString(PROBE_API_URL.toString()).addRoute('/register'),
{
probeKey: PROBE_KEY,
probeName: PROBE_NAME,
probeDescription: PROBE_DESCRIPTION,
clusterKey: ClusterKey.toString(),
}
);
if(hasClusterKey){
const resullt: HTTPResponse<JSONObject> = await API.post(URL.fromString(PROBE_API_URL.toString()).addRoute("/register"), {
"probeKey": PROBE_KEY,
"probeName": PROBE_NAME,
"probeDescription": PROBE_DESCRIPTION,
"clusterKey": ClusterKey.toString()
});
if(resullt.isSuccess()){
const probeId = resullt.data['_id'];
LocalCache.setString("PROBE", "PROBE_ID", probeId as string);
if (resullt.isSuccess()) {
const probeId: string = resullt.data['_id'] as string;
LocalCache.setString('PROBE', 'PROBE_ID', probeId as string);
}
}else{
} else {
// validate probe.
if(!PROBE_ID){
logger.error("PROBE_ID or ONEUPTIME_SECRET should be set");
if (!PROBE_ID) {
logger.error('PROBE_ID or ONEUPTIME_SECRET should be set');
return process.exit();
}
await API.post(URL.fromString(PROBE_API_URL.toString()).addRoute("/alive"), {
"probeKey": PROBE_KEY.toString(),
"probeId": PROBE_ID.toString(),
})
await API.post(
URL.fromString(PROBE_API_URL.toString()).addRoute('/alive'),
{
probeKey: PROBE_KEY.toString(),
probeId: PROBE_ID.toString(),
}
);
LocalCache.setString("PROBE", "PROBE_ID", PROBE_ID.toString() as string);
LocalCache.setString(
'PROBE',
'PROBE_ID',
PROBE_ID.toString() as string
);
}
}
}
}

View File

@@ -9,7 +9,6 @@ const RunCron: Function = (
},
runFunction: Function
): void => {
cron.schedule(options.schedule, async () => {
try {
logger.info(`Job ${jobName} Start`);
@@ -21,7 +20,7 @@ const RunCron: Function = (
}
});
if(options.runOnStartup) {
if (options.runOnStartup) {
runFunction();
}
};

View File

@@ -18,8 +18,7 @@ router.post(
next: NextFunction
): Promise<void> => {
try {
// middleware marks the probe as alive.
// middleware marks the probe as alive.
// so we dont need to do anything here.
return Response.sendEmptyResponse(req, res);
} catch (err) {

View File

@@ -12,9 +12,10 @@ import QueryHelper from 'CommonServer/Types/Database/QueryHelper';
import OneUptimeDate from 'Common/Types/Date';
import { ProbeExpressRequest } from '../Types/Request';
import BadDataException from 'Common/Types/Exception/BadDataException';
import CronTab from "CommonServer/Utils/CronTab"
import CronTab from 'CommonServer/Utils/CronTab';
import Monitor from 'Model/Models/Monitor';
import PositiveNumber from 'Common/Types/PositiveNumber';
import { JSONObject } from 'Common/Types/JSON';
const router: ExpressRouter = Express.getRouter();
@@ -27,12 +28,13 @@ router.post(
next: NextFunction
): Promise<void> => {
try {
const data = req.body;
const limit = data['limit'] as number || 100;
const data: JSONObject = req.body;
const limit: number = (data['limit'] as number) || 100;
if(!(req as ProbeExpressRequest).probe || !(req as ProbeExpressRequest).probe?.id){
if (
!(req as ProbeExpressRequest).probe ||
!(req as ProbeExpressRequest).probe?.id
) {
return Response.sendErrorResponse(
req,
res,
@@ -41,55 +43,65 @@ router.post(
}
//get list of monitors to be monitored
const monitorProbes: Array<MonitorProbe> = await MonitorProbeService.findBy({
query: {
probeId: ((req as ProbeExpressRequest).probe)!.id!,
isEnabled: true,
nextPingAt: QueryHelper.lessThanEqualTo(
OneUptimeDate.getCurrentDate()
)
},
skip: 0,
limit: limit,
select: {
probeId: true,
monitorId: true
},
populate: {
monitor: {
monitorSteps: true,
monitorType: true,
monitoringInterval: true,
}
},
props: {
isRoot: true
}
});
const monitorProbes: Array<MonitorProbe> =
await MonitorProbeService.findBy({
query: {
probeId: (req as ProbeExpressRequest).probe!.id!,
isEnabled: true,
nextPingAt: QueryHelper.lessThanEqualTo(
OneUptimeDate.getCurrentDate()
),
},
skip: 0,
limit: limit,
select: {
probeId: true,
monitorId: true,
},
populate: {
monitor: {
monitorSteps: true,
monitorType: true,
monitoringInterval: true,
},
},
props: {
isRoot: true,
},
});
// update the lastMonitoredAt field of the monitors
for(const monitorProbe of monitorProbes){
for (const monitorProbe of monitorProbes) {
await MonitorProbeService.updateOneById({
id: monitorProbe.id!,
data: {
lastPingAt: OneUptimeDate.getCurrentDate(),
nextPingAt: CronTab.getNextExecutionTime(monitorProbe?.monitor?.monitoringInterval as string)
nextPingAt: CronTab.getNextExecutionTime(
monitorProbe?.monitor?.monitoringInterval as string
),
},
props: {
isRoot: true
}
isRoot: true,
},
});
}
const monitors: Array<Monitor> = monitorProbes.map((monitorProbe) => {
return monitorProbe.monitor!;
});
const monitors: Array<Monitor> = monitorProbes.map(
(monitorProbe: MonitorProbe) => {
return monitorProbe.monitor!;
}
);
// return the list of monitors to be monitored
return Response.sendEntityArrayResponse(req, res, monitors, new PositiveNumber(monitors.length), Monitor);
return Response.sendEntityArrayResponse(
req,
res,
monitors,
new PositiveNumber(monitors.length),
Monitor
);
} catch (err) {
return next(err);
}

View File

@@ -50,13 +50,12 @@ router.post(
});
if (probe) {
await ProbeService.updateOneById({
id: probe.id!,
data: {
name: data['probeName'] as string,
description: data['probeDescription'] as string,
lastAlive: OneUptimeDate.getCurrentDate()
lastAlive: OneUptimeDate.getCurrentDate(),
},
props: {
isRoot: true,

View File

@@ -1,8 +1,5 @@
import { ClusterKey as ONEUPTIME_SECRET } from 'CommonServer/Config';
import {
ExpressResponse,
NextFunction,
} from 'CommonServer/Utils/Express';
import { ExpressResponse, NextFunction } from 'CommonServer/Utils/Express';
import Response from 'CommonServer/Utils/Response';
import BadDataException from 'Common/Types/Exception/BadDataException';
@@ -28,51 +25,51 @@ export default class ProbeAuthorization {
): Promise<void> {
const data: JSONObject = req.body;
if (!data['probeId'] || !data['probeKey']) {
return Response.sendErrorResponse(
req,
res,
new BadDataException('ProbeId or ProbeKey is missing')
);
}
if (!data['probeId'] || !data['probeKey']) {
return Response.sendErrorResponse(
req,
res,
new BadDataException('ProbeId or ProbeKey is missing')
);
}
const probeId: ObjectID = new ObjectID(data['probeId'] as string);
const probeId: ObjectID = new ObjectID(data['probeId'] as string);
const probeKey: string = data['probeKey'] as string;
const probeKey: string = data['probeKey'] as string;
const probe: Probe | null = await ProbeService.findOneBy({
query: {
_id: probeId.toString(),
key: probeKey,
},
select: {
_id: true,
},
props: {
isRoot: true,
},
});
const probe: Probe | null = await ProbeService.findOneBy({
query: {
_id: probeId.toString(),
key: probeKey,
},
select: {
_id: true,
},
props: {
isRoot: true,
},
});
if (!probe) {
return Response.sendErrorResponse(
req,
res,
new BadDataException('Invalid Probe ID or Probe Key')
);
}
if (!probe) {
return Response.sendErrorResponse(
req,
res,
new BadDataException('Invalid Probe ID or Probe Key')
);
}
await ProbeService.updateOneById({
id: probeId,
data: {
lastAlive: OneUptimeDate.getCurrentDate(),
},
props: {
isRoot: true,
},
});
await ProbeService.updateOneById({
id: probeId,
data: {
lastAlive: OneUptimeDate.getCurrentDate(),
},
props: {
isRoot: true,
},
});
req.probe = probe;
req.probe = probe;
return next();
return next();
}
}

View File

@@ -1,6 +1,6 @@
import { ExpressRequest } from "CommonServer/Utils/Express";
import Probe from "Model/Models/Probe";
import { ExpressRequest } from 'CommonServer/Utils/Express';
import Probe from 'Model/Models/Probe';
export interface ProbeExpressRequest extends ExpressRequest {
probe?: Probe | undefined;
}
}