mirror of
https://github.com/OneUptime/oneuptime.git
synced 2026-04-06 00:32:12 +02:00
completed migration script; completed adding and editing multiple schedules to monitor
This commit is contained in:
@@ -238,23 +238,10 @@ router.post('/:projectId', getUser, isAuthorized, isUserAdmin, async function(
|
||||
data.projectId = projectId;
|
||||
data.thirdPartyVariable = [data.name];
|
||||
const monitor = await MonitorService.create(data);
|
||||
if (data.callScheduleId) {
|
||||
const schedule = await ScheduleService.findOneBy({
|
||||
_id: data.callScheduleId,
|
||||
});
|
||||
let monitors = schedule.monitorIds;
|
||||
if (monitors.length > 0) {
|
||||
monitors.push({ _id: monitor._id, name: monitor.name });
|
||||
} else {
|
||||
monitors = Array(monitor._id);
|
||||
}
|
||||
const scheduleData = {
|
||||
projectId: projectId,
|
||||
monitorIds: monitors,
|
||||
};
|
||||
await ScheduleService.updateOneBy(
|
||||
{ _id: data.callScheduleId },
|
||||
scheduleData
|
||||
if (data.callScheduleIds && data.callScheduleIds.length) {
|
||||
await ScheduleService.addMonitorToSchedules(
|
||||
data.callScheduleIds,
|
||||
monitor._id
|
||||
);
|
||||
}
|
||||
|
||||
@@ -360,6 +347,15 @@ router.put(
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
await ScheduleService.deleteMonitor(req.params.monitorId);
|
||||
if (data.callScheduleIds && data.callScheduleIds.length) {
|
||||
await ScheduleService.addMonitorToSchedules(
|
||||
data.callScheduleIds,
|
||||
req.params.monitorId
|
||||
);
|
||||
}
|
||||
|
||||
let unsetData;
|
||||
if (!data.resourceCategory || data.resourceCategory === '') {
|
||||
unsetData = { resourceCategory: '' };
|
||||
@@ -369,6 +365,7 @@ router.put(
|
||||
data,
|
||||
unsetData
|
||||
);
|
||||
|
||||
if (monitor) {
|
||||
return sendItemResponse(req, res, monitor);
|
||||
} else {
|
||||
|
||||
@@ -61,11 +61,11 @@ const monitorSchema = new Schema({
|
||||
default: Date.now,
|
||||
},
|
||||
criteria: {
|
||||
up: [criterionEventSchema],
|
||||
degraded: [criterionEventSchema],
|
||||
down: [criterionEventSchema],
|
||||
up: { type: [criterionEventSchema], default: [] },
|
||||
degraded: { type: [criterionEventSchema], default: [] },
|
||||
down: { type: [criterionEventSchema], default: [] },
|
||||
},
|
||||
lastMatchedCriterion: criterionEventSchema,
|
||||
lastMatchedCriterion: { type: criterionEventSchema, default: {} },
|
||||
method: String,
|
||||
bodyType: String,
|
||||
formData: [Object],
|
||||
|
||||
@@ -435,8 +435,29 @@ module.exports = {
|
||||
limit,
|
||||
skip
|
||||
);
|
||||
|
||||
const monitorsWithSchedules = await Promise.all(
|
||||
monitors.map(async monitor => {
|
||||
const monitorSchedules = await ScheduleService.findBy(
|
||||
{
|
||||
monitorIds: monitor._id,
|
||||
}
|
||||
);
|
||||
return {
|
||||
...monitor.toObject(),
|
||||
schedules: monitorSchedules,
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
const count = await _this.countBy({ projectId: id });
|
||||
return { monitors, count, _id: id, skip, limit };
|
||||
return {
|
||||
monitors: monitorsWithSchedules,
|
||||
count,
|
||||
_id: id,
|
||||
skip,
|
||||
limit,
|
||||
};
|
||||
})
|
||||
);
|
||||
return subProjectMonitors;
|
||||
|
||||
@@ -137,6 +137,24 @@ module.exports = {
|
||||
}
|
||||
},
|
||||
|
||||
addMonitorToSchedules: async function(scheduleIds, monitorId) {
|
||||
try {
|
||||
await ScheduleModel.updateMany(
|
||||
{
|
||||
_id: { $in: scheduleIds },
|
||||
},
|
||||
{
|
||||
$addToSet: {
|
||||
monitorIds: monitorId,
|
||||
},
|
||||
}
|
||||
);
|
||||
} catch (error) {
|
||||
ErrorService.log('scheduleService.addMonitor', error);
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
|
||||
removeMonitor: async function(monitorId) {
|
||||
try {
|
||||
const schedule = await ScheduleModel.findOneAndUpdate(
|
||||
@@ -242,7 +260,7 @@ module.exports = {
|
||||
|
||||
deleteMonitor: async function(monitorId) {
|
||||
try {
|
||||
await ScheduleModel.update(
|
||||
await ScheduleModel.updateMany(
|
||||
{ deleted: false },
|
||||
{ $pull: { monitorIds: monitorId } }
|
||||
);
|
||||
|
||||
@@ -981,7 +981,7 @@ describe('SMS/Calls Incident Alerts', function() {
|
||||
const newMonitorId = newMonitor.body._id;
|
||||
|
||||
// let the probe server generate incident
|
||||
await sleep(60 * 1000);
|
||||
await sleep(120 * 1000);
|
||||
|
||||
const { _id: lastIncidentId } = await IncidentService.findOneBy({
|
||||
monitorId: newMonitorId,
|
||||
@@ -1034,7 +1034,7 @@ describe('SMS/Calls Incident Alerts', function() {
|
||||
/*
|
||||
* run the probe server for this test
|
||||
*/
|
||||
this.timeout(120 * 1000);
|
||||
this.timeout(180 * 1000);
|
||||
// first add a team member
|
||||
const userData = {
|
||||
email: `${generateRandomString}@fyipe.com`,
|
||||
@@ -1133,7 +1133,7 @@ describe('SMS/Calls Incident Alerts', function() {
|
||||
const newMonitorId = newMonitor.body._id;
|
||||
|
||||
// let the probe server generate incident
|
||||
await sleep(30 * 1000);
|
||||
await sleep(120 * 1000);
|
||||
|
||||
const { _id: lastIncidentId } = await IncidentService.findOneBy({
|
||||
monitorId: newMonitorId,
|
||||
|
||||
@@ -753,7 +753,7 @@ export function setMonitorCriteria(
|
||||
monitorName,
|
||||
monitorCategory,
|
||||
monitorSubProject,
|
||||
monitorCallSchedule,
|
||||
monitorCallSchedules,
|
||||
monitorSla,
|
||||
incidentCommunicationSla,
|
||||
monitorType
|
||||
@@ -765,7 +765,7 @@ export function setMonitorCriteria(
|
||||
name: monitorName,
|
||||
category: monitorCategory,
|
||||
subProject: monitorSubProject,
|
||||
schedule: monitorCallSchedule,
|
||||
schedules: monitorCallSchedules,
|
||||
type: monitorType,
|
||||
monitorSla,
|
||||
incidentCommunicationSla,
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
formValueSelector,
|
||||
change,
|
||||
isValid,
|
||||
FieldArray,
|
||||
} from 'redux-form';
|
||||
import {
|
||||
createMonitor,
|
||||
@@ -57,6 +58,7 @@ import { UploadFile } from '../basic/UploadFile';
|
||||
import CRITERIA_TYPES from '../../constants/CRITERIA_TYPES';
|
||||
import { Tab, TabList, TabPanel, Tabs } from 'react-tabs';
|
||||
import Fade from 'react-reveal/Fade';
|
||||
import ScheduleInput from '../schedule/ScheduleInput';
|
||||
const selector = formValueSelector('NewMonitor');
|
||||
const dJSON = require('dirty-json');
|
||||
|
||||
@@ -340,7 +342,17 @@ class NewMonitor extends Component {
|
||||
: this.props.type;
|
||||
postObj.resourceCategory =
|
||||
values[`resourceCategory_${this.props.index}`];
|
||||
postObj.callScheduleId = values[`callSchedule_${this.props.index}`];
|
||||
const callSchedules = values[`callSchedules_${this.props.index}`];
|
||||
let monitorSchedules = [];
|
||||
if (callSchedules && callSchedules.length) {
|
||||
monitorSchedules = callSchedules
|
||||
.filter(schedule => Object.values(schedule)[0] === true)
|
||||
.map(schedule => {
|
||||
return Object.keys(schedule)[0];
|
||||
});
|
||||
}
|
||||
|
||||
postObj.callScheduleIds = monitorSchedules;
|
||||
if (postObj.type === 'manual')
|
||||
postObj.data.description =
|
||||
values[`description_${this.props.index}`] || null;
|
||||
@@ -596,7 +608,7 @@ class NewMonitor extends Component {
|
||||
this.props.name,
|
||||
this.props.category,
|
||||
this.props.subProject,
|
||||
this.props.schedule,
|
||||
this.props.monitorSchedules,
|
||||
this.props.monitorSla,
|
||||
this.props.incidentCommunicationSla,
|
||||
value
|
||||
@@ -1856,7 +1868,7 @@ class NewMonitor extends Component {
|
||||
Call Duties
|
||||
</span>
|
||||
</span>
|
||||
<p>
|
||||
<p className="Flex-flex Flex-alignItems--center">
|
||||
<span>
|
||||
Set the
|
||||
configuration
|
||||
@@ -1864,55 +1876,7 @@ class NewMonitor extends Component {
|
||||
Monitor's
|
||||
Call duties.
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="nm-Fieldset-row">
|
||||
<label className="bs-Fieldset-label" />
|
||||
<label className="new-monitor-label">
|
||||
Call Schedule
|
||||
</label>
|
||||
</div>
|
||||
<div className="bs-Fieldset-row">
|
||||
<label className="bs-Fieldset-label" />
|
||||
<div className="bs-Fieldset-fields">
|
||||
<span className="flex">
|
||||
<Field
|
||||
className="db-select-nw"
|
||||
component={
|
||||
RenderSelect
|
||||
}
|
||||
name={`callSchedule_${this.props.index}`}
|
||||
id="callSchedule"
|
||||
placeholder="Call Duty"
|
||||
disabled={
|
||||
requesting
|
||||
}
|
||||
style={{
|
||||
height:
|
||||
'28px',
|
||||
}}
|
||||
options={[
|
||||
{
|
||||
value:
|
||||
'',
|
||||
label:
|
||||
'Select call schedule',
|
||||
},
|
||||
...(schedules &&
|
||||
schedules.length >
|
||||
0
|
||||
? schedules.map(
|
||||
schedule => ({
|
||||
value:
|
||||
schedule._id,
|
||||
label:
|
||||
schedule.name,
|
||||
})
|
||||
)
|
||||
: []),
|
||||
]}
|
||||
/>
|
||||
|
||||
<Tooltip title="Call Schedule">
|
||||
<div>
|
||||
<p>
|
||||
@@ -1947,6 +1911,40 @@ class NewMonitor extends Component {
|
||||
</p>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="bs-Fieldset-row">
|
||||
<label className="bs-Fieldset-label"></label>
|
||||
<div className="bs-Fieldset-fields">
|
||||
<span className="flex">
|
||||
<FieldArray
|
||||
className="db-select-nw"
|
||||
component={
|
||||
ScheduleInput
|
||||
}
|
||||
name={`callSchedules_${this.props.index}`}
|
||||
id="callSchedule"
|
||||
placeholder="Call Duty"
|
||||
disabled={
|
||||
requesting
|
||||
}
|
||||
style={{
|
||||
height:
|
||||
'28px',
|
||||
}}
|
||||
schedules={
|
||||
this
|
||||
.props
|
||||
.schedules
|
||||
}
|
||||
currentProject={
|
||||
this
|
||||
.props
|
||||
.currentProject
|
||||
}
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -2620,7 +2618,7 @@ const mapStateToProps = (state, ownProps) => {
|
||||
const mode = selector(state, 'mode_1000');
|
||||
const authentication = selector(state, 'authentication_1000');
|
||||
const category = selector(state, 'resourceCategory_1000');
|
||||
const schedule = selector(state, 'callSchedule_1000');
|
||||
const monitorSchedules = selector(state, 'callSchedules_1000');
|
||||
const monitorSla = selector(state, 'monitorSla');
|
||||
const incidentCommunicationSla = selector(
|
||||
state,
|
||||
@@ -2663,7 +2661,7 @@ const mapStateToProps = (state, ownProps) => {
|
||||
category,
|
||||
identityFile: state.monitor.file,
|
||||
uploadingIdentityFile: state.monitor.uploadFileRequest,
|
||||
schedule,
|
||||
monitorSchedules,
|
||||
monitorSla,
|
||||
incidentCommunicationSla,
|
||||
subProjects: state.subProject.subProjects.subProjects,
|
||||
@@ -2699,7 +2697,7 @@ const mapStateToProps = (state, ownProps) => {
|
||||
category,
|
||||
identityFile: state.monitor.file,
|
||||
uploadingIdentityFile: state.monitor.uploadFileRequest,
|
||||
schedule,
|
||||
monitorSchedules,
|
||||
monitorSla,
|
||||
incidentCommunicationSla,
|
||||
resourceCategoryList:
|
||||
@@ -2747,7 +2745,7 @@ NewMonitor.propTypes = {
|
||||
authentication: PropTypes.string,
|
||||
category: PropTypes.string,
|
||||
subProject: PropTypes.string,
|
||||
schedule: PropTypes.string,
|
||||
monitorSchedules: PropTypes.array,
|
||||
monitorSla: PropTypes.string,
|
||||
incidentCommunicationSla: PropTypes.string,
|
||||
resourceCategoryList: PropTypes.array,
|
||||
|
||||
@@ -13,6 +13,7 @@ import IsAdminSubProject from '../basic/IsAdminSubProject';
|
||||
import IsOwnerSubProject from '../basic/IsOwnerSubProject';
|
||||
import { logEvent } from '../../analytics';
|
||||
import { SHOULD_LOG_ANALYTICS } from '../../config';
|
||||
import Tooltip from '../basic/Tooltip';
|
||||
|
||||
function submitMonitorForm(values, dispatch, props) {
|
||||
const { subProjectId, scheduleId } = props.match.params;
|
||||
@@ -121,6 +122,32 @@ export function MonitorBox(props) {
|
||||
Schedule Monitors
|
||||
</span>
|
||||
</label>
|
||||
<Tooltip title="Moniors and Criteria Using Schedule">
|
||||
<div>
|
||||
<p>
|
||||
These are the
|
||||
list of monitors
|
||||
and criteria in
|
||||
a monitor using
|
||||
the schedule.
|
||||
Note that if an
|
||||
incident matches
|
||||
a criterion, the
|
||||
schedules
|
||||
associated with
|
||||
that criterion
|
||||
will be
|
||||
executed. If the
|
||||
criterion has no
|
||||
schedules
|
||||
associated, the
|
||||
monitor's
|
||||
schedules will
|
||||
be used.
|
||||
</p>
|
||||
</div>
|
||||
</Tooltip>
|
||||
|
||||
<div className="bs-Fieldset-fields bs-Fieldset-fields--wide">
|
||||
<div
|
||||
className="Box-root"
|
||||
|
||||
@@ -19,12 +19,27 @@ function MonitorInputs({ monitors, subProject, currentProject, schedule }) {
|
||||
...monitor.criteria.up,
|
||||
...monitor.criteria.degraded,
|
||||
...monitor.criteria.down,
|
||||
].forEach(criterion => {
|
||||
].forEach((criterion, index) => {
|
||||
const monitorUpCriteriaCount =
|
||||
monitor.criteria.up.length;
|
||||
const monitorDegradedCriteriaCount =
|
||||
monitor.criteria.degraded.length;
|
||||
const type =
|
||||
index < monitorUpCriteriaCount
|
||||
? 'Up'
|
||||
: index <
|
||||
monitorUpCriteriaCount +
|
||||
monitorDegradedCriteriaCount
|
||||
? 'Degraded'
|
||||
: 'Down';
|
||||
|
||||
if (criterion.scheduleIds.includes(schedule._id)) {
|
||||
criteriaUsingSchedule.push({
|
||||
id: criterion.id,
|
||||
name: `${criterion.name ||
|
||||
'Unnamed Criterion'}`,
|
||||
name: criterion.default
|
||||
? 'Default Criterion'
|
||||
: `${criterion.name ||
|
||||
'Unnamed Criterion'} (${type})`,
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -77,16 +92,19 @@ function MonitorInputs({ monitors, subProject, currentProject, schedule }) {
|
||||
</div>
|
||||
</div>
|
||||
<div className="Box-root Margin-left--32">
|
||||
{criteriaUsingSchedule.map(criterion => {
|
||||
return (
|
||||
<span
|
||||
key={criterion.id}
|
||||
className="bs-Fieldset-explanation"
|
||||
>
|
||||
{criterion.name}
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
<ul>
|
||||
{criteriaUsingSchedule.map(
|
||||
(criterion, index) => {
|
||||
return (
|
||||
<li key={index}>
|
||||
<span className="bs-Fieldset-explanation">
|
||||
{criterion.name}
|
||||
</span>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
)}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -762,6 +762,7 @@ class MonitorView extends React.Component {
|
||||
const mapStateToProps = (state, props) => {
|
||||
const scheduleWarning = [];
|
||||
const { projectId, componentId, monitorId } = props.match.params;
|
||||
const schedules = state.schedule.schedules;
|
||||
|
||||
state.schedule.subProjectSchedules.forEach(item => {
|
||||
item.schedules.forEach(item => {
|
||||
@@ -804,6 +805,18 @@ const mapStateToProps = (state, props) => {
|
||||
initialValues[`subProject_${monitor._id}`] = monitor.projectId._id;
|
||||
initialValues[`resourceCategory_${monitor._id}`] =
|
||||
monitor.resourceCategory && monitor.resourceCategory._id;
|
||||
|
||||
const monitorSchedules = [];
|
||||
if (schedules && schedules.data) {
|
||||
schedules.data.forEach(schedule => {
|
||||
monitorSchedules.push({
|
||||
[schedule._id]: schedule.monitorIds.some(
|
||||
monitorId => monitorId._id === monitor._id
|
||||
),
|
||||
});
|
||||
});
|
||||
}
|
||||
initialValues[`callSchedules_${monitor._id}`] = monitorSchedules;
|
||||
if (
|
||||
monitor.incidentCommunicationSla &&
|
||||
monitor.incidentCommunicationSla._id
|
||||
@@ -874,7 +887,6 @@ const mapStateToProps = (state, props) => {
|
||||
/**
|
||||
* @type { {data : Array}}
|
||||
*/
|
||||
const schedules = state.schedule.schedules;
|
||||
|
||||
if (
|
||||
criterionScheduleIds &&
|
||||
@@ -886,7 +898,7 @@ const mapStateToProps = (state, props) => {
|
||||
|
||||
// for each schedule, check if the criterion is already associated with it
|
||||
schedules.data.forEach(schedule => {
|
||||
const scheduleId = schedule._id.toString();
|
||||
const scheduleId = schedule._id;
|
||||
criterionSchedules.push({
|
||||
[scheduleId]: criterionScheduleIds.includes(
|
||||
scheduleId
|
||||
|
||||
@@ -1127,7 +1127,7 @@ export default function monitor(state = INITIAL_STATE, action) {
|
||||
name_1000: action.payload.name,
|
||||
resourceCategory_1000: action.payload.category,
|
||||
subProject_1000: action.payload.subProject,
|
||||
callSchedule_1000: action.payload.schedule,
|
||||
callSchedules_1000: action.payload.schedules,
|
||||
monitorSla: action.payload.monitorSla,
|
||||
incidentCommunicationSla:
|
||||
action.payload.incidentCommunicationSla,
|
||||
|
||||
82
init-script/scripts/3.0.7778.js
Normal file
82
init-script/scripts/3.0.7778.js
Normal file
@@ -0,0 +1,82 @@
|
||||
const { find, update } = require('../util/db');
|
||||
|
||||
const MONITOR_COLLECTION = 'monitors';
|
||||
|
||||
async function run() {
|
||||
const monitorsWithOldCriteria = await find(MONITOR_COLLECTION, {
|
||||
$or: [
|
||||
{ 'criteria.up': { $not: { $type: 'array' } } },
|
||||
{ 'criteria.degraded': { $not: { $type: 'array' } } },
|
||||
{ 'criteria.down': { $not: { $type: 'array' } } },
|
||||
],
|
||||
});
|
||||
|
||||
monitorsWithOldCriteria.forEach(monitor => {
|
||||
const newUpCriteria = [];
|
||||
const newDegradedCriteria = [];
|
||||
const newDownCriteria = [];
|
||||
|
||||
const newFields = {
|
||||
scheduleIds: [],
|
||||
title: '',
|
||||
description: '',
|
||||
default: false,
|
||||
};
|
||||
|
||||
// add default criterion
|
||||
newDownCriteria.push({
|
||||
createAlert:
|
||||
monitor.criteria && monitor.criteria.down
|
||||
? monitor.criteria.down.createAlert
|
||||
: true,
|
||||
autoAcknowledge:
|
||||
monitor.criteria && monitor.criteria.down
|
||||
? monitor.criteria.down.autoAcknowledge
|
||||
: false,
|
||||
autoResolve:
|
||||
monitor.criteria && monitor.criteria.down
|
||||
? monitor.criteria.down.autoResolve
|
||||
: false,
|
||||
...newFields,
|
||||
default: true,
|
||||
});
|
||||
|
||||
if (monitor.criteria) {
|
||||
if (monitor.criteria.up) {
|
||||
newUpCriteria.push({
|
||||
...monitor.criteria.up,
|
||||
...newFields,
|
||||
name: 'Online',
|
||||
});
|
||||
}
|
||||
if (monitor.criteria.degraded) {
|
||||
newDegradedCriteria.push({
|
||||
...monitor.criteria.degraded,
|
||||
...newFields,
|
||||
name: 'Degraded',
|
||||
});
|
||||
}
|
||||
if (monitor.criteria.down) {
|
||||
newDownCriteria.push({
|
||||
...monitor.criteria.down,
|
||||
...newFields,
|
||||
name: 'Offline',
|
||||
});
|
||||
}
|
||||
}
|
||||
update(
|
||||
MONITOR_COLLECTION,
|
||||
{ _id: monitor._id },
|
||||
{
|
||||
criteria: {
|
||||
up: newUpCriteria,
|
||||
degraded: newDegradedCriteria,
|
||||
down: newDownCriteria,
|
||||
},
|
||||
lastMatchedCriterion: {},
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = run;
|
||||
Reference in New Issue
Block a user