From 11826b4bc3cd3da8b131fe5a3cd59417d8cbf6bd Mon Sep 17 00:00:00 2001 From: Mohamed Awnallah Date: Wed, 27 Dec 2023 16:56:36 +0200 Subject: [PATCH 1/5] Re-configure the regressions in the test cases --- babel.config.js | 12 + package.json | 6 +- src/plugins/NetworkIhr.js | 28 - .../models/AggregatedAlarmsDataModel.js | 149 +---- src/plugins/models/IodaChartDataModel.js | 4 +- .../models/TableAggregatedAlarmsDataModel.js | 4 +- .../TimeSeriesAggregatedAlarmsDataModel.js | 2 +- .../TreeMapAggregatedAlarmsDataModel.js | 2 +- .../WorldMapAggregatedAlarmsDataModel.js | 3 +- src/plugins/models/tests/data.js | 618 ------------------ .../tests/AggregatedAlarmsDataModel.test.js | 8 +- .../tests/AggregatedAlarmsUtils.test.js | 2 +- src/plugins/tests/GripApi.test.js | 62 ++ src/plugins/tests/IodaApi.test.js | 140 ++++ .../tests/IodaChartDataModel.test.js | 4 +- .../TableAggregatedAlarmsDataModel.test.js | 7 +- ...imeSeriesAggregatedAlarmsDataModel.test.js | 5 +- .../TreeMapAggregatedAlarmsDataModel.test.js | 5 +- .../WorldMapAggregatedAlarmsDataModel.test.js | 4 +- src/plugins/tests/resources/data.js | 615 +++++++++++++++++ 20 files changed, 879 insertions(+), 801 deletions(-) create mode 100644 babel.config.js delete mode 100644 src/plugins/NetworkIhr.js delete mode 100644 src/plugins/models/tests/data.js rename src/plugins/{models => }/tests/AggregatedAlarmsDataModel.test.js (99%) rename src/plugins/{utils => }/tests/AggregatedAlarmsUtils.test.js (99%) create mode 100644 src/plugins/tests/GripApi.test.js create mode 100644 src/plugins/tests/IodaApi.test.js rename src/plugins/{models => }/tests/IodaChartDataModel.test.js (99%) rename src/plugins/{models => }/tests/TableAggregatedAlarmsDataModel.test.js (95%) rename src/plugins/{models => }/tests/TimeSeriesAggregatedAlarmsDataModel.test.js (97%) rename src/plugins/{models => }/tests/TreeMapAggregatedAlarmsDataModel.test.js (96%) rename src/plugins/{models => }/tests/WorldMapAggregatedAlarmsDataModel.test.js (93%) create mode 100644 src/plugins/tests/resources/data.js diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 00000000..2d026ca2 --- /dev/null +++ b/babel.config.js @@ -0,0 +1,12 @@ +module.exports = { + presets: [ + [ + '@babel/preset-env', + { + targets: { + node: 'current', + }, + }, + ] + ], +}; \ No newline at end of file diff --git a/package.json b/package.json index bd3df48a..471d1823 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,8 @@ "build": "vite build", "preview": "vite preview", "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path .gitignore", - "format": "prettier --write src/" + "format": "prettier --write src/", + "test": "jest --verbose" }, "dependencies": { "@intlify/unplugin-vue-i18n": "^1.5.0", @@ -21,12 +22,15 @@ "vue-router": "^4.2.5" }, "devDependencies": { + "@babel/preset-env": "^7.23.6", "@quasar/vite-plugin": "^1.6.0", "@rushstack/eslint-patch": "^1.3.3", "@vitejs/plugin-vue": "^4.4.0", "@vue/eslint-config-prettier": "^8.0.0", "eslint": "^8.49.0", "eslint-plugin-vue": "^9.17.0", + "jest": "^29.7.0", + "joi": "^17.11.0", "prettier": "^3.0.3", "sass": "^1.33.0", "stylus": "^0.62.0", diff --git a/src/plugins/NetworkIhr.js b/src/plugins/NetworkIhr.js deleted file mode 100644 index 8fd1602d..00000000 --- a/src/plugins/NetworkIhr.js +++ /dev/null @@ -1,28 +0,0 @@ -import axios from 'axios' - -export async function getNetworkInfo(asnList) { - const API_URL = 'https://ihr.iijlab.net/ihr/api/networks'; - const MAX_ASNS_PER_REQUEST = 30; - - const asnArray = asnList.split(',').map(asn => asn.trim()); - const numRequests = Math.ceil(asnArray.length / MAX_ASNS_PER_REQUEST); - - const requests = []; - for (let i = 0; i < numRequests; i++) { - const startIdx = i * MAX_ASNS_PER_REQUEST; - const endIdx = (i + 1) * MAX_ASNS_PER_REQUEST; - const slicedASNs = asnArray.slice(startIdx, endIdx); - - const params = { number: slicedASNs.join(',') }; - - requests.push( - axios.get(API_URL, { params }) - .then(response => response.data.results) - .catch(error => { - throw error; - }) - ); - } - - return Promise.all(requests).then(resultsArray => resultsArray.flat()) -} \ No newline at end of file diff --git a/src/plugins/models/AggregatedAlarmsDataModel.js b/src/plugins/models/AggregatedAlarmsDataModel.js index e5d0446d..1fef6941 100644 --- a/src/plugins/models/AggregatedAlarmsDataModel.js +++ b/src/plugins/models/AggregatedAlarmsDataModel.js @@ -1,10 +1,8 @@ -import * as GripApiPlugin from '../GripApi' -import * as IodaApiPlugin from '../IodaApi' -import * as AggregatedAlarmsUtils from '../utils/AggregatedAlarmsUtils' -import { getCountryISOCode3, getCountryName } from '../countryName' -import * as NetworkIhr from '../NetworkIhr' -// import getCountryName from '../plugins/countryName' - +import * as GripApiPlugin from '../GripApi'; +import * as IodaApiPlugin from '../IodaApi'; +import * as AsNamesPlugin from '../AsNames'; +import * as AggregatedAlarmsUtils from '../utils/AggregatedAlarmsUtils'; +import { getCountryISOCode3, getCountryName } from '../countryName'; const dataSourcesTransformers = { ihr: { @@ -20,22 +18,23 @@ const dataSourcesTransformers = { let asNamesCountryMappingsResult = {} -export function etl(dataSourcesSelected, dataSources, alarmTypesSelected, groupByKeys, ihrAlarms, externalAlarms, iodaIPAddressFamilies, startTime, endTime) { +export function etl(dataSourcesSelected, dataSources, alarmTypesSelected, groupByKeys, ihrAlarms, externalAlarms, iodaIPAddressFamilies, startUnixTime, endUnixTime) { dataSourcesTransformers.ioda.ipAddressFamilies = iodaIPAddressFamilies return new Promise((resolve, reject) => { - extractAlarms(dataSourcesSelected, alarmTypesSelected, ihrAlarms, externalAlarms, startTime, endTime) + extractAlarms(dataSourcesSelected, alarmTypesSelected, ihrAlarms, externalAlarms, startUnixTime, endUnixTime) .then((extractedAlarms) => transformAlarms(extractedAlarms, dataSourcesSelected, dataSources, alarmTypesSelected, groupByKeys)) .then((alarms) => resolve(alarms)) .catch((error) => reject(error)); }) } -function extractAlarms(dataSourcesSelected, alarmTypesSelected, ihrAlarms, externalAlarms, startTime, endTime) { +function extractAlarms(dataSourcesSelected, alarmTypesSelected, ihrAlarms, externalAlarms, startUnixTime, endUnixTime) { const request = () => { return new Promise((resolve, _) => { let extractedAlarms = { ihr: ihrAlarms } - let gripAlarmsPromise = dataSourcesSelected.grip && !externalAlarms.grip ? GripApiPlugin.getGripAlarms(startTime, endTime) : Promise.resolve([]) - let iodaAlarmsPromise = dataSourcesSelected.ioda && !externalAlarms.ioda ? IodaApiPlugin.getIodaAlarms(startTime, endTime) : Promise.resolve([]) + + let gripAlarmsPromise = dataSourcesSelected.grip && !externalAlarms.grip ? GripApiPlugin.getGripAlarms(new Date(startUnixTime * 1000), new Date(endUnixTime * 1000)) : Promise.resolve([]) + let iodaAlarmsPromise = dataSourcesSelected.ioda && !externalAlarms.ioda ? IodaApiPlugin.getIodaAlarms(new Date(startUnixTime * 1000), new Date(endUnixTime * 1000)) : Promise.resolve([]) Promise.all([gripAlarmsPromise, iodaAlarmsPromise]).then(([gripAlarms, iodaAlarms]) => { if (dataSourcesSelected.grip) { @@ -78,7 +77,7 @@ function dynamicAlarmsTransformation(alarms, dataSourcesSelected, dataSources, a for (const dataSource in dataSourcesSelected) { const isDataSourceSelected = dataSourcesSelected[dataSource] if (isDataSourceSelected) { - const { transformFunc, ipAddressFamilies } = dataSourcesTransformers[dataSource] + const { transformFunc, ipAddressFamilies } = dataSourcesTransformers[dataSource]; const dataSourceAlarmsTransformed = transformFunc(alarms[dataSource], dataSources[dataSource].alarm_types, alarmTypesSelected, groupByKeys, ipAddressFamilies); const dataSourceColumns = AggregatedAlarmsUtils.normalizeColumns(AggregatedAlarmsUtils.filterDictByPrefixes(Object.values(dataSourceAlarmsTransformed)[0], Object.keys(dataSources[dataSource].alarm_types))) const alarmsTransformedColumns = AggregatedAlarmsUtils.normalizeColumns(AggregatedAlarmsUtils.filterDictByPrefixes(Object.values(alarmsTransformed)[0], Object.keys(dataSources).flatMap((dataSource) => Object.keys(dataSources[dataSource].alarm_types)))) @@ -404,122 +403,18 @@ function addASNameAndCountryInfo(alarms) { addASNameAndCountryInfoHelper(alarms, asNamesCountryMappingsResult) resolve(alarms) } else { - addASNameAndCountryIsoCode2(alarms).then((alarmsWithCountryIsoCodes2) => { - asNamesCountryMappingsResult = alarmsWithCountryIsoCodes2 - addASNameAndCountryInfoHelper(alarms, alarmsWithCountryIsoCodes2) - return resolve(alarms) - }).catch(error => { - reject(error) - }) + AsNamesPlugin.getASNamesCountryMappings() + .then((asNamesCountryMappings) => { + asNamesCountryMappingsResult = asNamesCountryMappings + addASNameAndCountryInfoHelper(alarms, asNamesCountryMappings) + return resolve(alarms) + }) + .catch((error) => reject(error)) } }) return request() } -function addASNameAndCountryIsoCode2(alarms) { - const asnNumbers = []; - - for (let asnNumber in alarms) { - const alarm = alarms[asnNumber] - const containsCountryIsoCode2 = alarm.country_iso_code2 - if (!containsCountryIsoCode2 || !isNaN(alarm.asn_name)) { - asnNumbers.push(asnNumber) - } - } - - const needToGetASNamesAndIsoCodes = asnNumbers.length > 0; - if (needToGetASNamesAndIsoCodes) { - const alarmsWithCountryIsoCodes2Promise = getASNamesAndIsoCodes(alarms, asnNumbers) - return alarmsWithCountryIsoCodes2Promise - } else { - return Promise.resolve(alarms) - } -} - -function getASNamesAndIsoCodes(alarms, asnNumbers) { - return new Promise((resolve, reject) => { - const asnNumbersCommaSeparated = asnNumbers.join(','); - getASNameAndCountryIsoCode2Proxy(asnNumbersCommaSeparated) - .then(asnNamesAndIsoCodes2 => { - for (const asnNameAndIsoCode2 of asnNamesAndIsoCodes2) { - const { asn_number: asNumber, asn_name: asName, country_iso_code2: countryIsoCode2 } = asnNameAndIsoCode2; - alarms[asNumber].country_iso_code2 = countryIsoCode2; - alarms[asNumber].asn_name = asName - } - return resolve(alarms); - }) - .catch(error => { - console.error('Error retrieving ASN name and country ISO code:', error); - return reject(error); - }); - }); -} - -function getASNameAndCountryIsoCode2Proxy(asnNumbersCommaSeperated, maxRetries = 5, delay = 500) { - let retries = 0; - - const request = () => { - return new Promise((resolve, reject) => { - getASNameAndCountryIsoCode2(asnNumbersCommaSeperated) - .then(asnNamesAndIsoCodes2 => resolve(asnNamesAndIsoCodes2)) - .catch(error => { - console.error(error) - if (retries < maxRetries) { - retryRequest(asnNumbersCommaSeperated, resolve, reject) - } else { - console.error(`Maximum retries reached for ASN ${asnNumbersCommaSeperated}`) - reject(error); - } - }); - }); - }; - - const retryRequest = (asnNumber, resolve, reject) => { - retries++; - console.log(`Retrying request for ASN ${asnNumber} (Attempt ${retries + 1})...`); - setTimeout(() => { - request().then(resolve).catch(reject); - }, delay); - }; - - return request(); -} - -function getASNameAndCountryIsoCode2(asnNumbersCommaSeperated) { - const asnNamesAndIsoCodes2 = [] - - const request = () => { - return new Promise((resolve, reject) => { - NetworkIhr.getNetworkInfo(asnNumbersCommaSeperated).then((networks) => { - networks.forEach(network => { - for (let asnNumber of asnNumbersCommaSeperated.split(',')) { - if (network.number == asnNumber) { - const countryIsoCode2 = normalizeCountryIsoCode2(network.name) - const asnName = normalizeASName(network.name) - asnNamesAndIsoCodes2.push({ - asn_number: asnNumber, - asn_name: asnName, - country_iso_code2: countryIsoCode2, - }) - } - } - return resolve(asnNamesAndIsoCodes2) - }) - }).catch((error) => reject(error)) - }) - } - - return request(); -} - -function normalizeCountryIsoCode2(asnName) { - return asnName.split(',').splice(-1)[0].trim() -} - -function normalizeASName(asnName) { - return asnName.split(',').splice(0, asnName.split(',').length - 1).join(',').trim() -} - function addASNameAndCountryInfoHelper(alarms, asNamesCountryMappings) { for (const asn in alarms) { const alarm = alarms[asn] @@ -542,9 +437,9 @@ function addASNameAndCountryInfoHelper(alarms, asNamesCountryMappings) { alarm[asn_country_iso_code2_key][i] = country_iso_code2 alarm[asn_country_iso_code3_key][i] = country_iso_code3 } else { - // console.warn(`Hey there! It seems like the Autonomous System Number (ASN) ${asn} is not in our asn country mapping file yet. - // 🌍 You can help us by adding it and contributing to our data quality! - // 💪 Thank you for making our system even better! 🙏`); + console.warn(`Hey there! It seems like the Autonomous System Number (ASN) ${asn} is not in our asn country mapping file yet. + 🌍 You can help us by adding it and contributing to our data quality! + 💪 Thank you for making our system even better! 🙏`); } } } else { diff --git a/src/plugins/models/IodaChartDataModel.js b/src/plugins/models/IodaChartDataModel.js index 5670234a..7ad69dc5 100644 --- a/src/plugins/models/IodaChartDataModel.js +++ b/src/plugins/models/IodaChartDataModel.js @@ -1,4 +1,4 @@ -import * as AggregatedAlarmsUtils from '../utils/AggregatedAlarmsUtils' +import * as AggregatedAlarmsUtils from '../utils/AggregatedAlarmsUtils'; import * as IodaApiPlugin from '../IodaApi'; export function etl(entityType, entityValue, startDateTime, endDateTime, iodaAlarmTypes, sourceParams) { @@ -52,4 +52,4 @@ function transformAlarms(iodaData, iodaAlarmTypes) { } return dataTransformed -} +} \ No newline at end of file diff --git a/src/plugins/models/TableAggregatedAlarmsDataModel.js b/src/plugins/models/TableAggregatedAlarmsDataModel.js index c2eed6d0..b272584e 100644 --- a/src/plugins/models/TableAggregatedAlarmsDataModel.js +++ b/src/plugins/models/TableAggregatedAlarmsDataModel.js @@ -1,5 +1,5 @@ -import * as AggregatedAlarmsUtils from '../utils/AggregatedAlarmsUtils' -import * as AggregatedAlarmsDataModel from './AggregatedAlarmsDataModel' +import * as AggregatedAlarmsUtils from '../utils/AggregatedAlarmsUtils'; +import * as AggregatedAlarmsDataModel from './AggregatedAlarmsDataModel'; const aggregatedFunctions = { total_count: getCount, diff --git a/src/plugins/models/TimeSeriesAggregatedAlarmsDataModel.js b/src/plugins/models/TimeSeriesAggregatedAlarmsDataModel.js index f21224d1..f077e0c6 100644 --- a/src/plugins/models/TimeSeriesAggregatedAlarmsDataModel.js +++ b/src/plugins/models/TimeSeriesAggregatedAlarmsDataModel.js @@ -1,4 +1,4 @@ -import * as AggregatedAlarmUtils from '../utils/AggregatedAlarmsUtils' +import * as AggregatedAlarmUtils from '../utils/AggregatedAlarmsUtils'; export function etl(alarms, aggregatedAttrsZipped, countryName, alarmTypeTitlesMap, legend, isASGranularity) { const asGranularity = switchASGranularity(countryName, isASGranularity) diff --git a/src/plugins/models/TreeMapAggregatedAlarmsDataModel.js b/src/plugins/models/TreeMapAggregatedAlarmsDataModel.js index 4fc67e70..9c15e35e 100644 --- a/src/plugins/models/TreeMapAggregatedAlarmsDataModel.js +++ b/src/plugins/models/TreeMapAggregatedAlarmsDataModel.js @@ -1,4 +1,4 @@ -import * as AggregatedAlarmsUtils from '../utils/AggregatedAlarmsUtils' +import * as AggregatedAlarmsUtils from '../utils/AggregatedAlarmsUtils'; export function etl(alarms, aggregatedAttrsZipped, countryName, alarmTypeTitlesMap, legend, isASGranularity) { const asGranularity = switchASGranularity(countryName, isASGranularity) diff --git a/src/plugins/models/WorldMapAggregatedAlarmsDataModel.js b/src/plugins/models/WorldMapAggregatedAlarmsDataModel.js index a0f6d439..2fbb395a 100644 --- a/src/plugins/models/WorldMapAggregatedAlarmsDataModel.js +++ b/src/plugins/models/WorldMapAggregatedAlarmsDataModel.js @@ -1,5 +1,4 @@ -import * as AggregatedAlarmsUtils from '../utils/AggregatedAlarmsUtils' - +import * as AggregatedAlarmsUtils from '../utils/AggregatedAlarmsUtils'; export function etl(alarms, alarmCountsSelected, alarmTypeTitlesMap) { const alarmCountsByCountry = groupAlarmCountsByCountry(alarms, alarmCountsSelected) diff --git a/src/plugins/models/tests/data.js b/src/plugins/models/tests/data.js deleted file mode 100644 index 92f57901..00000000 --- a/src/plugins/models/tests/data.js +++ /dev/null @@ -1,618 +0,0 @@ - -export const ALARMS = [ - { - 'asn': 1, - 'asn_name': 'LVLT-1', - 'asn_country': 'United States', - 'asn_country_iso_code2': 'US', - 'asn_country_iso_code3': 'USA', - 'moas_asn_attacker': [ - 1 - ], - 'moas_asn_attacker_name': [ - 'LVLT-1' - ], - 'moas_asn_attacker_country': [ - 'United States' - ], - 'moas_asn_attacker_country_iso_code2': [ - 'US' - ], - 'moas_asn_attacker_country_iso_code3': [ - 'USA' - ], - 'moas_asn_attacker_af': [ - '4, 4' - ], - 'moas_asn_attacker_newcomer': [ - true - ], - 'moas_asn_attacker_attacking_prefix': [ - '103.28.85.0/24, 103.98.129.0/24' - ], - 'moas_asn_attacker_trustworthy': [ - true - ], - 'moas_asn_attacker_trustworthy_tag': [ - 'all-newcomers-next-to-an-oldcomer, newcomer-small-asn, rpki-all-newcomer-invalid-roa, rpki-some-newcomer-invalid-roa, not-previously-announced-by-any-newcomer' - ], - 'moas_asn_victim': [ - 58504 - ], - 'moas_asn_victim_name': [ - 'TECHMINDS-NP TECHMINDS NETWORKS PVT. LTD.' - ], - 'moas_asn_victim_country': [ - 'Nepal' - ], - 'moas_asn_victim_country_iso_code2': [ - 'NP' - ], - 'moas_asn_victim_country_iso_code3': [ - 'NPL' - ], - 'moas_asn_victim_newcomer': [ - false - ], - 'moas_asn_victim_trustworthy': [ - true - ], - 'moas_asn_victim_trustworthy_tag': [ - 'all-newcomers-next-to-an-oldcomer, newcomer-small-asn, rpki-all-newcomer-invalid-roa, rpki-some-newcomer-invalid-roa, not-previously-announced-by-any-newcomer' - ], - 'moas_asn_victim_af': [ - '4, 4' - ], - 'moas_timebin': [ - 1697784625 - ], - 'moas_count': [ - 1 - ], - 'moas_severity': [ - 'high' - ], - 'moas_deviation': [ - 80 - ], - 'moas_duration': [ - 5 - ], - 'moas_key': 'asn_attacker', - 'asn_name_truncated': 'LVLT-1 (AS1)', - 'bgp_entity': [ - 1, - 1 - ], - 'bgp_entity_type': [ - 'asn', - 'asn' - ], - 'bgp_entity_name': [ - 'LVLT-1', - 'LVLT-1' - ], - 'bgp_entity_country': [ - 'United States', - 'United States' - ], - 'bgp_entity_country_iso_code2': [ - 'US', - 'US' - ], - 'bgp_entity_country_iso_code3': [ - 'USA', - 'USA' - ], - 'bgp_entity_af': [ - '4, 6', - '4, 6' - ], - 'bgp_entity_ip_count': [ - 11416, - 11416 - ], - 'bgp_entity_alarm_type': [ - 'bgp', - 'bgp' - ], - 'bgp_condition': [ - 'normal', - '< 0.99' - ], - 'bgp_value': [ - 58, - 56 - ], - 'bgp_historical_value': [ - 57, - 57 - ], - 'bgp_severity': [ - 'medium', - 'high' - ], - 'bgp_timebin': [ - 1697781600, - 1697781900 - ], - 'bgp_count': [ - 1, - 1 - ], - 'bgp_key': 'entity' - }, - { - 'asn': 2, - 'asn_name': 'UDEL-DCN', - 'asn_country': 'United States', - 'asn_country_iso_code2': 'US', - 'asn_country_iso_code3': 'USA', - 'moas_asn_attacker': [ - 2 - ], - 'moas_asn_attacker_name': [ - 'UDEL-DCN' - ], - 'moas_asn_attacker_country': [ - 'United States' - ], - 'moas_asn_attacker_country_iso_code2': [ - 'US' - ], - 'moas_asn_attacker_country_iso_code3': [ - 'USA' - ], - 'moas_asn_attacker_af': [ - 4 - ], - 'moas_asn_attacker_newcomer': [ - true - ], - 'moas_asn_attacker_attacking_prefix': [ - '103.120.237.0/24' - ], - 'moas_asn_attacker_trustworthy': [ - true - ], - 'moas_asn_attacker_trustworthy_tag': [ - 'rpki-all-newcomer-invalid-roa, rpki-all-oldcomer-invalid-roa, rpki-some-newcomer-invalid-roa, origin-small-edit-distance, rpki-some-oldcomer-invalid-roa, not-previously-announced-by-any-newcomer' - ], - 'moas_asn_victim': [ - 4 - ], - 'moas_asn_victim_name': [ - 'ISI-AS' - ], - 'moas_asn_victim_country': [ - 'United States' - ], - 'moas_asn_victim_country_iso_code2': [ - 'US' - ], - 'moas_asn_victim_country_iso_code3': [ - 'USA' - ], - 'moas_asn_victim_newcomer': [ - false - ], - 'moas_asn_victim_trustworthy': [ - true - ], - 'moas_asn_victim_trustworthy_tag': [ - 'rpki-all-newcomer-invalid-roa, rpki-all-oldcomer-invalid-roa, rpki-some-newcomer-invalid-roa, origin-small-edit-distance, rpki-some-oldcomer-invalid-roa, not-previously-announced-by-any-newcomer' - ], - 'moas_asn_victim_af': [ - 4 - ], - 'moas_timebin': [ - 1697794226 - ], - 'moas_count': [ - 1 - ], - 'moas_severity': [ - 'high' - ], - 'moas_deviation': [ - 80 - ], - 'moas_duration': [ - 45 - ], - 'moas_key': 'asn_attacker', - 'asn_name_truncated': 'UDEL-DCN (AS2)' - }, - { - 'asn': 27717, - 'asn_name': 'Corporacion Digitel C.A.', - 'asn_country': 'Venezuela', - 'asn_country_iso_code2': 'VE', - 'asn_country_iso_code3': 'VEN', - 'network_delay_startpoint': [ - 27717, - 27717 - ], - 'network_delay_startpoint_type': [ - 'AS', - 'AS' - ], - 'network_delay_startpoint_name': [ - 'Corporacion Digitel C.A.', - 'Corporacion Digitel C.A.' - ], - 'network_delay_startpoint_country': [ - 'Venezuela', - 'Venezuela' - ], - 'network_delay_startpoint_country_iso_code2': [ - 'VE', - 'VE' - ], - 'network_delay_startpoint_country_iso_code3': [ - 'VEN', - 'VEN' - ], - 'network_delay_startpoint_af': [ - 4, - 4 - ], - 'network_delay_endpoint': [ - 3320, - 3320 - ], - 'network_delay_endpoint_type': [ - 'AS', - 'AS' - ], - 'network_delay_endpoint_name': [ - 'DTAG Deutsche Telekom AG', - 'DTAG Deutsche Telekom AG' - ], - 'network_delay_endpoint_country': [ - 'Germany', - 'Germany' - ], - 'network_delay_endpoint_country_iso_code2': [ - 'DE', - 'DE' - ], - 'network_delay_endpoint_country_iso_code3': [ - 'DEU', - 'DEU' - ], - 'network_delay_endpoint_af': [ - 4, - 4 - ], - 'network_delay_count': [ - 1, - 1 - ], - 'network_delay_timebin': [ - 1697829300, - 1697829300 - ], - 'network_delay_severity': [ - 'low', - 'low' - ], - 'network_delay_deviation': [ - 10.0817387384346, - 10.6897085814724 - ], - 'network_delay_key': 'startpoint', - 'asn_name_truncated': 'Corporacio (AS27717)' - } - ] - - export const ALARM_TYPES_MAP = { - 'hegemony': 'AS Dependency', - 'network_delay': 'Network Delay', - 'network_disconnection': 'Network Disconnection', - 'moas': 'MOAS', - 'submoas': 'Sub-MOAS', - 'defcon': 'DEFCON', - 'edges': 'Fake Path', - 'ping_slash24': 'Ping', - 'bgp': 'BGP', - 'ucsd_nt': 'UCSD Telescope', - 'merit_nt': 'Merit Telescope' - } - - export const IHR_ALARMS_MOCKED = [ - { - 'timebin': '2023-10-20T23:45:00Z', - 'originasn': 197150, - 'asn': 12418, - 'deviation': 35.2348037171613, - 'af': 4, - 'asn_name': 'QUANTUM Quantum CJSC, RU', - 'originasn_name': 'MCRBN-AS Federal State Unitary Enterprise of the Order of the Red Banner of Labour "Russian Broad-casting and Notification Network", RU', - 'event_type': 'hegemony' - }, - { - 'timebin': '2023-10-20T23:15:00Z', - 'originasn': 135647, - 'asn': 45355, - 'deviation': 22.9060399467486, - 'af': 4, - 'asn_name': 'DIGICELPACIFIC-1-AP Digicel Fiji Limited, FJ', - 'originasn_name': 'AFL-AS-AP Airports Fiji Limited, FJ', - 'event_type': 'hegemony' - }, - { - 'timebin': '2023-10-20T23:15:00Z', - 'startpoint_type': 'AS', - 'startpoint_name': '8866', - 'startpoint_af': 4, - 'endpoint_type': 'AS', - 'endpoint_name': '42473', - 'endpoint_af': 4, - 'deviation': 11.9389361531127, - 'event_type': 'network_delay' - }, - { - 'timebin': '2023-10-20T23:15:00Z', - 'startpoint_type': 'AS', - 'startpoint_name': '397143', - 'startpoint_af': 4, - 'endpoint_type': 'AS', - 'endpoint_name': '6461', - 'endpoint_af': 4, - 'deviation': 14.6861362079549, - 'event_type': 'network_delay' - }, - { - 'id': 131964651, - 'streamtype': 'asn', - 'streamname': '58224', - 'starttime': '2023-10-20T19:07:00Z', - 'endtime': '2023-10-20T19:07:00Z', - 'avglevel': 12, - 'nbdiscoprobes': 10, - 'totalprobes': 32, - 'ongoing': true, - 'discoprobes': [ - { - 'probe_id': 27080, - 'ipv4': '151.245.9.12', - 'prefixv4': '151.245.8.0/22', - 'event': 131964651, - 'starttime': '2023-10-20T19:07:24Z', - 'endtime': '2023-10-20T19:07:24Z', - 'level': 12, - 'lat': 37.2875, - 'lon': 49.6015 - }, - { - 'probe_id': 26337, - 'ipv4': '151.245.9.12', - 'prefixv4': '151.245.8.0/22', - 'event': 131964651, - 'starttime': '2023-10-20T19:07:02Z', - 'endtime': '2023-10-20T19:07:02Z', - 'level': 12, - 'lat': 37.2705, - 'lon': 49.5785 - }, - { - 'probe_id': 26313, - 'ipv4': '151.245.9.12', - 'prefixv4': '151.245.8.0/22', - 'event': 131964651, - 'starttime': '2023-10-20T19:07:02Z', - 'endtime': '2023-10-20T19:07:02Z', - 'level': 12, - 'lat': 37.2685, - 'lon': 49.5575 - }, - { - 'probe_id': 24749, - 'ipv4': '151.245.9.12', - 'prefixv4': '151.245.8.0/22', - 'event': 131964651, - 'starttime': '2023-10-20T19:07:01Z', - 'endtime': '2023-10-20T19:07:01Z', - 'level': 12, - 'lat': 37.2915, - 'lon': 49.5695 - }, - { - 'probe_id': 26351, - 'ipv4': '151.245.9.12', - 'prefixv4': '151.245.8.0/22', - 'event': 131964651, - 'starttime': '2023-10-20T19:02:34Z', - 'endtime': '2023-10-20T19:02:34Z', - 'level': 12, - 'lat': 37.2775, - 'lon': 49.5995 - }, - { - 'probe_id': 26328, - 'ipv4': '151.245.9.12', - 'prefixv4': '151.245.8.0/22', - 'event': 131964651, - 'starttime': '2023-10-20T19:07:01Z', - 'endtime': '2023-10-20T19:07:01Z', - 'level': 12, - 'lat': 37.2715, - 'lon': 49.5885 - }, - { - 'probe_id': 24801, - 'ipv4': '151.245.9.12', - 'prefixv4': '151.245.8.0/22', - 'event': 131964651, - 'starttime': '2023-10-20T19:07:01Z', - 'endtime': '2023-10-20T19:07:01Z', - 'level': 12, - 'lat': 37.2675, - 'lon': 49.5575 - }, - { - 'probe_id': 24890, - 'ipv4': '151.245.9.12', - 'prefixv4': '151.245.8.0/22', - 'event': 131964651, - 'starttime': '2023-10-20T19:07:01Z', - 'endtime': '2023-10-20T19:07:01Z', - 'level': 12, - 'lat': 37.2675, - 'lon': 49.5915 - }, - { - 'probe_id': 24806, - 'ipv4': '151.245.9.12', - 'prefixv4': '151.245.8.0/22', - 'event': 131964651, - 'starttime': '2023-10-20T19:07:00Z', - 'endtime': '2023-10-20T19:07:00Z', - 'level': 12, - 'lat': 37.2705, - 'lon': 49.5875 - }, - { - 'probe_id': 25072, - 'ipv4': '151.245.9.12', - 'prefixv4': '151.245.8.0/22', - 'event': 131964651, - 'starttime': '2023-10-20T19:07:01Z', - 'endtime': '2023-10-20T19:07:01Z', - 'level': 12, - 'lat': 29.5485, - 'lon': 52.5905 - } - ], - 'duration': null, - 'event_type': 'network_disconnection' - }, - { - 'id': 131964645, - 'streamtype': 'country', - 'streamname': 'IR', - 'starttime': '2023-10-20T19:07:00Z', - 'endtime': '2023-10-20T19:21:33Z', - 'avglevel': 11, - 'nbdiscoprobes': 10, - 'totalprobes': 102, - 'ongoing': false, - 'discoprobes': [ - { - 'probe_id': 27080, - 'ipv4': '151.245.9.12', - 'prefixv4': '151.245.8.0/22', - 'event': 131964645, - 'starttime': '2023-10-20T19:07:24Z', - 'endtime': '2023-10-20T19:12:57Z', - 'level': 11, - 'lat': 37.2875, - 'lon': 49.6015 - }, - { - 'probe_id': 26351, - 'ipv4': '151.245.9.12', - 'prefixv4': '151.245.8.0/22', - 'event': 131964645, - 'starttime': '2023-10-20T19:02:34Z', - 'endtime': '2023-10-20T19:16:16Z', - 'level': 11, - 'lat': 37.2775, - 'lon': 49.5995 - }, - { - 'probe_id': 26337, - 'ipv4': '151.245.9.12', - 'prefixv4': '151.245.8.0/22', - 'event': 131964645, - 'starttime': '2023-10-20T19:07:02Z', - 'endtime': '2023-10-20T19:07:02Z', - 'level': 11, - 'lat': 37.2705, - 'lon': 49.5785 - }, - { - 'probe_id': 26313, - 'ipv4': '151.245.9.12', - 'prefixv4': '151.245.8.0/22', - 'event': 131964645, - 'starttime': '2023-10-20T19:07:02Z', - 'endtime': '2023-10-20T19:07:02Z', - 'level': 11, - 'lat': 37.2685, - 'lon': 49.5575 - }, - { - 'probe_id': 25072, - 'ipv4': '151.245.9.12', - 'prefixv4': '151.245.8.0/22', - 'event': 131964645, - 'starttime': '2023-10-20T19:07:01Z', - 'endtime': '2023-10-20T19:23:18Z', - 'level': 11, - 'lat': 29.5485, - 'lon': 52.5905 - }, - { - 'probe_id': 24890, - 'ipv4': '151.245.9.12', - 'prefixv4': '151.245.8.0/22', - 'event': 131964645, - 'starttime': '2023-10-20T19:07:01Z', - 'endtime': '2023-10-20T19:25:40Z', - 'level': 11, - 'lat': 37.2675, - 'lon': 49.5915 - }, - { - 'probe_id': 24801, - 'ipv4': '151.245.9.12', - 'prefixv4': '151.245.8.0/22', - 'event': 131964645, - 'starttime': '2023-10-20T19:07:01Z', - 'endtime': '2023-10-20T19:19:48Z', - 'level': 11, - 'lat': 37.2675, - 'lon': 49.5575 - }, - { - 'probe_id': 26328, - 'ipv4': '151.245.9.12', - 'prefixv4': '151.245.8.0/22', - 'event': 131964645, - 'starttime': '2023-10-20T19:07:01Z', - 'endtime': '2023-10-20T19:07:01Z', - 'level': 11, - 'lat': 37.2715, - 'lon': 49.5885 - }, - { - 'probe_id': 24749, - 'ipv4': '151.245.9.12', - 'prefixv4': '151.245.8.0/22', - 'event': 131964645, - 'starttime': '2023-10-20T19:07:01Z', - 'endtime': '2023-10-20T19:27:41Z', - 'level': 11, - 'lat': 37.2915, - 'lon': 49.5695 - }, - { - 'probe_id': 24806, - 'ipv4': '151.245.9.12', - 'prefixv4': '151.245.8.0/22', - 'event': 131964645, - 'starttime': '2023-10-20T19:07:00Z', - 'endtime': '2023-10-20T19:07:00Z', - 'level': 11, - 'lat': 37.2705, - 'lon': 49.5875 - } - ], - 'duration': 15, - 'event_type': 'network_disconnection' - } - ] - - \ No newline at end of file diff --git a/src/plugins/models/tests/AggregatedAlarmsDataModel.test.js b/src/plugins/tests/AggregatedAlarmsDataModel.test.js similarity index 99% rename from src/plugins/models/tests/AggregatedAlarmsDataModel.test.js rename to src/plugins/tests/AggregatedAlarmsDataModel.test.js index 8b07ac3d..30b60e4d 100644 --- a/src/plugins/models/tests/AggregatedAlarmsDataModel.test.js +++ b/src/plugins/tests/AggregatedAlarmsDataModel.test.js @@ -1,6 +1,6 @@ -import * as AggregatedAlarmsDataModel from '../AggregatedAlarmsDataModel' -import { ALARMS_INFO } from '../../views/charts/global/AggregatedAlarmsMetadata'; -import { ALARMS, IHR_ALARMS_MOCKED } from './data' +import * as AggregatedAlarmsDataModel from '../models/AggregatedAlarmsDataModel'; +import { ALARMS_INFO } from '../metadata/AggregatedAlarmsMetadata'; +import { ALARMS, IHR_ALARMS_MOCKED } from './resources/data'; const GRIP_ALARMS_MOCKED = [ { @@ -2873,4 +2873,4 @@ describe('filterAlarmsByIpAddressFamily', () => { const result = AggregatedAlarmsDataModel.filterAlarmsByIpAddressFamily(ALARMS, ipAddressFamilies, emptyAggregatedAttrs); expect(result).toHaveLength(0); }); -}) +}) \ No newline at end of file diff --git a/src/plugins/utils/tests/AggregatedAlarmsUtils.test.js b/src/plugins/tests/AggregatedAlarmsUtils.test.js similarity index 99% rename from src/plugins/utils/tests/AggregatedAlarmsUtils.test.js rename to src/plugins/tests/AggregatedAlarmsUtils.test.js index ebba185a..4dfe89d0 100644 --- a/src/plugins/utils/tests/AggregatedAlarmsUtils.test.js +++ b/src/plugins/tests/AggregatedAlarmsUtils.test.js @@ -1,4 +1,4 @@ -import * as AggregatedAlarmsUtils from '../AggregatedAlarmsUtils' +import * as AggregatedAlarmsUtils from '../utils/AggregatedAlarmsUtils' describe('truncateString', () => { test('should truncate a string if it exceeds the max length', () => { diff --git a/src/plugins/tests/GripApi.test.js b/src/plugins/tests/GripApi.test.js new file mode 100644 index 00000000..080b7c38 --- /dev/null +++ b/src/plugins/tests/GripApi.test.js @@ -0,0 +1,62 @@ +import * as GripApiPlugin from '../GripApi'; +import Joi from 'joi'; + +describe('getGripAlarms', () => { + const timeoutMilliseconds = 20000; + it('returns valid JSON data with expected schema', async () => { + const inferenceSchema = Joi.object({ + suspicion_level: Joi.number().required(), + confidence: Joi.number().optional(), + explanation: Joi.string().optional().allow(null, ''), + inference_id: Joi.string().optional().allow(null, ''), + labels: Joi.array().items(Joi.string()).optional(), + }); + + const inferenceResultSchema = Joi.object({ + inferences: Joi.array().items(inferenceSchema).optional().allow(null), + primary_inference: inferenceSchema.required(), + }); + + const summarySchema = Joi.object({ + inference_result: inferenceResultSchema.required(), + tr_worthy: Joi.boolean().required(), + victims: Joi.array().items(Joi.string()).required(), + ases: Joi.array().optional().allow(null), + attackers: Joi.array().optional().allow(null), + newcomers: Joi.array().optional().allow(null), + prefixes: Joi.array().optional().allow(null), + tags: Joi.array().optional().allow(null), + }); + + const expectedSchema = Joi.array().items(Joi.object({ + summary: summarySchema.required(), + last_modified_ts: Joi.number().required(), + event_type: Joi.string().required(), + asinfo: Joi.object().optional().allow(null), + debug: Joi.object().optional().allow(null), + duration: Joi.number().optional().allow(null), + event_metrics: Joi.object().optional().allow(null), + finished_ts: Joi.number().optional().allow(null), + id: Joi.string().optional().allow(null, ''), + insert_ts: Joi.number().optional().allow(null), + pfx_events: Joi.array().optional().allow(null), + tr_metrics: Joi.object().optional().allow(null), + view_ts: Joi.number().optional().allow(null) + })).required() + + const endTime = new Date(); + const startTime = new Date(endTime); + startTime.setHours(endTime.getHours() - 1); + + const timezone = ''; + const minSuspicionLevel = 80; + const maxSuspicionLevel = 100; + const eventType = 'all'; + const onePage = true; + + const result = await GripApiPlugin.getGripAlarms(startTime, endTime, timezone, minSuspicionLevel, maxSuspicionLevel, eventType, onePage) + + const { error } = expectedSchema.validate(result); + expect(error).toBe(undefined); + }, timeoutMilliseconds); +}); \ No newline at end of file diff --git a/src/plugins/tests/IodaApi.test.js b/src/plugins/tests/IodaApi.test.js new file mode 100644 index 00000000..850696f3 --- /dev/null +++ b/src/plugins/tests/IodaApi.test.js @@ -0,0 +1,140 @@ +import * as IodaApiPlugin from '../IodaApi'; +import Joi from 'joi'; + +describe('getIodaAlarms', () => { + const timeoutMilliseconds = 20000; + it('returns valid JSON data with expected schema', async () => { + const entitySchema = Joi.object({ + code: Joi.string().required(), + name: Joi.string().required(), + attrs: Joi.object().optional().allow(null), + type: Joi.string().optional().allow(null, ''), + }) + + const expectedSchema = Joi.array().items( + Joi.object({ + datasource: Joi.string().required(), + entity: entitySchema.required(), + time: Joi.number().integer().required(), + level: Joi.string().required(), + value: Joi.number().required(), + historyValue: Joi.number().required(), + condition: Joi.string().optional().allow(null, ''), + method: Joi.string().optional().allow(null, '') + }) + ); + + const endTime = new Date(); + const startTime = new Date(endTime); + startTime.setHours(endTime.getHours() - 1); + + const result = await IodaApiPlugin.getIodaAlarms(startTime, endTime) + + const { error } = expectedSchema.validate(result); + expect(error).toBe(undefined); + }, timeoutMilliseconds) +}) + +describe('getIodaEntityInfo', () => { + const timeoutMilliseconds = 20000; + let asnIodaEntityInfo; + let countryIodaEntityInfo; + + beforeAll(async () => { + const endDateTime = new Date(); + const startDateTime = new Date(endDateTime); + startDateTime.setHours(endDateTime.getHours() - 24); + + const startUnixTime = Math.floor(startDateTime / 1000); + const endUnixTime = Math.floor(endDateTime / 1000); + + const entityType1 = 'asn'; const entityValue1 = '59127'; const sourceParams1 = 'WEB_SEARCH'; + const entityType2 = 'country'; const entityValue2 = 'US'; const sourceParams2 = 'WEB_SEARCH'; + + [asnIodaEntityInfo, countryIodaEntityInfo] = await Promise.all([ + IodaApiPlugin.getIodaEntityInfo(entityType1, entityValue1, startUnixTime, endUnixTime, sourceParams1), + IodaApiPlugin.getIodaEntityInfo(entityType2, entityValue2, startUnixTime, endUnixTime, sourceParams2), + ]); + }, timeoutMilliseconds); + + it('returns valid JSON data with expected schema', () => { + const val = [ + { + entityType: 'asn', + entityCode: '59127', + entityName: 'AS59127 (NCV)', + entityFqid: 'asn.59127', + datasource: 'merit-nt', + subtype: '', + from: 1698854400, + until: 1698941100, + step: 300, + nativeStep: 300, + values: [] + }, + { + entityType: 'asn', + entityCode: '59127', + entityName: 'AS59127 (NCV)', + entityFqid: 'asn.59127', + datasource: 'bgp', + subtype: '', + from: 1698854400, + until: 1698941100, + step: 300, + nativeStep: 300, + values: [] + }, + { + entityType: 'asn', + entityCode: '59127', + entityName: 'AS59127 (NCV)', + entityFqid: 'asn.59127', + datasource: 'ping-slash24', + subtype: '', + from: 1698854400, + until: 1698941400, + step: 600, + nativeStep: 600, + values: [] + } + ] + + const dataItemSchema = Joi.object({ + entityType: Joi.string().optional().allow(null, ''), + entityCode: Joi.string().optional().allow(null, ''), + entityName: Joi.string().optional().allow(null, ''), + entityFqid: Joi.string().optional().allow(null, ''), + datasource: Joi.string().required(), + subtype: Joi.string().optional().allow(null, ''), + from: Joi.number().required(), + until: Joi.number().required(), + step: Joi.number().optional().allow(null), + nativeStep: Joi.number().required(), + values: Joi.array().items(Joi.number().allow(null)).required(), + }); + + const expectedSchema = Joi.array().items(dataItemSchema); + + const result1 = expectedSchema.validate(asnIodaEntityInfo); + const result2 = expectedSchema.validate(countryIodaEntityInfo); + + expect(result1.error).toBe(undefined); + expect(result2.error).toBe(undefined); + + }) + + it('checks alarm values within the time range', () => { + const alarmTypesData = [...asnIodaEntityInfo, ...countryIodaEntityInfo] + for (const alarmTypeData of alarmTypesData) { + let fromUnixTime = alarmTypeData.from + alarmTypeData.nativeStep + let untilUnixTime = alarmTypeData.until + let counter = 0 + while (fromUnixTime <= untilUnixTime) { + fromUnixTime += alarmTypeData.nativeStep + counter += 1 + } + expect(alarmTypeData.values.length).toBe(counter) + } + }); +}) \ No newline at end of file diff --git a/src/plugins/models/tests/IodaChartDataModel.test.js b/src/plugins/tests/IodaChartDataModel.test.js similarity index 99% rename from src/plugins/models/tests/IodaChartDataModel.test.js rename to src/plugins/tests/IodaChartDataModel.test.js index 8367cae7..20ba29bb 100644 --- a/src/plugins/models/tests/IodaChartDataModel.test.js +++ b/src/plugins/tests/IodaChartDataModel.test.js @@ -1,4 +1,4 @@ -import * as IodaChartDataModel from '../IodaChartDataModel' +import * as IodaChartDataModel from '../models/IodaChartDataModel'; const IODA_ENTITY_INFO_MOCKED = [ { @@ -768,7 +768,7 @@ const IODA_ENTITY_INFO_MOCKED = [ } ] -jest.mock('../../plugins/IodaApi', () => ({ +jest.mock('../IodaApi', () => ({ getIodaEntityInfo: jest.fn().mockResolvedValue(IODA_ENTITY_INFO_MOCKED), })); diff --git a/src/plugins/models/tests/TableAggregatedAlarmsDataModel.test.js b/src/plugins/tests/TableAggregatedAlarmsDataModel.test.js similarity index 95% rename from src/plugins/models/tests/TableAggregatedAlarmsDataModel.test.js rename to src/plugins/tests/TableAggregatedAlarmsDataModel.test.js index deff03e3..89987d41 100644 --- a/src/plugins/models/tests/TableAggregatedAlarmsDataModel.test.js +++ b/src/plugins/tests/TableAggregatedAlarmsDataModel.test.js @@ -1,7 +1,6 @@ -import * as TableAggregatedAlarmsDataModel from '../TableAggregatedAlarmsDataModel' -import { ALARMS_INFO } from '../../views/charts/global/AggregatedAlarmsMetadata'; -import { ALARMS } from './data'; - +import * as TableAggregatedAlarmsDataModel from '../models/TableAggregatedAlarmsDataModel' +import { ALARMS_INFO } from '../metadata/AggregatedAlarmsMetadata'; +import { ALARMS } from './resources/data'; describe('etlTableAggregatedAlarmsDataModel', () => { it('should correctly ETL TableAggregatedAlarmsDataModel when all data sources selected', () => { diff --git a/src/plugins/models/tests/TimeSeriesAggregatedAlarmsDataModel.test.js b/src/plugins/tests/TimeSeriesAggregatedAlarmsDataModel.test.js similarity index 97% rename from src/plugins/models/tests/TimeSeriesAggregatedAlarmsDataModel.test.js rename to src/plugins/tests/TimeSeriesAggregatedAlarmsDataModel.test.js index 35bfb5bd..a3f61874 100644 --- a/src/plugins/models/tests/TimeSeriesAggregatedAlarmsDataModel.test.js +++ b/src/plugins/tests/TimeSeriesAggregatedAlarmsDataModel.test.js @@ -1,6 +1,5 @@ -import * as TimeSeriesAggregatedAlarmsDataModel from '../TimeSeriesAggregatedAlarmsDataModel' -import { ALARMS, ALARM_TYPES_MAP } from './data'; - +import * as TimeSeriesAggregatedAlarmsDataModel from '../models/TimeSeriesAggregatedAlarmsDataModel' +import { ALARMS, ALARM_TYPES_MAP } from './resources/data'; describe('etlTimeSeriesAggregatedAlarmsDataModel', () => { it('should correctly ETL TimeSeriesAggregatedAlarmsDataModel when all data sources selected', () => { diff --git a/src/plugins/models/tests/TreeMapAggregatedAlarmsDataModel.test.js b/src/plugins/tests/TreeMapAggregatedAlarmsDataModel.test.js similarity index 96% rename from src/plugins/models/tests/TreeMapAggregatedAlarmsDataModel.test.js rename to src/plugins/tests/TreeMapAggregatedAlarmsDataModel.test.js index 7e451917..aa31f010 100644 --- a/src/plugins/models/tests/TreeMapAggregatedAlarmsDataModel.test.js +++ b/src/plugins/tests/TreeMapAggregatedAlarmsDataModel.test.js @@ -1,6 +1,5 @@ -import * as TreeMapAggregatedAlarmsDataModel from '../TreeMapAggregatedAlarmsDataModel' -import { ALARMS, ALARM_TYPES_MAP } from './data'; - +import * as TreeMapAggregatedAlarmsDataModel from '../models/TreeMapAggregatedAlarmsDataModel' +import { ALARMS, ALARM_TYPES_MAP } from './resources/data'; describe('etlTreeMapAggregatedAlarmsDataModel', () => { diff --git a/src/plugins/models/tests/WorldMapAggregatedAlarmsDataModel.test.js b/src/plugins/tests/WorldMapAggregatedAlarmsDataModel.test.js similarity index 93% rename from src/plugins/models/tests/WorldMapAggregatedAlarmsDataModel.test.js rename to src/plugins/tests/WorldMapAggregatedAlarmsDataModel.test.js index 7358eef5..9f9ff85a 100644 --- a/src/plugins/models/tests/WorldMapAggregatedAlarmsDataModel.test.js +++ b/src/plugins/tests/WorldMapAggregatedAlarmsDataModel.test.js @@ -1,5 +1,5 @@ -import * as WorldMapAggregatedAlarmsDataModel from '../WorldMapAggregatedAlarmsDataModel' -import { ALARMS, ALARM_TYPES_MAP } from './data'; +import * as WorldMapAggregatedAlarmsDataModel from '../models/WorldMapAggregatedAlarmsDataModel' +import { ALARMS, ALARM_TYPES_MAP } from './resources/data'; describe('etlWorldMapAggregatedAlarmsDataModel', () => { it('should correctly ETL World Map Data Viz when all data sources selected', () => { diff --git a/src/plugins/tests/resources/data.js b/src/plugins/tests/resources/data.js new file mode 100644 index 00000000..71436b66 --- /dev/null +++ b/src/plugins/tests/resources/data.js @@ -0,0 +1,615 @@ +export const ALARMS = [ + { + 'asn': 1, + 'asn_name': 'LVLT-1', + 'asn_country': 'United States', + 'asn_country_iso_code2': 'US', + 'asn_country_iso_code3': 'USA', + 'moas_asn_attacker': [ + 1 + ], + 'moas_asn_attacker_name': [ + 'LVLT-1' + ], + 'moas_asn_attacker_country': [ + 'United States' + ], + 'moas_asn_attacker_country_iso_code2': [ + 'US' + ], + 'moas_asn_attacker_country_iso_code3': [ + 'USA' + ], + 'moas_asn_attacker_af': [ + '4, 4' + ], + 'moas_asn_attacker_newcomer': [ + true + ], + 'moas_asn_attacker_attacking_prefix': [ + '103.28.85.0/24, 103.98.129.0/24' + ], + 'moas_asn_attacker_trustworthy': [ + true + ], + 'moas_asn_attacker_trustworthy_tag': [ + 'all-newcomers-next-to-an-oldcomer, newcomer-small-asn, rpki-all-newcomer-invalid-roa, rpki-some-newcomer-invalid-roa, not-previously-announced-by-any-newcomer' + ], + 'moas_asn_victim': [ + 58504 + ], + 'moas_asn_victim_name': [ + 'TECHMINDS-NP TECHMINDS NETWORKS PVT. LTD.' + ], + 'moas_asn_victim_country': [ + 'Nepal' + ], + 'moas_asn_victim_country_iso_code2': [ + 'NP' + ], + 'moas_asn_victim_country_iso_code3': [ + 'NPL' + ], + 'moas_asn_victim_newcomer': [ + false + ], + 'moas_asn_victim_trustworthy': [ + true + ], + 'moas_asn_victim_trustworthy_tag': [ + 'all-newcomers-next-to-an-oldcomer, newcomer-small-asn, rpki-all-newcomer-invalid-roa, rpki-some-newcomer-invalid-roa, not-previously-announced-by-any-newcomer' + ], + 'moas_asn_victim_af': [ + '4, 4' + ], + 'moas_timebin': [ + 1697784625 + ], + 'moas_count': [ + 1 + ], + 'moas_severity': [ + 'high' + ], + 'moas_deviation': [ + 80 + ], + 'moas_duration': [ + 5 + ], + 'moas_key': 'asn_attacker', + 'asn_name_truncated': 'LVLT-1 (AS1)', + 'bgp_entity': [ + 1, + 1 + ], + 'bgp_entity_type': [ + 'asn', + 'asn' + ], + 'bgp_entity_name': [ + 'LVLT-1', + 'LVLT-1' + ], + 'bgp_entity_country': [ + 'United States', + 'United States' + ], + 'bgp_entity_country_iso_code2': [ + 'US', + 'US' + ], + 'bgp_entity_country_iso_code3': [ + 'USA', + 'USA' + ], + 'bgp_entity_af': [ + '4, 6', + '4, 6' + ], + 'bgp_entity_ip_count': [ + 11416, + 11416 + ], + 'bgp_entity_alarm_type': [ + 'bgp', + 'bgp' + ], + 'bgp_condition': [ + 'normal', + '< 0.99' + ], + 'bgp_value': [ + 58, + 56 + ], + 'bgp_historical_value': [ + 57, + 57 + ], + 'bgp_severity': [ + 'medium', + 'high' + ], + 'bgp_timebin': [ + 1697781600, + 1697781900 + ], + 'bgp_count': [ + 1, + 1 + ], + 'bgp_key': 'entity' + }, + { + 'asn': 2, + 'asn_name': 'UDEL-DCN', + 'asn_country': 'United States', + 'asn_country_iso_code2': 'US', + 'asn_country_iso_code3': 'USA', + 'moas_asn_attacker': [ + 2 + ], + 'moas_asn_attacker_name': [ + 'UDEL-DCN' + ], + 'moas_asn_attacker_country': [ + 'United States' + ], + 'moas_asn_attacker_country_iso_code2': [ + 'US' + ], + 'moas_asn_attacker_country_iso_code3': [ + 'USA' + ], + 'moas_asn_attacker_af': [ + 4 + ], + 'moas_asn_attacker_newcomer': [ + true + ], + 'moas_asn_attacker_attacking_prefix': [ + '103.120.237.0/24' + ], + 'moas_asn_attacker_trustworthy': [ + true + ], + 'moas_asn_attacker_trustworthy_tag': [ + 'rpki-all-newcomer-invalid-roa, rpki-all-oldcomer-invalid-roa, rpki-some-newcomer-invalid-roa, origin-small-edit-distance, rpki-some-oldcomer-invalid-roa, not-previously-announced-by-any-newcomer' + ], + 'moas_asn_victim': [ + 4 + ], + 'moas_asn_victim_name': [ + 'ISI-AS' + ], + 'moas_asn_victim_country': [ + 'United States' + ], + 'moas_asn_victim_country_iso_code2': [ + 'US' + ], + 'moas_asn_victim_country_iso_code3': [ + 'USA' + ], + 'moas_asn_victim_newcomer': [ + false + ], + 'moas_asn_victim_trustworthy': [ + true + ], + 'moas_asn_victim_trustworthy_tag': [ + 'rpki-all-newcomer-invalid-roa, rpki-all-oldcomer-invalid-roa, rpki-some-newcomer-invalid-roa, origin-small-edit-distance, rpki-some-oldcomer-invalid-roa, not-previously-announced-by-any-newcomer' + ], + 'moas_asn_victim_af': [ + 4 + ], + 'moas_timebin': [ + 1697794226 + ], + 'moas_count': [ + 1 + ], + 'moas_severity': [ + 'high' + ], + 'moas_deviation': [ + 80 + ], + 'moas_duration': [ + 45 + ], + 'moas_key': 'asn_attacker', + 'asn_name_truncated': 'UDEL-DCN (AS2)' + }, + { + 'asn': 27717, + 'asn_name': 'Corporacion Digitel C.A.', + 'asn_country': 'Venezuela', + 'asn_country_iso_code2': 'VE', + 'asn_country_iso_code3': 'VEN', + 'network_delay_startpoint': [ + 27717, + 27717 + ], + 'network_delay_startpoint_type': [ + 'AS', + 'AS' + ], + 'network_delay_startpoint_name': [ + 'Corporacion Digitel C.A.', + 'Corporacion Digitel C.A.' + ], + 'network_delay_startpoint_country': [ + 'Venezuela', + 'Venezuela' + ], + 'network_delay_startpoint_country_iso_code2': [ + 'VE', + 'VE' + ], + 'network_delay_startpoint_country_iso_code3': [ + 'VEN', + 'VEN' + ], + 'network_delay_startpoint_af': [ + 4, + 4 + ], + 'network_delay_endpoint': [ + 3320, + 3320 + ], + 'network_delay_endpoint_type': [ + 'AS', + 'AS' + ], + 'network_delay_endpoint_name': [ + 'DTAG Deutsche Telekom AG', + 'DTAG Deutsche Telekom AG' + ], + 'network_delay_endpoint_country': [ + 'Germany', + 'Germany' + ], + 'network_delay_endpoint_country_iso_code2': [ + 'DE', + 'DE' + ], + 'network_delay_endpoint_country_iso_code3': [ + 'DEU', + 'DEU' + ], + 'network_delay_endpoint_af': [ + 4, + 4 + ], + 'network_delay_count': [ + 1, + 1 + ], + 'network_delay_timebin': [ + 1697829300, + 1697829300 + ], + 'network_delay_severity': [ + 'low', + 'low' + ], + 'network_delay_deviation': [ + 10.0817387384346, + 10.6897085814724 + ], + 'network_delay_key': 'startpoint', + 'asn_name_truncated': 'Corporacio (AS27717)' + } +] + +export const ALARM_TYPES_MAP = { + 'hegemony': 'AS Dependency', + 'network_delay': 'Network Delay', + 'network_disconnection': 'Network Disconnection', + 'moas': 'MOAS', + 'submoas': 'Sub-MOAS', + 'defcon': 'DEFCON', + 'edges': 'Fake Path', + 'ping_slash24': 'Ping', + 'bgp': 'BGP', + 'ucsd_nt': 'UCSD Telescope', + 'merit_nt': 'Merit Telescope' +} + +export const IHR_ALARMS_MOCKED = [ + { + 'timebin': '2023-10-20T23:45:00Z', + 'originasn': 197150, + 'asn': 12418, + 'deviation': 35.2348037171613, + 'af': 4, + 'asn_name': 'QUANTUM Quantum CJSC, RU', + 'originasn_name': 'MCRBN-AS Federal State Unitary Enterprise of the Order of the Red Banner of Labour "Russian Broad-casting and Notification Network", RU', + 'event_type': 'hegemony' + }, + { + 'timebin': '2023-10-20T23:15:00Z', + 'originasn': 135647, + 'asn': 45355, + 'deviation': 22.9060399467486, + 'af': 4, + 'asn_name': 'DIGICELPACIFIC-1-AP Digicel Fiji Limited, FJ', + 'originasn_name': 'AFL-AS-AP Airports Fiji Limited, FJ', + 'event_type': 'hegemony' + }, + { + 'timebin': '2023-10-20T23:15:00Z', + 'startpoint_type': 'AS', + 'startpoint_name': '8866', + 'startpoint_af': 4, + 'endpoint_type': 'AS', + 'endpoint_name': '42473', + 'endpoint_af': 4, + 'deviation': 11.9389361531127, + 'event_type': 'network_delay' + }, + { + 'timebin': '2023-10-20T23:15:00Z', + 'startpoint_type': 'AS', + 'startpoint_name': '397143', + 'startpoint_af': 4, + 'endpoint_type': 'AS', + 'endpoint_name': '6461', + 'endpoint_af': 4, + 'deviation': 14.6861362079549, + 'event_type': 'network_delay' + }, + { + 'id': 131964651, + 'streamtype': 'asn', + 'streamname': '58224', + 'starttime': '2023-10-20T19:07:00Z', + 'endtime': '2023-10-20T19:07:00Z', + 'avglevel': 12, + 'nbdiscoprobes': 10, + 'totalprobes': 32, + 'ongoing': true, + 'discoprobes': [ + { + 'probe_id': 27080, + 'ipv4': '151.245.9.12', + 'prefixv4': '151.245.8.0/22', + 'event': 131964651, + 'starttime': '2023-10-20T19:07:24Z', + 'endtime': '2023-10-20T19:07:24Z', + 'level': 12, + 'lat': 37.2875, + 'lon': 49.6015 + }, + { + 'probe_id': 26337, + 'ipv4': '151.245.9.12', + 'prefixv4': '151.245.8.0/22', + 'event': 131964651, + 'starttime': '2023-10-20T19:07:02Z', + 'endtime': '2023-10-20T19:07:02Z', + 'level': 12, + 'lat': 37.2705, + 'lon': 49.5785 + }, + { + 'probe_id': 26313, + 'ipv4': '151.245.9.12', + 'prefixv4': '151.245.8.0/22', + 'event': 131964651, + 'starttime': '2023-10-20T19:07:02Z', + 'endtime': '2023-10-20T19:07:02Z', + 'level': 12, + 'lat': 37.2685, + 'lon': 49.5575 + }, + { + 'probe_id': 24749, + 'ipv4': '151.245.9.12', + 'prefixv4': '151.245.8.0/22', + 'event': 131964651, + 'starttime': '2023-10-20T19:07:01Z', + 'endtime': '2023-10-20T19:07:01Z', + 'level': 12, + 'lat': 37.2915, + 'lon': 49.5695 + }, + { + 'probe_id': 26351, + 'ipv4': '151.245.9.12', + 'prefixv4': '151.245.8.0/22', + 'event': 131964651, + 'starttime': '2023-10-20T19:02:34Z', + 'endtime': '2023-10-20T19:02:34Z', + 'level': 12, + 'lat': 37.2775, + 'lon': 49.5995 + }, + { + 'probe_id': 26328, + 'ipv4': '151.245.9.12', + 'prefixv4': '151.245.8.0/22', + 'event': 131964651, + 'starttime': '2023-10-20T19:07:01Z', + 'endtime': '2023-10-20T19:07:01Z', + 'level': 12, + 'lat': 37.2715, + 'lon': 49.5885 + }, + { + 'probe_id': 24801, + 'ipv4': '151.245.9.12', + 'prefixv4': '151.245.8.0/22', + 'event': 131964651, + 'starttime': '2023-10-20T19:07:01Z', + 'endtime': '2023-10-20T19:07:01Z', + 'level': 12, + 'lat': 37.2675, + 'lon': 49.5575 + }, + { + 'probe_id': 24890, + 'ipv4': '151.245.9.12', + 'prefixv4': '151.245.8.0/22', + 'event': 131964651, + 'starttime': '2023-10-20T19:07:01Z', + 'endtime': '2023-10-20T19:07:01Z', + 'level': 12, + 'lat': 37.2675, + 'lon': 49.5915 + }, + { + 'probe_id': 24806, + 'ipv4': '151.245.9.12', + 'prefixv4': '151.245.8.0/22', + 'event': 131964651, + 'starttime': '2023-10-20T19:07:00Z', + 'endtime': '2023-10-20T19:07:00Z', + 'level': 12, + 'lat': 37.2705, + 'lon': 49.5875 + }, + { + 'probe_id': 25072, + 'ipv4': '151.245.9.12', + 'prefixv4': '151.245.8.0/22', + 'event': 131964651, + 'starttime': '2023-10-20T19:07:01Z', + 'endtime': '2023-10-20T19:07:01Z', + 'level': 12, + 'lat': 29.5485, + 'lon': 52.5905 + } + ], + 'duration': null, + 'event_type': 'network_disconnection' + }, + { + 'id': 131964645, + 'streamtype': 'country', + 'streamname': 'IR', + 'starttime': '2023-10-20T19:07:00Z', + 'endtime': '2023-10-20T19:21:33Z', + 'avglevel': 11, + 'nbdiscoprobes': 10, + 'totalprobes': 102, + 'ongoing': false, + 'discoprobes': [ + { + 'probe_id': 27080, + 'ipv4': '151.245.9.12', + 'prefixv4': '151.245.8.0/22', + 'event': 131964645, + 'starttime': '2023-10-20T19:07:24Z', + 'endtime': '2023-10-20T19:12:57Z', + 'level': 11, + 'lat': 37.2875, + 'lon': 49.6015 + }, + { + 'probe_id': 26351, + 'ipv4': '151.245.9.12', + 'prefixv4': '151.245.8.0/22', + 'event': 131964645, + 'starttime': '2023-10-20T19:02:34Z', + 'endtime': '2023-10-20T19:16:16Z', + 'level': 11, + 'lat': 37.2775, + 'lon': 49.5995 + }, + { + 'probe_id': 26337, + 'ipv4': '151.245.9.12', + 'prefixv4': '151.245.8.0/22', + 'event': 131964645, + 'starttime': '2023-10-20T19:07:02Z', + 'endtime': '2023-10-20T19:07:02Z', + 'level': 11, + 'lat': 37.2705, + 'lon': 49.5785 + }, + { + 'probe_id': 26313, + 'ipv4': '151.245.9.12', + 'prefixv4': '151.245.8.0/22', + 'event': 131964645, + 'starttime': '2023-10-20T19:07:02Z', + 'endtime': '2023-10-20T19:07:02Z', + 'level': 11, + 'lat': 37.2685, + 'lon': 49.5575 + }, + { + 'probe_id': 25072, + 'ipv4': '151.245.9.12', + 'prefixv4': '151.245.8.0/22', + 'event': 131964645, + 'starttime': '2023-10-20T19:07:01Z', + 'endtime': '2023-10-20T19:23:18Z', + 'level': 11, + 'lat': 29.5485, + 'lon': 52.5905 + }, + { + 'probe_id': 24890, + 'ipv4': '151.245.9.12', + 'prefixv4': '151.245.8.0/22', + 'event': 131964645, + 'starttime': '2023-10-20T19:07:01Z', + 'endtime': '2023-10-20T19:25:40Z', + 'level': 11, + 'lat': 37.2675, + 'lon': 49.5915 + }, + { + 'probe_id': 24801, + 'ipv4': '151.245.9.12', + 'prefixv4': '151.245.8.0/22', + 'event': 131964645, + 'starttime': '2023-10-20T19:07:01Z', + 'endtime': '2023-10-20T19:19:48Z', + 'level': 11, + 'lat': 37.2675, + 'lon': 49.5575 + }, + { + 'probe_id': 26328, + 'ipv4': '151.245.9.12', + 'prefixv4': '151.245.8.0/22', + 'event': 131964645, + 'starttime': '2023-10-20T19:07:01Z', + 'endtime': '2023-10-20T19:07:01Z', + 'level': 11, + 'lat': 37.2715, + 'lon': 49.5885 + }, + { + 'probe_id': 24749, + 'ipv4': '151.245.9.12', + 'prefixv4': '151.245.8.0/22', + 'event': 131964645, + 'starttime': '2023-10-20T19:07:01Z', + 'endtime': '2023-10-20T19:27:41Z', + 'level': 11, + 'lat': 37.2915, + 'lon': 49.5695 + }, + { + 'probe_id': 24806, + 'ipv4': '151.245.9.12', + 'prefixv4': '151.245.8.0/22', + 'event': 131964645, + 'starttime': '2023-10-20T19:07:00Z', + 'endtime': '2023-10-20T19:07:00Z', + 'level': 11, + 'lat': 37.2705, + 'lon': 49.5875 + } + ], + 'duration': 15, + 'event_type': 'network_disconnection' + } +] \ No newline at end of file From 4f0e13c66aff49ec7ef0622d780afd7e050fd245 Mon Sep 17 00:00:00 2001 From: Mohamed Awnallah Date: Wed, 27 Dec 2023 17:10:34 +0200 Subject: [PATCH 2/5] Re-configure the documentation. --- src/assets/docs/global_report.md | 208 ++++++++++++++++++ .../aggregated-alarms-architecture.png | Bin .../{documentation => imgs}/disco_AS16322.png | Bin .../dns-anomaly-alarm-type-integration.png | Bin .../forwarding_AS174.png | Bin .../hegemony_AS2497.png | Bin .../linkdelay_AS7922.png | Bin .../netdelay_AS24482.png | Bin src/i18n/locales/en.json | 10 +- src/i18n/locales/jp.json | 10 +- 10 files changed, 218 insertions(+), 10 deletions(-) create mode 100644 src/assets/docs/global_report.md rename src/assets/{documentation => imgs}/aggregated-alarms-architecture.png (100%) rename src/assets/{documentation => imgs}/disco_AS16322.png (100%) rename src/assets/{documentation => imgs}/dns-anomaly-alarm-type-integration.png (100%) rename src/assets/{documentation => imgs}/forwarding_AS174.png (100%) rename src/assets/{documentation => imgs}/hegemony_AS2497.png (100%) rename src/assets/{documentation => imgs}/linkdelay_AS7922.png (100%) rename src/assets/{documentation => imgs}/netdelay_AS24482.png (100%) diff --git a/src/assets/docs/global_report.md b/src/assets/docs/global_report.md new file mode 100644 index 00000000..07fb6af1 --- /dev/null +++ b/src/assets/docs/global_report.md @@ -0,0 +1,208 @@ +# Table of Contents +- [How to Add Alarm Type](#how-to-add-alarm-type) + - [Step 1: Choose Your Data Source](#step-1-choose-your-data-source) + - [Step2: Dataset Requirements](#step2-dataset-requirements) + - [Step3: Adding Alarm Types to the Dashboard](#step3-adding-alarm-types-to-the-dashboard) + - [Step4: Adding IHR DNS Anomaly Alarm Type to the Dashboard (Demo)](#step4-adding-ihr-dns-anomaly-alarm-type-to-the-dashboard-demo) + - [Step4.1: Metadata](#step41-metadata) + - [Step4.2: Extracting the IHR DNS Anomaly Data](#step42-extracting-the-ihr-dns-anomaly-data) + - [Step4.3: Integrating DNS Anomaly Alarms with Other IHR Alarms](#step43-integrating-dns-anomaly-alarms-with-other-ihr-alarms) + - [Step4.4: Successful Integration of DNS Anomaly Alarms into the Dashboard 🚀](#step44-successful-integration-of-dns-anomaly-alarms-into-the-dashboard-) +- [How to Add Data Source](#how-to-add-data-source) +- [How to Change the Selected Alarm Types by Default](#how-to-change-the-selected-alarm-types-by-default) +- [How to Change the Default Group By Keys](#how-to-change-the-default-group-by-keys) +- [How to Modify Text Content in the Dashboard](#how-to-modify-text-content-in-the-dashboard) + - [How to Modify Text Content in the Filters Area and Data Visualizations (WorldMap, TimeSeries, and TreeMap)](#how-to-modify-text-content-in-the-filters-area-and-data-visualizations-worldmap-timeseries-and-treemap) + - [To Change the Data Source Name in the Table Filters Area:](#to-change-the-data-source-name-in-the-table-filters-area) + - [To Alter the Alarm Type Name in the Table Filters Area and Data Visualizations:](#to-alter-the-alarm-type-name-in-the-table-filters-area-and-data-visualizations) + - [To Adjust Group By Key Names in the Table Filters Area:](#to-adjust-group-by-key-names-in-the-table-filters-area) + - [How to Customize Text Content in the Table Data Visualization](#how-to-customize-text-content-in-the-table-data-visualization) + - [To Modify the Text of the Button in the Table Data Visualization:](#to-modify-the-text-of-the-button-in-the-table-data-visualization) + - [To Revise Table Column Names:](#to-revise-table-column-names) + +# How to Add Alarm Type +## Step 1: Choose Your Data Source +Before adding a data source to your dashboard, you need to determine where your data will come from. Common data sources include databases, APIs, spreadsheets, and other data storage systems. Once you've selected your data source, make sure you have the necessary access credentials, API keys, or connection details. +## Step2: Dataset Requirements +Our dashboard is currently designed to work with specific attributes: Autonomous System, Country, Time, and Severity Granularities. To ensure proper functionality across all data visualizations, your dataset must include the following: autonomous system number, country ISO code 3 (mandatory for the world map), timebin (mandatory for the time series), deviation (mandatory for the treemap), and country ISO code 2 (optional but convenient for inclusion). +## Step3: Adding Alarm Types to the Dashboard +To add an alarm type to the dashboard, it's essential to understand the following context: we have approximately 3 data sources and 11 alarm types, with each alarm type considered a data source with its complex schema and time variation. To avoid accidental complexity, we follow the Extract Transform Load (ETL) with Model View Controller (MVC) architecture, allowing each step to evolve independently. Adopting this approach ensures maintainable and testable code over time. + +If the alarm type you want to add is sourced from IHR, it's advisable to use the IHR API Vue.js client to benefit from caching or debouncing API calls. To do this, place the extraction code in the Aggregated Alarms Controller and handle transformation and loading steps in the Aggregated Alarms Data Model. If the alarm type comes from other data sources, perform all ETL steps in the Aggregated Alarms Data Model. +![Aggregated Alarms Architecture](../imgs/aggregated-alarms-architecture.png) + +## Step4: Adding IHR DNS Anomaly Alarm Type to the Dashboard (Demo) +### Step4.1: Metadata +When writing your configuration, pay attention to the `columns`, `name`, and `field` values, ensuring they access the same attribute name. Also, distinguish between the key and alternative key to enable proper grouping by different keys. For example, I distinguished the key as `main_stream` and the alternative key as `alternative_stream`. Make sure that attributes related to each key start with the respective prefix, except for `timebin,` `severity`, `deviation`, and `count`, as they are related to the alarm as a whole and not specific to each key. Review other metadata in the file for a better understanding of the pattern. + +Add the following metadata under the `ihr` data source in the `AggregatedAlarmsMetadata.js` file: +```javascript +dns_anomaly: { + columns: { + dns_anomaly_main_stream: [], + dns_anomaly_main_stream_name: [], + dns_anomaly_main_stream_country: [], + dns_anomaly_main_stream_country_iso_code2: [], + dns_anomaly_main_stream_country_iso_code3: [], + dns_anomaly_main_stream_af: [], + dns_anomaly_alternative_stream: [], + dns_anomaly_alternative_stream_name: [], + dns_anomaly_alternative_stream_country: [], + dns_anomaly_alternative_stream_country_iso_code2: [], + dns_anomaly_alternative_stream_country_iso_code3: [], + dns_anomaly_alternative_stream_af: [], + dns_anomaly_count: [], + dns_anomaly_timebin: [], + dns_anomaly_severity: [], + dns_anomaly_deviation: [] + }, + metadata: { + title: 'DNS Anomaly', + table_button_text: 'DNS Anomaly Alarms', + description: 'DNS Anomaly Alarms', + showHelpModal: false, + default_key: 'main_stream', + group_by_key_options: { origin_stream: 'main_stream', stream: 'alternative_stream' }, + is_default_selected: false, + table_columns: [ + { name: 'overview', label: 'Overview', align: 'center' }, + { name: 'main_stream', required: true, label: 'Origin Stream', align: 'left', field: row => row.main_stream, format: val => `${val}`, sortable: true }, + { name: 'main_stream_name', required: true, label: 'Origin Stream Name', align: 'left', field: row => row.main_stream_name, format: val => `${val}`, sortable: false }, + { name: 'main_stream_af', required: true, label: 'Origin Stream IP Address Family', align: 'left', field: row => row.main_stream_af, format: val => `${val}`, sortable: true }, + { name: 'main_stream_country', required: true, label: 'Origin Stream Country', align: 'left', field: row => row.main_stream_country, format: val => `${val}`, sortable: true }, + { name: 'main_stream_country_iso_code3', required: true, label: 'Origin Stream Country Code', align: 'left', field: row => row.main_stream_country_iso_code3, format: val => `${val}`, sortable: true }, + { name: 'alternative_stream', required: true, label: 'Stream', align: 'left', field: row => row.alternative_stream, format: val => `${val}`, sortable: true }, + { name: 'alternative_stream_name', required: true, label: 'Stream Name', align: 'left', field: row => row.alternative_stream_name, format: val => `${val}`, sortable: false }, + { name: 'alternative_stream_af', required: true, label: 'Stream IP Address Family', align: 'left', field: row => row.alternative_stream_af, format: val => `${val}`, sortable: true }, + { name: 'alternative_stream_country', required: true, label: 'Stream Country', align: 'left', field: row => row.alternative_stream_country, format: val => `${val}`, sortable: false }, + { name: 'alternative_stream_country_iso_code3', required: true, label: 'Stream Country Code', align: 'left', field: row => row.alternative_stream_country_iso_code3, format: val => `${val}`, sortable: true } + ], + table_aggregated_columns: [ + { name: 'total_count', required: true, label: 'Nb. Alarms', align: 'left', field: row => row.total_count, format: val => `${val}`, sortable: true }, + { name: 'high_severity_count', required: true, label: 'Nb. High Severity Alarms', align: 'left', field: row => row.high_severity_count, format: val => `${val}`, sortable: true }, + { name: 'medium_severity_count', required: true, label: 'Nb. Medium Severity Alarms', align: 'left', field: row => row.medium_severity_count, format: val => `${val}`, sortable: true }, + { name: 'low_severity_count', required: true, label: 'Nb. Low Severity Alarms', align: 'left', field: row => row.low_severity_count, format: val => `${val}`, sortable: true }, + { name: 'deviation_median', required: true, label: 'Median Deviation', align: 'left', field: row => row.deviation_median, format: val => `${val}`, sortable: true }, + { name: 'deviation_avg', required: true, label: 'Average Deviation', align: 'left', field: row => row.deviation_avg, format: val => `${val}`, sortable: true } + ] + } +} +``` +### Step4.2: Extracting the IHR DNS Anomaly Data +The DNS anomaly data we want to extract is sourced from IHR. To gain an understanding of the integration process, I've hardcoded simulated data. In the `AggregatedAlarmsController.js` file, please follow these steps to add the DNS anomaly and its related method. Note that the event type is tagged with the `event_type` attribute. +```javascript +... +ihrAlarms: { + hegemony: { + data: null, + extract: this.extractHegemonyAlarms + }, + network_delay: { + data: null, + extract: this.extractNetworkDelayAlarms + }, + network_disconnection: { + data: null + }, + dns_anomaly: { + data: null, + extract: this.extractDNSAnomalyAlarms // Added here + } +} +... +extractDNSAnomalyAlarms() { +if (this.ihrAlarms.dns_anomaly.data !== null) return +const staticData = [{ + "event_type": "dns_anomaly", + "dns_anomaly_main_stream": 27750, + "dns_anomaly_main_stream_type": "AS", + "dns_anomaly_main_stream_name": 27750, + "dns_anomaly_main_stream_country": null, + "dns_anomaly_main_stream_country_iso_code2": null, + "dns_anomaly_main_stream_country_iso_code3": null, + "dns_anomaly_main_stream_af": 4, + "dns_anomaly_alternative_stream": 3333, + "dns_anomaly_alternative_stream_type": "AS", + "dns_anomaly_alternative_stream_name": 3333, + "dns_anomaly_alternative_stream_country": null, + "dns_anomaly_alternative_stream_country_iso_code2": null, + "dns_anomaly_alternative_stream_country_iso_code3": null, + "dns_anomaly_alternative_stream_af": 4, + "dns_anomaly_count": 1, + "dns_anomaly_timebin": 1697845500, + "dns_anomaly_severity": "low", + "dns_anomaly_deviation": 28.4518378612748 + }, + { + "event_type": "dns_anomaly", + "dns_anomaly_main_stream": 3257, + "dns_anomaly_main_stream_type": "AS", + "dns_anomaly_main_stream_name": 3257, + "dns_anomaly_main_stream_country": null, + "dns_anomaly_main_stream_country_iso_code2": null, + "dns_anomaly_main_stream_country_iso_code3": null, + "dns_anomaly_main_stream_af": 4, + "dns_anomaly_alternative_stream": 22646, + "dns_anomaly_alternative_stream_type": "AS", + "dns_anomaly_alternative_stream_name": 22646, + "dns_anomaly_alternative_stream_country": null, + "dns_anomaly_alternative_stream_country_iso_code2": null, + "dns_anomaly_alternative_stream_country_iso_code3": null, + "dns_anomaly_alternative_stream_af": 4, + "dns_anomaly_count": 1, + "dns_anomaly_timebin": 1697845500, + "dns_anomaly_severity": "low", + "dns_anomaly_deviation": 27.9531828230822 + } + ] +} +``` +### Step4.3: Integrating DNS Anomaly Alarms with Other IHR Alarms +In the `AggregatedAlarmsDataModel.js` file, update the `transformIHRAlarms` method to incorporate the DNS anomaly alarms into the aggregation. The following code snippet demonstrates how to join the DNS anomaly alarms with other IHR alarms: +```javascript +const ihrAlarmsJoined = [/*Oher IHR Alarms */, ...dnsAnomalyAlarmsTransformed] +``` + +### Step4.4: Successful Integration of DNS Anomaly Alarms into the Dashboard 🚀 +You can confirm this integration through data visualization, and I've verified it for you. Here's a snapshot of the DNS Anomaly Alarm Type Integration: +![DNS Anomaly Alarm Type Integration](../imgs/dns-anomaly-alarm-type-integration.png) + +# How to Add Data Source +To add a data source effectively, it's important to understand the process of adding an alarm type and how it integrates with other data sources, such as `IHR`, `GRIP`, and `IODA`. Please refer to the sections above for detailed instructions on adding alarm types and the broader integration process. + +# How to Change the Selected Alarm Types by Default +To modify the default selection of alarm types for the data visualizations, simply locate and update the `is_default_selected` attribute within the `AggregatedAlarmsMetadata.js` file. To modify the initial selected alarm type in the table data visualization, simply update `INITIAL_TABLE_ALARM_TYPE_SELECTED` variable in `AggregatedAlarmsController.js` file make sure it matches with the alarm type in `AggregatedAlarmsMetadata.js`. + +# How to Change the Default Group By Keys +To adjust the default group by keys, you can easily do so by modifying the `default_key` attribute in the `AggregatedAlarmsMetadata.js` file to match one of the values listed in the `group_by_key_options` attribute. + +# How to Modify Text Content in the Dashboard +You have the flexibility to customize and alter the text content within the dashboard by making modifications in the `AggregatedAlarmsMetadata.js` file. For more detailed information, please refer to the following sections. + +## How to Modify Text Content in the Filters Area and Data Visualizations (WorldMap, TimeSeries, and TreeMap) + +### To Change the Data Source Name in the Table Filters Area: +Please review and update the `title` attribute within the metadata for the specific data source in the `AggregatedAlarmsMetadata.js` file. + +### To Alter the Alarm Type Name in the Table Filters Area and Data Visualizations: +To modify the Alarm Type name displayed in the table filters area and data visualizations, navigate to the `title` attribute of the respective alarm type in the `AggregatedAlarmsMetadata.js` file. + +### To Adjust Group By Key Names in the Table Filters Area: +To change the names of group by keys in the table filters area, refer to the `group_by_key_options` attribute in the `AggregatedAlarmsMetadata.js` file. Modify the key as needed to match the desired UI appearance. For instance, if you want to change "source" to "source_startpoint," you can update it like this: +From: +```javascript +{ source: 'startpoint', destination: 'endpoint' } +``` +To: +```javascript +{ source_startpoint: 'startpoint', destination: 'endpoint' } +``` +Note: The keys in this context are related to the UI, as they map what appears in the UI to the corresponding dataset elements. + +## How to Customize Text Content in the Table Data Visualization + +### To Modify the Text of the Button in the Table Data Visualization: +- To change the text of the button in the table data visualization, adjust the `table_button_text` attribute within the `AggregatedAlarmsMetadata.js` file. + +### To Revise Table Column Names: +- To update the names of table columns, you can modify the `label` attribute within the `table_columns` and `table_aggregated_columns` in the `AggregatedAlarmsMetadata.js` file to reflect the desired column labels. diff --git a/src/assets/documentation/aggregated-alarms-architecture.png b/src/assets/imgs/aggregated-alarms-architecture.png similarity index 100% rename from src/assets/documentation/aggregated-alarms-architecture.png rename to src/assets/imgs/aggregated-alarms-architecture.png diff --git a/src/assets/documentation/disco_AS16322.png b/src/assets/imgs/disco_AS16322.png similarity index 100% rename from src/assets/documentation/disco_AS16322.png rename to src/assets/imgs/disco_AS16322.png diff --git a/src/assets/documentation/dns-anomaly-alarm-type-integration.png b/src/assets/imgs/dns-anomaly-alarm-type-integration.png similarity index 100% rename from src/assets/documentation/dns-anomaly-alarm-type-integration.png rename to src/assets/imgs/dns-anomaly-alarm-type-integration.png diff --git a/src/assets/documentation/forwarding_AS174.png b/src/assets/imgs/forwarding_AS174.png similarity index 100% rename from src/assets/documentation/forwarding_AS174.png rename to src/assets/imgs/forwarding_AS174.png diff --git a/src/assets/documentation/hegemony_AS2497.png b/src/assets/imgs/hegemony_AS2497.png similarity index 100% rename from src/assets/documentation/hegemony_AS2497.png rename to src/assets/imgs/hegemony_AS2497.png diff --git a/src/assets/documentation/linkdelay_AS7922.png b/src/assets/imgs/linkdelay_AS7922.png similarity index 100% rename from src/assets/documentation/linkdelay_AS7922.png rename to src/assets/imgs/linkdelay_AS7922.png diff --git a/src/assets/documentation/netdelay_AS24482.png b/src/assets/imgs/netdelay_AS24482.png similarity index 100% rename from src/assets/documentation/netdelay_AS24482.png rename to src/assets/imgs/netdelay_AS24482.png diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index 3eafb8fe..1c136a67 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -412,7 +412,7 @@ "2": { "header": "What do the graphs mean?", "img": { - "src": "assets/documentation/hegemony_AS2497.png", + "src": "assets/imgs/hegemony_AS2497.png", "style": "max-width:100%" }, "body": "Let's take a look at the above example which corresponds to results obtained on March 2nd 2020 for AS2497 (IIJ).

The top plot shows the AS dependencies of AS2497, i.e., the most common transit networks used to reach AS2497. The value (a.k.a AS Hegemony) ranges between 0 and 1. This is an estimate of the ratio of AS paths towards AS2497 that go through a certain AS transit. A value close to 1 means that the reachability of the monitored AS is strongly dependant on that transit AS. In the above example, the plot shows a few weak dependencies to Telia (AS1299), NTT America (AS2914), Level(3) (AS3356), and GTT (AS3257). On that day we estimate around 16% of the paths towards IIJ transit through Telia, 9% through NTT, and 2% through Level(3).

Stub ASes usually have much higher values, for example the values go up to 1 for ASes with a single upstream provider (meaning that all the paths cross the upstream provider). You can click on the graph to display dependency details at a particular timestamp and a graphical representation of BGP changes around that time (using BGPlay).

The bottom plot shows the number of networks that depend on AS2497. In this case there are more than 370 networks that use IIJ for transit. This is somehow related to IIJ's customer cone. The main difference is that networks using IIJ as a backup transit are not counted here whereas they are counted in its customer cone. You can click on the graph to obtain the complete list of dependent networks." @@ -510,7 +510,7 @@ "1": { "header": "What does the graph mean?", "img": { - "src": "assets/documentation/netdelay_AS24482.png", + "src": "assets/imgs/netdelay_AS24482.png", "style": "max-width:100%" }, "body": "By default graphs load network delay from the selected network to a few locations (Tokyo, London, Singapore, Ashburn, K-Root server (AS25152), Google (AS15169)), but you can load more results with the search fields above the graph. The graph shows the estimated median RTT from a network to these locations. To compute these values we do the following: We collect a set of RTT estimates by taking all RTT values in traceroute and computing differential RTTs (i.e. the difference between two RTT values found in a traceroute). Then we store the median value of these RTT estimates as a representative value. The above example depicts the median RTTs from an ISP in Singapore (AS24482) to pre-selected locations. As an example, the values for London represent the median values of all RTTs from IP addresses that map to AS24482 (that could be Atlas probes or router addresses) to IPs in the same traceroutes that map to London.

The example above shows two anomalies, the first one on March 16th represents a delay increase only to London, whereas the second one on March 17th impacted all plotted locations." @@ -532,7 +532,7 @@ "1": { "header": "What does the link delay graph mean?", "img": { - "src": "assets/documentation/linkdelay_AS7922.png", + "src": "assets/imgs/linkdelay_AS7922.png", "style": "max-width:100%" }, "body": "
Let's take a look at the above example, which corresponds to results obtained on March 4th 2020 for Comcast (AS7922). The top plot (blue line) represents the overall delay changes we observe for AS7922's links. This value is normally close to 0, but features higher values when we observe significant delay changes for IP addresses in that AS. In this example we see that AS7922 exhibits increased delays around midnight on March 4th. By clicking on the peak at 1:30am we obtain the list of IP addresses that are detected by our system (bottom table) and the end-to-end delays for traceroute monitoring reported IP addresses. Here we see that end-to-end delays of traceroutes crossing the first reported links have increased by 60 ~ 90 ms. The red vertical dashed lines also show that packets are dropped at that time." @@ -540,7 +540,7 @@ "2": { "header": "What does the forwarding anomaly graph mean?", "img": { - "src": "assets/documentation/forwarding_AS174.png", + "src": "assets/imgs/forwarding_AS174.png", "style": "max-width:100%" }, "body": "For forwarding anomalies let's look at another example, AS174 Cogent on November 2017.

The bottom plot represents the forwarding anomalies observed for AS174. Intuitively, this graph represents the presence and absence of IP addresses for AS174 in the monitored traceroutes. If the number of observed IP addresses for AS174 is constant then the forwarding anomaly level is close to 0. If we observe more IP addresses than usual then the forwarding anomaly level takes higher positive values. On the other hand if we observe fewer IP addresses than usual, the forwarding anomaly level takes lower negative values. In this example, IP addresses from AS174 are appearing more than usual due to an internal routing anomaly. You can click on the graphs to obtain the list of reported IP addresses, we used to have a visualization of corresponding traceroutes (TraceMON) but this currently not working." @@ -570,7 +570,7 @@ "1": { "header": "What does the graph mean?", "img": { - "src": "assets/documentation/disco_AS16322.png", + "src": "assets/imgs/disco_AS16322.png", "style": "max-width:100%" }, "body": "
The above example shows the disconnection of an Iranian network (AS16322) due to an update in an upstream provider on March 3rd 2020. The world map shows the location of disconnected Atlas probes and the below graphs show ping results from these probes. These ping measurements provide us with an internal view of the outage. Here we found that pings toward Google DNS and Atlas controller failed from around 00:45 until 01:35. Pings to the K-root server are, however, carried out as usual. This means that this network could still reach a K-root instance during the outage (probably the one located in Teheran).

The table reports a deviation score, 11 in this case, and the number of disconnected Atlas probes. Larger deviation values represent stronger evidence of the network disconnection. To avoid too many false positives, only higher values are reported (this threshold is different for the global and network reports). We also only monitor networks and countries that have at least five Atlas probes." diff --git a/src/i18n/locales/jp.json b/src/i18n/locales/jp.json index 252c5bed..7f91df2f 100644 --- a/src/i18n/locales/jp.json +++ b/src/i18n/locales/jp.json @@ -412,7 +412,7 @@ "2": { "header": "What do the graphs mean?", "img": { - "src": "assets/documentation/hegemony_AS2497.png", + "src": "assets/imgs/hegemony_AS2497.png", "style": "max-width:100%" }, "body": "Let's take a look at the above example which corresponds to results obtained on March 2nd 2020 for AS2497 (IIJ).

The top plot shows the AS dependencies of AS2497, i.e., the most common transit networks used to reach AS2497. The value (a.k.a AS Hegemony) ranges between 0 and 1. This is an estimate of the ratio of AS paths towards AS2497 that go through a certain AS transit. A value close to 1 means that the reachability of the monitored AS is strongly dependant on that transit AS. In the above example, the plot shows a few weak dependencies to Telia (AS1299), NTT America (AS2914), Level(3) (AS3356), and GTT (AS3257). On that day we estimate around 16% of the paths towards IIJ transit through Telia, 9% through NTT, and 2% through Level(3).

Stub ASes usually have much higher values, for example the values go up to 1 for ASes with a single upstream provider (meaning that all the paths cross the upstream provider). You can click on the graph to display dependency details at a particular timestamp and a graphical representation of BGP changes around that time (using BGPlay).

The bottom plot shows the number of networks that depend on AS2497. In this case there are more than 370 networks that use IIJ for transit. This is somehow related to IIJ's customer cone. The main difference is that networks using IIJ as a backup transit are not counted here whereas they are counted in its customer cone. You can click on the graph to obtain the complete list of dependent networks." @@ -510,7 +510,7 @@ "1": { "header": "What does the graph mean?", "img": { - "src": "assets/documentation/netdelay_AS24482.png", + "src": "assets/imgs/netdelay_AS24482.png", "style": "max-width:100%" }, "body": "By default graphs load network delay from the selected network to a few locations (Tokyo, London, Singapore, Ashburn, K-Root server (AS25152), Google (AS15169)), but you can load more results with the search fields above the graph. The graph shows the estimated median RTT from a network to these locations. To compute these values we do the following: We collect a set of RTT estimates by taking all RTT values in traceroute and computing differential RTTs (i.e. the difference between two RTT values found in a traceroute). Then we store the median value of these RTT estimates as a representative value. The above example depicts the median RTTs from an ISP in Singapore (AS24482) to pre-selected locations. As an example, the values for London represent the median values of all RTTs from IP addresses that map to AS24482 (that could be Atlas probes or router addresses) to IPs in the same traceroutes that map to London.

The example above shows two anomalies, the first one on March 16th represents a delay increase only to London, whereas the second one on March 17th impacted all plotted locations." @@ -532,7 +532,7 @@ "1": { "header": "What does the link delay graph mean?", "img": { - "src": "assets/documentation/linkdelay_AS7922.png", + "src": "assets/imgs/linkdelay_AS7922.png", "style": "max-width:100%" }, "body": "
Let's take a look at the above example, which corresponds to results obtained on March 4th 2020 for Comcast (AS7922). The top plot (blue line) represents the overall delay changes we observe for AS7922's links. This value is normally close to 0, but features higher values when we observe significant delay changes for IP addresses in that AS. In this example we see that AS7922 exhibits increased delays around midnight on March 4th. By clicking on the peak at 1:30am we obtain the list of IP addresses that are detected by our system (bottom table) and the end-to-end delays for traceroute monitoring reported IP addresses. Here we see that end-to-end delays of traceroutes crossing the first reported links have increased by 60 ~ 90 ms. The red vertical dashed lines also show that packets are dropped at that time." @@ -540,7 +540,7 @@ "2": { "header": "What does the forwarding anomaly graph mean?", "img": { - "src": "assets/documentation/forwarding_AS174.png", + "src": "assets/imgs/forwarding_AS174.png", "style": "max-width:100%" }, "body": "For forwarding anomalies let's look at another example, AS174 Cogent on November 2017.

The bottom plot represents the forwarding anomalies observed for AS174. Intuitively, this graph represents the presence and absence of IP addresses for AS174 in the monitored traceroutes. If the number of observed IP addresses for AS174 is constant then the forwarding anomaly level is close to 0. If we observe more IP addresses than usual then the forwarding anomaly level takes higher positive values. On the other hand if we observe fewer IP addresses than usual, the forwarding anomaly level takes lower negative values. In this example, IP addresses from AS174 are appearing more than usual due to an internal routing anomaly. You can click on the graphs to obtain the list of reported IP addresses, we used to have a visualization of corresponding traceroutes (TraceMON) but this currently not working." @@ -570,7 +570,7 @@ "1": { "header": "What does the graph mean?", "img": { - "src": "assets/documentation/disco_AS16322.png", + "src": "assets/imgs/disco_AS16322.png", "style": "max-width:100%" }, "body": "
The above example shows the disconnection of an Iranian network (AS16322) due to an update in an upstream provider on March 3rd 2020. The world map shows the location of disconnected Atlas probes and the below graphs show ping results from these probes. These ping measurements provide us with an internal view of the outage. Here we found that pings toward Google DNS and Atlas controller failed from around 00:45 until 01:35. Pings to the K-root server are, however, carried out as usual. This means that this network could still reach a K-root instance during the outage (probably the one located in Teheran).

The table reports a deviation score, 11 in this case, and the number of disconnected Atlas probes. Larger deviation values represent stronger evidence of the network disconnection. To avoid too many false positives, only higher values are reported (this threshold is different for the global and network reports). We also only monitor networks and countries that have at least five Atlas probes." From bcdc199db6a4f1d09b8933d138ac7fe4cdbbbb8a Mon Sep 17 00:00:00 2001 From: Mohamed Awnallah Date: Sat, 30 Dec 2023 21:12:18 +0200 Subject: [PATCH 3/5] Address the global report regressions caused by Vue js 3 Migration --- src/components/charts/IodaChart.vue | 15 +- src/components/charts/ReactiveChart.vue | 17 +- .../TimeSeriesAggregatedAlarmsChart.vue | 70 ++-- .../charts/TreeMapAggregatedAlarmsChart.vue | 66 +-- .../charts/WorldMapAggregatedAlarmsChart.vue | 25 +- .../AggregatedAlarmsController.vue | 393 ++++++++++-------- .../maps/WorldMapAggregatedAlarmsMap.vue | 9 +- .../tables/AggregatedAlarmsTable.vue | 349 ++++++++++------ src/plugins/AsNames.js | 2 +- src/plugins/countryName.js | 6 +- .../metadata/AggregatedAlarmsMetadata.js | 16 +- .../models/AggregatedAlarmsDataModel.js | 21 + src/plugins/models/IodaChartDataModel.js | 9 + .../models/TableAggregatedAlarmsDataModel.js | 15 +- .../TimeSeriesAggregatedAlarmsDataModel.js | 29 +- .../WorldMapAggregatedAlarmsDataModel.js | 9 +- src/views/GlobalReport.vue | 245 +++++------ 17 files changed, 726 insertions(+), 570 deletions(-) diff --git a/src/components/charts/IodaChart.vue b/src/components/charts/IodaChart.vue index ffced522..1f724982 100644 --- a/src/components/charts/IodaChart.vue +++ b/src/components/charts/IodaChart.vue @@ -9,10 +9,6 @@ const props = defineProps({ type: String, required: true }, - iodaAlarmTypesUnits: { - type: Object, - required: true, - }, filterByCountry: { type: Boolean, required: true, @@ -30,10 +26,6 @@ const props = defineProps({ const layout = ref(IODA_ALARMS_SPECIFIC_ENTRY_TIMESERIES_LAYOUT) const traces = ref([]) const loading = ref(false) -const iodaAlarmTypesUnitsVal = ref({ - ...props.iodaAlarmTypesUnits, - 'gtr': 'Google (Search)' -}) const iodaSourceParams = ref('WEB_SEARCH') const noData = ref('') @@ -43,14 +35,15 @@ const entityType = computed(() => { const apiCall = () => { loading.value = true - IodaChartDataModel.etl(entityType.value, props.entityValue, props.startTime, props.endTime, iodaAlarmTypesUnitsVal.value, iodaSourceParams.value) - .then((res)=> { + const iodaAlarmTypesUnits = IodaChartDataModel.getIodaAlarmTypesUnits() + IodaChartDataModel.etl(entityType.value, props.entityValue, props.startTime, props.endTime, iodaAlarmTypesUnits, iodaSourceParams.value) + .then((res) => { traces.value = res layout.value.datarevision = new Date().getTime() loading.value = false noData.value = !res.length ? 'No data to show' : '' }) - .catch((error)=>{ + .catch((error) => { console.error(error) }) } diff --git a/src/components/charts/ReactiveChart.vue b/src/components/charts/ReactiveChart.vue index 59a830f3..8017239a 100644 --- a/src/components/charts/ReactiveChart.vue +++ b/src/components/charts/ReactiveChart.vue @@ -108,19 +108,28 @@ const init = () => { if (startDateTime && endDateTime) { startDateTime += 'Z' endDateTime += 'Z' + startDateTime = new Date(startDateTime) + endDateTime = new Date(endDateTime) emits('plotly-time-filter', { startDateTime, endDateTime }) } }) graphDiv.on('plotly_click', (eventData) => { - if (eventData && eventData.points ) { + if (eventData && eventData.points) { emits('plotly-click', eventData) } }) graphDiv.on('plotly_legendclick', (eventData) => { - if (eventData && eventData.node) { - emits('plotly-legend-click', eventData) + if (eventData) { + const legend = eventData.node.textContent + const opacityStyle = eventData.node.getAttribute('style'); + const opacityMatch = opacityStyle.match(/opacity:\s*([^;]+);/); + if (opacityMatch && legend !== 'All') { + const opacity = Number(opacityMatch[1]); + const result = { legend, opacity } + emits('plotly-legend-click', result); + } } }) @@ -133,7 +142,7 @@ onMounted(() => { watch(() => props.traces, () => { react() -}, {deep: true}) +}, { deep: true }) // watch(() => props.layout, () => { // react() // }) diff --git a/src/components/charts/TimeSeriesAggregatedAlarmsChart.vue b/src/components/charts/TimeSeriesAggregatedAlarmsChart.vue index 045c3b20..6bc968cb 100644 --- a/src/components/charts/TimeSeriesAggregatedAlarmsChart.vue +++ b/src/components/charts/TimeSeriesAggregatedAlarmsChart.vue @@ -1,4 +1,5 @@ \ No newline at end of file diff --git a/src/components/charts/TreeMapAggregatedAlarmsChart.vue b/src/components/charts/TreeMapAggregatedAlarmsChart.vue index c7fd526f..132dc8e0 100644 --- a/src/components/charts/TreeMapAggregatedAlarmsChart.vue +++ b/src/components/charts/TreeMapAggregatedAlarmsChart.vue @@ -1,4 +1,5 @@ \ No newline at end of file diff --git a/src/components/charts/WorldMapAggregatedAlarmsChart.vue b/src/components/charts/WorldMapAggregatedAlarmsChart.vue index 1c1442ba..2e49b296 100644 --- a/src/components/charts/WorldMapAggregatedAlarmsChart.vue +++ b/src/components/charts/WorldMapAggregatedAlarmsChart.vue @@ -1,8 +1,8 @@ +defineExpose({ init }) + \ No newline at end of file diff --git a/src/components/controllers/AggregatedAlarmsController.vue b/src/components/controllers/AggregatedAlarmsController.vue index 9c157537..c320aba0 100644 --- a/src/components/controllers/AggregatedAlarmsController.vue +++ b/src/components/controllers/AggregatedAlarmsController.vue @@ -1,18 +1,18 @@ @@ -331,124 +341,157 @@ watch(selectedAlarmTypesOptions.value, () => { - - - Data Source - Alarm Types - - - - - {{ dataSource.metadata.title }} - - {{ dataAlarm.metadata.title }} - - - {{ ALARMS_INFO[indexSource].alarm_types[indexAlarm].metadata.description }} - - - - - - - + + + Data Source + Alarm Types + + + + + + {{ dataSource.metadata.title }} + + + {{ ALARMS_INFO[indexSource].metadata.description }} + + + + + {{ + dataAlarm.metadata.title }} + + + {{ ALARMS_INFO[indexSource].alarm_types[indexAlarm].metadata.description }} + + + + + + + +

-
- +
+
+
+ +
+
+
+ +
+
+
+
+ + APPLY +
+
+ + RESET TIME +
+
+
+
+
- +
- Reset Granularity + Show + All Countries
- -
Aggregated Alarms by Countries
-
- - +
-
-
{{ selectedCountry ? `Alarms by ASNs over Time for ${selectedCountry}` : 'Alarms for all Countries over Time' }}
+
+
+ + RESET TIME + +
+
+ + Show All Countries + +
+
- +
-
{{ selectedCountry ? `Aggregated Alarms by ASN, Alarm Type, and Severity for ${selectedCountry}` : 'Aggregated Alarms by Country, ASN, Alarm Type, and Severity' }}
+
+ + Show All Countries + +
- +
- + - + - + :selected-table-alarm-type="indexAlarmTypeTitlesMap" :loading="loadingVal" :country-name="selectedCountry" + :alarms="alarms.filter" :aggregated-attrs-selected="aggregatedAttrs" + :alarm-type-titles-map="alarmTypeTitlesMap" :filter="filter" @country-clicked="onCountryClicked" + @asn-name-key-clicked="onASNameClicked" /> diff --git a/src/components/maps/WorldMapAggregatedAlarmsMap.vue b/src/components/maps/WorldMapAggregatedAlarmsMap.vue index c10925ec..21c871df 100644 --- a/src/components/maps/WorldMapAggregatedAlarmsMap.vue +++ b/src/components/maps/WorldMapAggregatedAlarmsMap.vue @@ -32,6 +32,7 @@ const layout = ref({ countrycolor: 'rgb(235, 235, 235)', showcountries: true, }, + height: 500 }) const traces = ref([ { @@ -54,7 +55,7 @@ const traces = ref([ bgcolor: 'white', }, colorbar: { - title: 'Alarm Counts', + title: 'Alarm Density', len: 0.9, } }, @@ -89,12 +90,12 @@ const noData = computed(() => { }) const plotlyClickedDataHandler = (val) => { - emits('country-clicked', val) + const country = val.points[0].text + emits('country-clicked', country) } onMounted(() => { - // clearDataViz() - // setTraces() + setTraces() }) diff --git a/src/components/tables/AggregatedAlarmsTable.vue b/src/components/tables/AggregatedAlarmsTable.vue index c94f05f6..b9274d35 100644 --- a/src/components/tables/AggregatedAlarmsTable.vue +++ b/src/components/tables/AggregatedAlarmsTable.vue @@ -1,25 +1,24 @@ - - - - - - - - + :networkDelayLoading="loading.network_delay" :networkDisconnectionAlarms="networkDisconnectionAlarms" + :networkDisconnectionLoading="loading.network_disconnection" />
From 9014e5feff07df690566b2e29b0bc16d743f01d9 Mon Sep 17 00:00:00 2001 From: Mohamed Awnallah Date: Sun, 31 Dec 2023 17:19:29 +0200 Subject: [PATCH 4/5] Update the node version in the test CI to '20.10.0' to be compatible with the new vue.js 3 migration --- .github/workflows/test.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index df4f9644..93939157 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -15,12 +15,12 @@ jobs: steps: - name: Checkout Repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Set up Node.js - uses: actions/setup-node@v2 + uses: actions/setup-node@v4 with: - node-version: '16.x' + node-version: '20.10.0' - name: Install Dependencies run: npm install From d2fd33bdb53e6628d828603456db85cd13b5243a Mon Sep 17 00:00:00 2001 From: Mohamed Awnallah Date: Sun, 31 Dec 2023 19:26:38 +0200 Subject: [PATCH 5/5] Integrate IODA Alarms Chart in Networks and Countries Report --- src/i18n/locales/en.json | 3 +++ src/i18n/locales/jp.json | 3 +++ src/views/Countries.vue | 14 +++++++++++++- src/views/Networks.vue | 15 ++++++++++++++- 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index 1c136a67..39d80a13 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -120,6 +120,9 @@ "apiTitle": "Displayed data is available at the following links:" } }, + "iodaChart": { + "title": "IODA Overview" + }, "countryHegemony": { "title": "Network Dependency", "table": { diff --git a/src/i18n/locales/jp.json b/src/i18n/locales/jp.json index 7f91df2f..525f803d 100644 --- a/src/i18n/locales/jp.json +++ b/src/i18n/locales/jp.json @@ -120,6 +120,9 @@ "apiTitle": "Displayed data is available at the following links:" } }, + "iodaChart": { + "title": "IODA Overview" + }, "countryHegemony": { "title": "Network Dependency", "table": { diff --git a/src/views/Countries.vue b/src/views/Countries.vue index c474e41e..d2fd4e99 100644 --- a/src/views/Countries.vue +++ b/src/views/Countries.vue @@ -14,6 +14,7 @@ import { isoCountries } from '@/plugins/countryName' import { DEFAULT_DISCO_AVG_LEVEL } from '@/plugins/disco' import { AS_FAMILY } from '@/plugins/IhrApi' import CountryHegemonyChart from '../components/charts/CountryHegemonyChart.vue' +import IodaChart from '@/components/charts/IodaChart.vue' const { t } = useI18n() @@ -50,6 +51,8 @@ const show = ref({ disco_disable: false, hegemony: true, hegemony_disable: false, + ioda: true, + ioda_disable: false, net_delay: true, net_delay_disable: false }) @@ -181,7 +184,16 @@ onMounted(() => { - + + + + + + + + { /> - + + + + + + + + +