diff --git a/services/nodeping/nodeping-status.service.js b/services/nodeping/nodeping-status.service.js new file mode 100644 index 0000000000000000000000000000000000000000..987e3fb6dc55e92e8c4ba0c50dd4c301fde3a0e0 --- /dev/null +++ b/services/nodeping/nodeping-status.service.js @@ -0,0 +1,105 @@ +'use strict' + +const { BaseJsonService } = require('..') +const Joi = require('joi') + +const rowSchema = Joi.object().keys({ su: Joi.boolean() }) + +const schema = Joi.array() + .items(rowSchema) + .min(1) + +/* + * this is the checkUuid for the NodePing.com (as used on the [example page](https://nodeping.com/reporting.html#results)) + */ +const sampleCheckUuid = 'jkiwn052-ntpp-4lbb-8d45-ihew6d9ucoei' + +class NodePingStatus extends BaseJsonService { + static get category() { + return 'monitoring' + } + + static get defaultBadgeData() { + return { + label: 'Status', + } + } + + static get route() { + return { + base: 'nodeping/status', + pattern: ':checkUuid', + queryParams: ['up_message', 'down_message', 'up_color', 'down_color'], + } + } + + static get examples() { + return [ + { + title: 'NodePing status', + namedParams: { + checkUuid: sampleCheckUuid, + }, + staticPreview: this.render({ status: true }), + }, + { + title: 'NodePing status (customized)', + namedParams: { + checkUuid: sampleCheckUuid, + }, + queryParams: { + up_message: 'Online', + up_color: 'blue', + down_message: 'Offline', + down_color: 'lightgrey', + }, + staticPreview: this.render({ + status: true, + upMessage: 'Online', + upColor: 'blue', + }), + }, + ] + } + + async fetch({ checkUuid }) { + const rows = await this._requestJson({ + schema, + url: `https://nodeping.com/reports/results/${checkUuid}/1`, + options: { + qs: { format: 'json' }, + headers: { + 'cache-control': 'no-cache', + }, + }, + }) + return { status: rows[0].su } + } + + async handle( + { checkUuid }, + { + up_message: upMessage, + down_message: downMessage, + up_color: upColor, + down_color: downColor, + } + ) { + const { status } = await this.fetch({ checkUuid }) + return this.constructor.render({ + status, + upMessage, + downMessage, + upColor, + downColor, + }) + } + + static render({ status, upMessage, downMessage, upColor, downColor }) { + return status + ? { message: upMessage || 'up', color: upColor || 'brightgreen' } + : { message: downMessage || 'down', color: downColor || 'red' } + } +} + +module.exports = NodePingStatus diff --git a/services/nodeping/nodeping-status.tester.js b/services/nodeping/nodeping-status.tester.js new file mode 100644 index 0000000000000000000000000000000000000000..17ee03b0b092f5368ffb4e9a812e24bae1288b9f --- /dev/null +++ b/services/nodeping/nodeping-status.tester.js @@ -0,0 +1,75 @@ +'use strict' + +const Joi = require('joi') + +const t = (module.exports = require('../tester').createServiceTester()) + +t.create('NodePing status - live').get( + '/jkiwn052-ntpp-4lbb-8d45-ihew6d9ucoei.json' +) +Joi.object().keys({ + name: 'Status', + value: Joi.equal('up', 'down').required(), +}) + +t.create('NodePing status - up (mock)') + .get('/jkiwn052-ntpp-4lbb-8d45-ihew6d9ucoei.json') + .intercept(nock => + nock('https://nodeping.com') + .get( + '/reports/results/jkiwn052-ntpp-4lbb-8d45-ihew6d9ucoei/1?format=json' + ) + .reply(200, [{ su: true }]) + ) + .expectJSON({ + name: 'Status', + value: 'up', + }) + +t.create('NodePing status - down (mock)') + .get('/jkiwn052-ntpp-4lbb-8d45-ihew6d9ucoei.json') + .intercept(nock => + nock('https://nodeping.com') + .get( + '/reports/results/jkiwn052-ntpp-4lbb-8d45-ihew6d9ucoei/1?format=json' + ) + .reply(200, [{ su: false }]) + ) + .expectJSON({ + name: 'Status', + value: 'down', + }) + +t.create('NodePing status - custom up color/message') + .get( + '/jkiwn052-ntpp-4lbb-8d45-ihew6d9ucoei.json?style=_shields_test&up_color=blue&up_message=happy' + ) + .intercept(nock => + nock('https://nodeping.com') + .get( + '/reports/results/jkiwn052-ntpp-4lbb-8d45-ihew6d9ucoei/1?format=json' + ) + .reply(200, [{ su: true }]) + ) + .expectJSON({ + name: 'Status', + value: 'happy', + color: 'blue', + }) + +t.create('NodePing status - custom down color/message') + .get( + '/jkiwn052-ntpp-4lbb-8d45-ihew6d9ucoei.json?style=_shields_test&down_color=yellow&down_message=sad' + ) + .intercept(nock => + nock('https://nodeping.com') + .get( + '/reports/results/jkiwn052-ntpp-4lbb-8d45-ihew6d9ucoei/1?format=json' + ) + .reply(200, [{ su: false }]) + ) + .expectJSON({ + name: 'Status', + value: 'sad', + color: 'yellow', + }) diff --git a/services/nodeping/nodeping-uptime.service.js b/services/nodeping/nodeping-uptime.service.js new file mode 100644 index 0000000000000000000000000000000000000000..3b1c8ff5108c8574175b5b2cd48ef7806ff6202c --- /dev/null +++ b/services/nodeping/nodeping-uptime.service.js @@ -0,0 +1,100 @@ +'use strict' + +const { BaseJsonService } = require('..') +const Joi = require('joi') +const { colorScale } = require('../../lib/color-formatters') +const colorFormatter = colorScale([99, 99.5, 100]) + +const rowSchema = Joi.object().keys({ + uptime: Joi.number() + .precision(3) + .min(0) + .max(100), +}) + +const schema = Joi.array() + .items(rowSchema) + .min(1) + +/* + * this is the checkUuid for the NodePing.com (as used on the [example page](https://nodeping.com/reporting.html#results)) + */ +const sampleCheckUuid = 'jkiwn052-ntpp-4lbb-8d45-ihew6d9ucoei' + +// TODO: support for custom # of days +// TODO: support for custom color thresholds +// TODO: support for custom colors +// TODO: support for custom '100%' label +// TODO: support for custom # of decimal places + +class NodePingUptime extends BaseJsonService { + static get category() { + return 'monitoring' + } + + static get defaultBadgeData() { + return { + label: 'Uptime', + } + } + + static get route() { + return { + base: 'nodeping/uptime', + pattern: ':checkUuid', + } + } + + static get examples() { + return [ + { + title: 'NodePing uptime', + namedParams: { + checkUuid: sampleCheckUuid, + }, + staticPreview: this.render({ uptime: 99.999 }), + }, + ] + } + + async fetch({ checkUuid }) { + const thirtyDaysAgo = new Date( + new Date().getTime() - 30 * 24 * 60 * 60 * 1000 + ) + .toISOString() + .slice(0, 10) + + const rows = await this._requestJson({ + schema, + url: `https://nodeping.com/reports/uptime/${checkUuid}`, + options: { + qs: { format: 'json', interval: 'days', start: thirtyDaysAgo }, + headers: { + 'cache-control': 'no-cache', + }, + }, + }) + return { uptime: rows[rows.length - 1].uptime } + } + + async handle({ checkUuid }) { + const { uptime } = await this.fetch({ checkUuid }) + return this.constructor.render({ uptime }) + } + + static formatPercentage(uptime) { + if (uptime === 100.0) { + return '100%' + } + return `${uptime.toFixed(3)}%` + } + + static render({ uptime }) { + return { + message: NodePingUptime.formatPercentage(uptime), + color: colorFormatter(uptime), + } + } +} + +module.exports = NodePingUptime diff --git a/services/nodeping/nodeping-uptime.tester.js b/services/nodeping/nodeping-uptime.tester.js new file mode 100644 index 0000000000000000000000000000000000000000..7ba3021bd38c407831eec9b0bb7d360727193a8b --- /dev/null +++ b/services/nodeping/nodeping-uptime.tester.js @@ -0,0 +1,87 @@ +'use strict' + +const t = (module.exports = require('../tester').createServiceTester()) +const { isPercentage } = require('../test-validators') + +t.create('NodePing uptime - live') + .get('/jkiwn052-ntpp-4lbb-8d45-ihew6d9ucoei.json') + .expectJSONTypes({ + name: 'Uptime', + value: isPercentage, + }) + +t.create('NodePing uptime - 100% (mock)') + .get('/jkiwn052-ntpp-4lbb-8d45-ihew6d9ucoei.json?style=_shields_test') + .intercept(nock => + nock('https://nodeping.com') + .get( + `/reports/uptime/jkiwn052-ntpp-4lbb-8d45-ihew6d9ucoei?format=json&interval=days&start=${new Date( + new Date().getTime() - 30 * 24 * 60 * 60 * 1000 + ) + .toISOString() + .slice(0, 10)}` + ) + .reply(200, [{ uptime: 100 }]) + ) + .expectJSON({ + name: 'Uptime', + value: '100%', + color: 'brightgreen', + }) + +t.create('NodePing uptime - 99.999% (mock)') + .get('/jkiwn052-ntpp-4lbb-8d45-ihew6d9ucoei.json?style=_shields_test') + .intercept(nock => + nock('https://nodeping.com') + .get( + `/reports/uptime/jkiwn052-ntpp-4lbb-8d45-ihew6d9ucoei?format=json&interval=days&start=${new Date( + new Date().getTime() - 30 * 24 * 60 * 60 * 1000 + ) + .toISOString() + .slice(0, 10)}` + ) + .reply(200, [{ uptime: 99.999 }]) + ) + .expectJSON({ + name: 'Uptime', + value: '99.999%', + color: 'green', + }) + +t.create('NodePing uptime - 99.001% (mock)') + .get('/jkiwn052-ntpp-4lbb-8d45-ihew6d9ucoei.json?style=_shields_test') + .intercept(nock => + nock('https://nodeping.com') + .get( + `/reports/uptime/jkiwn052-ntpp-4lbb-8d45-ihew6d9ucoei?format=json&interval=days&start=${new Date( + new Date().getTime() - 30 * 24 * 60 * 60 * 1000 + ) + .toISOString() + .slice(0, 10)}` + ) + .reply(200, [{ uptime: 99.001 }]) + ) + .expectJSON({ + name: 'Uptime', + value: '99.001%', + color: 'yellow', + }) + +t.create('NodePing uptime - 90.001% (mock)') + .get('/jkiwn052-ntpp-4lbb-8d45-ihew6d9ucoei.json?style=_shields_test') + .intercept(nock => + nock('https://nodeping.com') + .get( + `/reports/uptime/jkiwn052-ntpp-4lbb-8d45-ihew6d9ucoei?format=json&interval=days&start=${new Date( + new Date().getTime() - 30 * 24 * 60 * 60 * 1000 + ) + .toISOString() + .slice(0, 10)}` + ) + .reply(200, [{ uptime: 90.001 }]) + ) + .expectJSON({ + name: 'Uptime', + value: '90.001%', + color: 'red', + })