From 43390ac7280c8c1972c91d4cee7e1a995b037b63 Mon Sep 17 00:00:00 2001 From: Daniel Cherrett Date: Fri, 21 Jan 2022 14:20:02 +0100 Subject: [PATCH] Added changed files --- .gitlab-ci.yml | 29 -- README.md | 6 +- alerter/Pipfile | 2 +- alerter/Pipfile.lock | 392 +++++++++--------- .../alerter/alerters/contract/chainlink.py | 17 +- .../src/alerter/alerts/contract/chainlink.py | 4 +- .../chainlink_contract_metric_code.py | 10 +- .../grouped_alerts_metric_code/github.py | 2 +- .../node/chainlink_node_metric_code.py | 28 +- .../node/evm_node_metric_code.py | 4 +- .../grouped_alerts_metric_code/system.py | 6 +- .../commands/handlers/slack_cmd_handlers.py | 10 +- alerter/src/data_store/redis/store_keys.py | 149 ++++--- alerter/src/data_store/stores/alert.py | 55 +-- alerter/src/monitors/node/chainlink.py | 67 ++- alerter/src/utils/constants/data.py | 50 +-- .../alerters/contract/test_chainlink.py | 22 +- .../alerter/factory/test_alerting_factory.py | 23 +- .../handlers/test_slack_cmd_handlers.py | 180 ++++---- .../data_store/stores/test_alert_store.py | 70 +++- .../data_store/stores/test_config_store.py | 2 +- alerter/test/monitors/node/test_chainlink.py | 90 ++-- docker-compose-tests.yml | 4 +- docker-compose.yml | 6 +- docs/CHANGE_LOG.md | 11 +- slack_manifest.yaml | 26 +- web-installer/package-lock.json | 4 +- web-installer/package.json | 4 +- 28 files changed, 676 insertions(+), 597 deletions(-) delete mode 100644 .gitlab-ci.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index 402508fc4..000000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,29 +0,0 @@ -image: node:latest - -before_script: - - cd web-installer - -stages: - - build - - test - -cache: - paths: - - web-installer/node_modules/ - -install: - stage: build - script: - - npm install - - npm i gulp - artifacts: - paths: - - node_modules/ - -include: - - template: Code-Quality.gitlab-ci.yml - -code_quality: - stage: test - artifacts: - paths: [gl-code-quality-report.json] diff --git a/README.md b/README.md index 5d211740f..04e8fc422 100644 --- a/README.md +++ b/README.md @@ -222,11 +222,7 @@ Check if the installation was successful by checking if {NODE_IP}:{PORT}/metrics 7. Take note of the Token generated, this is the App-Level Token. 8. Go to the 'Install App' setting (left pane) and click `Install to Workspace`, followed by `Allow`. 9. Go to the 'OAuth & Permissions' feature (left pane) and take note of the `Bot User OAuth Token`. - 10. Go to the 'Slash Commands' feature and create the following commands: - * */start* command with *Welcome message* as the short description. - * */help* command with *Available Commands* as the short description. - * */ping* command with *Ping the Slack Commands Handler* as the short description. - 11. Add the newly created `PANIC Notifications` app to the target channel by typing `/add` within the channel and selecting `Add apps to this channel`. + 10. Add the newly created `PANIC Notifications` app to the target channel by typing `/add` within the channel and selecting `Add apps to this channel`. 4. Go to the Slack client, right click the name of the target slack channel within the list of channels (left pane), click `Open channel details`, and take note of the Channel ID *(found at the bottom)*. **At the end, you should have:** diff --git a/alerter/Pipfile b/alerter/Pipfile index 5bb848790..8af58bdf3 100644 --- a/alerter/Pipfile +++ b/alerter/Pipfile @@ -12,7 +12,7 @@ freezegun = "*" configparser = "*" pika = "*" prometheus_client = "*" -pymongo = "*" +pymongo = "==3.12.1" python-telegram-bot = "*" python-dateutil = "*" pdpyras = "*" diff --git a/alerter/Pipfile.lock b/alerter/Pipfile.lock index 8fc143bcd..9e064eb37 100644 --- a/alerter/Pipfile.lock +++ b/alerter/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "0883b9ad45631edfb29822d77dfd25c9f685551a2d0c1c22f80527146d350efc" + "sha256": "9d3407a69b71d8529a04ff911878c47dfa744a545766bb04775876c789ff14a4" }, "pipfile-spec": 6, "requires": { @@ -111,19 +111,19 @@ }, "async-timeout": { "hashes": [ - "sha256:a22c0b311af23337eb05fcf05a8b51c3ea53729d46fb5460af62bee033cec690", - "sha256:b930cb161a39042f9222f6efb7301399c87eeab394727ec5437924a36d6eef51" + "sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15", + "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c" ], "markers": "python_version >= '3.6'", - "version": "==4.0.1" + "version": "==4.0.2" }, "attrs": { "hashes": [ - "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1", - "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb" + "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4", + "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==21.2.0" + "version": "==21.4.0" }, "base58": { "hashes": [ @@ -156,19 +156,19 @@ }, "charset-normalizer": { "hashes": [ - "sha256:735e240d9a8506778cd7a453d97e817e536bb1fc29f4f6961ce297b9c7a917b0", - "sha256:83fcdeb225499d6344c8f7f34684c2981270beacc32ede2e669e94f7fa544405" + "sha256:876d180e9d7432c5d1dfd4c5d26b72f099d503e8fcc0feb7532c9289be60fcbd", + "sha256:cb957888737fc0bbcd78e3df769addb41fd1ff8cf950dc9e7ad7793f1bf44455" ], "markers": "python_version >= '3'", - "version": "==2.0.8" + "version": "==2.0.10" }, "configparser": { "hashes": [ - "sha256:202b9679a809b703720afa2eacaad4c6c2d63196070e5d9edc953c0489dfd536", - "sha256:f99c2256b24c551de13cf9e42c7b5db96fb133f0ca4de5dcb1df1aaf89f48298" + "sha256:1b35798fdf1713f1c3139016cfcbc461f09edbf099d1fb658d4b7479fcaa3daa", + "sha256:e8b39238fb6f0153a069aa253d349467c3c4737934f253ef6abac5fe0eca1e5d" ], "index": "pypi", - "version": "==5.1.0" + "version": "==5.2.0" }, "contextlib2": { "hashes": [ @@ -255,7 +255,7 @@ "sha256:74240a8c6f652d085ed3c85f5f1654203d2f10ff9062f83b3bad0a12ff321c7a", "sha256:bf82762a46978714190b0370265a7148c954d3f0adaa31c6f085ea375e4c61af" ], - "markers": "python_version >= '3.5' and python_version < '4' and python_full_version != '3.5.2'", + "markers": "python_version >= '3.5' and python_full_version != '3.5.2' and python_version < '4'", "version": "==1.10.0" }, "frozenlist": { @@ -474,6 +474,14 @@ "index": "pypi", "version": "==2.1.5" }, + "packaging": { + "hashes": [ + "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb", + "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522" + ], + "markers": "python_version >= '3.6'", + "version": "==21.3" + }, "parsimonious": { "hashes": [ "sha256:3add338892d580e0cb3b1a39e4a1b427ff9f687858fdd61097053742391a9f6b" @@ -505,68 +513,70 @@ }, "protobuf": { "hashes": [ - "sha256:038daf4fa38a7e818dd61f51f22588d61755160a98db087a046f80d66b855942", - "sha256:28ccea56d4dc38d35cd70c43c2da2f40ac0be0a355ef882242e8586c6d66666f", - "sha256:36d90676d6f426718463fe382ec6274909337ca6319d375eebd2044e6c6ac560", - "sha256:3cd0458870ea7d1c58e948ac8078f6ba8a7ecc44a57e03032ed066c5bb318089", - "sha256:5935c8ce02e3d89c7900140a8a42b35bc037ec07a6aeb61cc108be8d3c9438a6", - "sha256:615b426a177780ce381ecd212edc1e0f70db8557ed72560b82096bd36b01bc04", - "sha256:62a8e4baa9cb9e064eb62d1002eca820857ab2138440cb4b3ea4243830f94ca7", - "sha256:655264ed0d0efe47a523e2255fc1106a22f6faab7cc46cfe99b5bae085c2a13e", - "sha256:6e8ea9173403219239cdfd8d946ed101f2ab6ecc025b0fda0c6c713c35c9981d", - "sha256:71b0250b0cfb738442d60cab68abc166de43411f2a4f791d31378590bfb71bd7", - "sha256:74f33edeb4f3b7ed13d567881da8e5a92a72b36495d57d696c2ea1ae0cfee80c", - "sha256:77d2fadcf369b3f22859ab25bd12bb8e98fb11e05d9ff9b7cd45b711c719c002", - "sha256:8b30a7de128c46b5ecb343917d9fa737612a6e8280f440874e5cc2ba0d79b8f6", - "sha256:8e51561d72efd5bd5c91490af1f13e32bcba8dab4643761eb7de3ce18e64a853", - "sha256:a529e7df52204565bcd33738a7a5f288f3d2d37d86caa5d78c458fa5fabbd54d", - "sha256:b691d996c6d0984947c4cf8b7ae2fe372d99b32821d0584f0b90277aa36982d3", - "sha256:d80f80eb175bf5f1169139c2e0c5ada98b1c098e2b3c3736667f28cbbea39fc8", - "sha256:d83e1ef8cb74009bebee3e61cc84b1c9cd04935b72bca0cbc83217d140424995", - "sha256:d8919368410110633717c406ab5c97e8df5ce93020cfcf3012834f28b1fab1ea", - "sha256:db3532d9f7a6ebbe2392041350437953b6d7a792de10e629c1e4f5a6b1fe1ac6", - "sha256:e7b24c11df36ee8e0c085e5b0dc560289e4b58804746fb487287dda51410f1e2", - "sha256:e7e8d2c20921f8da0dea277dfefc6abac05903ceac8e72839b2da519db69206b", - "sha256:e813b1c9006b6399308e917ac5d298f345d95bb31f46f02b60cd92970a9afa17", - "sha256:fd390367fc211cc0ffcf3a9e149dfeca78fecc62adb911371db0cec5c8b7472d" + "sha256:1291a0a7db7d792745c99d4657b4c5c4942695c8b1ac1bfb993a34035ec123f7", + "sha256:18c40a1b8721026a85187640f1786d52407dc9c1ba8ec38accb57a46e84015f6", + "sha256:1cb2ed66aac593adbf6dca4f07cd7ee7e2958b17bbc85b2cc8bc564ebeb258ec", + "sha256:2acd7ca329be544d1a603d5f13a4e34a3791c90d651ebaf130ba2e43ae5397c6", + "sha256:2cddcbcc222f3144765ccccdb35d3621dc1544da57a9aca7e1944c1a4fe3db11", + "sha256:397d82f1c58b76445469c8c06b8dee1ff67b3053639d054f52599a458fac9bc6", + "sha256:3bf3a07d17ba3511fe5fa916afb7351f482ab5dbab5afe71a7a384274a2cd550", + "sha256:3f80a3491eaca767cdd86cb8660dc778f634b44abdb0dffc9b2a8e8d0cd617d0", + "sha256:49677e5e9c7ea1245a90c2e8a00d304598f22ea3aa0628f0e0a530a9e70665fa", + "sha256:544fe9705189b249380fae07952d220c97f5c6c9372a6f936cc83a79601dcb70", + "sha256:6202df8ee8457cb00810c6e76ced480f22a1e4e02c899a14e7b6e6e1de09f938", + "sha256:84bf3aa3efb00dbe1c7ed55da0f20800b0662541e582d7e62b3e1464d61ed365", + "sha256:898bda9cd37ec0c781b598891e86435de80c3bfa53eb483a9dac5a11ec93e942", + "sha256:8ad761ef3be34c8bdc7285bec4b40372a8dad9e70cfbdc1793cd3cf4c1a4ce74", + "sha256:8ceaf5fdb72c8e1fcb7be9f2b3b07482ce058a3548180c0bdd5c7e4ac5e14165", + "sha256:a9401d96552befcc7311f5ef8f0fa7dba0ef5fd805466b158b141606cd0ab6a8", + "sha256:af7238849fa79285d448a24db686517570099739527a03c9c2971cce99cc5ae2", + "sha256:afa8122de8064fd577f49ae9eef433561c8ace97a0a7b969d56e8b1d39b5d177", + "sha256:b53519b2ebec70cfe24b4ddda21e9843f0918d7c3627a785393fb35d402ab8ad", + "sha256:c781402ed5396ab56358d7b866d78c03a77cbc26ba0598d8bb0ac32084b1a257", + "sha256:d975a6314fbf5c524d4981e24294739216b5fb81ef3c14b86fb4b045d6690907", + "sha256:df2ba379ee42427e8fcc6a0a76843bff6efb34ef5266b17f95043939b5e25b69", + "sha256:e54b8650e849ee8e95e481024bff92cf98f5ec61c7650cb838d928a140adcb63", + "sha256:e765e6dfbbb02c55e4d6d1145743401a84fc0b508f5a81b2c5a738cf86353139", + "sha256:ef02d112c025e83db5d1188a847e358beab3e4bbfbbaf10eaf69e67359af51b2", + "sha256:f6d4b5b7595a57e69eb7314c67bef4a3c745b4caf91accaf72913d8e0635111b" ], "markers": "python_version >= '3.5'", - "version": "==3.19.1" + "version": "==3.19.3" }, "pycryptodome": { "hashes": [ - "sha256:014c758af7fa38cab85b357a496b76f4fc9dda1f731eb28358d66fef7ad4a3e1", - "sha256:06162fcfed2f9deee8383fd59eaeabc7b7ffc3af50d3fad4000032deb8f700b0", - "sha256:0ca7a6b4fc1f9fafe990b95c8cda89099797e2cfbf40e55607f2f2f5a3355dcb", - "sha256:2a4bcc8a9977fee0979079cd33a9e9f0d3ddba5660d35ffe874cf84f1dd399d2", - "sha256:3c7ed5b07274535979c730daf5817db5e983ea80b04c22579eee8da4ca3ae4f8", - "sha256:4169ed515742425ff21e4bd3fabbb6994ffb64434472fb72230019bdfa36b939", - "sha256:428096bbf7a77e207f418dfd4d7c284df8ade81d2dc80f010e92753a3e406ad0", - "sha256:4ce6b09547bf2c7cede3a017f79502eaed3e819c13cdb3cb357aea1b004e4cc6", - "sha256:53989477044be41fa4a63da09d5038c2a34b2f4554cfea2e3933b17186ee9e19", - "sha256:621a90147a5e255fdc2a0fec2d56626b76b5d72ea9e60164c9a5a8976d45b0c9", - "sha256:6db1f9fa1f52226621905f004278ce7bd90c8f5363ffd5d7ab3755363d98549a", - "sha256:6eda8a3157c91ba60b26a07bedd6c44ab8bda6cd79b6b5ea9744ba62c39b7b1e", - "sha256:75e78360d1dd6d02eb288fd8275bb4d147d6e3f5337935c096d11dba1fa84748", - "sha256:7ff701fc283412e651eaab4319b3cd4eaa0827e94569cd37ee9075d5c05fe655", - "sha256:8f3a60926be78422e662b0d0b18351b426ce27657101c8a50bad80300de6a701", - "sha256:a843350d08c3d22f6c09c2f17f020d8dcfa59496165d7425a3fba0045543dda7", - "sha256:ae29fcd56152f417bfba50a36a56a7a5f9fb74ff80bab98704cac704de6568ab", - "sha256:ae31cb874f6f0cedbed457c6374e7e54d7ed45c1a4e11a65a9c80968da90a650", - "sha256:b33c9b3d1327d821e28e9cc3a6512c14f8b17570ddb4cfb9a52247ed0fcc5d8b", - "sha256:b59bf823cfafde8ef1105d8984f26d1694dff165adb7198b12e3e068d7999b15", - "sha256:bc3c61ff92efdcc14af4a7b81da71d849c9acee51d8fd8ac9841a7620140d6c6", - "sha256:ce81b9c6aaa0f920e2ab05eb2b9f4ccd102e3016b2f37125593b16a83a4b0cc2", - "sha256:d7e5f6f692421e5219aa3b545eb0cffd832cd589a4b9dcd4a5eb4260e2c0d68a", - "sha256:da796e9221dda61a0019d01742337eb8a322de8598b678a4344ca0a436380315", - "sha256:ead516e03dfe062aefeafe4a29445a6449b0fc43bc8cb30194b2754917a63798", - "sha256:ed45ef92d21db33685b789de2c015e9d9a18a74760a8df1fc152faee88cdf741", - "sha256:f19edd42368e9057c39492947bb99570dc927123e210008f2af7cf9b505c6892", - "sha256:f9bad2220b80b4ed74f089db012ab5ab5419143a33fad6c8aedcc2a9341eac70", - "sha256:fce7e22d96030b35345637c563246c24d4513bd3b413e1c40293114837ab8912", - "sha256:ffd0cac13ff41f2d15ed39dc6ba1d2ad88dd2905d656c33d8235852f5d6151fd" - ], - "version": "==3.11.0" + "sha256:1181c90d1a6aee68a84826825548d0db1b58d8541101f908d779d601d1690586", + "sha256:12c7343aec5a3b3df5c47265281b12b611f26ec9367b6129199d67da54b768c1", + "sha256:212c7f7fe11cad9275fbcff50ca977f1c6643f13560d081e7b0f70596df447b8", + "sha256:32d15da81959faea6cbed95df2bb44f7f796211c110cf90b5ad3b2aeeb97fc8e", + "sha256:341c6bbf932c406b4f3ee2372e8589b67ac0cf4e99e7dc081440f43a3cde9f0f", + "sha256:3558616f45d8584aee3eba27559bc6fd0ba9be6c076610ed3cc62bd5229ffdc3", + "sha256:39da5807aa1ff820799c928f745f89432908bf6624b9e981d2d7f9e55d91b860", + "sha256:3f2f3dd596c6128d91314e60a6bcf4344610ef0e97f4ae4dd1770f86dd0748d8", + "sha256:4cded12e13785bbdf4ba1ff5fb9d261cd98162145f869e4fbc4a4b9083392f0b", + "sha256:5a8c24d39d4a237dbfe181ea6593792bf9b5582c7fcfa7b8e0e12fda5eec07af", + "sha256:5d4264039a2087977f50072aaff2346d1c1c101cb359f9444cf92e3d1f42b4cd", + "sha256:6bb0d340c93bcb674ea8899e2f6408ec64c6c21731a59481332b4b2a8143cc60", + "sha256:6f8f5b7b53516da7511951910ab458e799173722c91fea54e2ba2f56d102e4aa", + "sha256:90ad3381ccdc6a24cc2841e295706a168f32abefe64c679695712acac71fd5da", + "sha256:93acad54a72d81253242eb0a15064be559ec9d989e5173286dc21cad19f01765", + "sha256:9ea2f6674c803602a7c0437fccdc2ea036707e60456974fe26ca263bd501ec45", + "sha256:a6e1bcd9d5855f1a3c0f8d585f44c81b08f39a02754007f374fb8db9605ba29c", + "sha256:a78e4324e566b5fbc2b51e9240950d82fa9e1c7eb77acdf27f58712f65622c1d", + "sha256:aceb1d217c3a025fb963849071446cf3aca1353282fe1c3cb7bd7339a4d47947", + "sha256:aed7eb4b64c600fbc5e6d4238991ad1b4179a558401f203d1fcbd24883748982", + "sha256:b07a4238465eb8c65dd5df2ab8ba6df127e412293c0ed7656c003336f557a100", + "sha256:b91404611767a7485837a6f1fd20cf9a5ae0ad362040a022cd65827ecb1b0d00", + "sha256:d8083de50f6dec56c3c6f270fb193590999583a1b27c9c75bc0b5cac22d438cc", + "sha256:d845c587ceb82ac7cbac7d0bf8c62a1a0fe7190b028b322da5ca65f6e5a18b9e", + "sha256:db66ccda65d5d20c17b00768e462a86f6f540f9aea8419a7f76cc7d9effd82cd", + "sha256:dc88355c4b261ed259268e65705b28b44d99570337694d593f06e3b1698eaaf3", + "sha256:de0b711d673904dd6c65307ead36cb76622365a393569bf880895cba21195b7a", + "sha256:e05f994f30f1cda3cbe57441f41220d16731cf99d868bb02a8f6484c454c206b", + "sha256:e80f7469b0b3ea0f694230477d8501dc5a30a717e94fddd4821e6721f3053eae", + "sha256:f699360ae285fcae9c8f53ca6acf33796025a82bb0ccd7c1c551b04c1726def3" + ], + "version": "==3.12.0" }, "pyjwt": { "hashes": [ @@ -689,32 +699,40 @@ "index": "pypi", "version": "==3.12.1" }, - "pyrsistent": { + "pyparsing": { "hashes": [ - "sha256:097b96f129dd36a8c9e33594e7ebb151b1515eb52cceb08474c10a5479e799f2", - "sha256:2aaf19dc8ce517a8653746d98e962ef480ff34b6bc563fc067be6401ffb457c7", - "sha256:404e1f1d254d314d55adb8d87f4f465c8693d6f902f67eb6ef5b4526dc58e6ea", - "sha256:48578680353f41dca1ca3dc48629fb77dfc745128b56fc01096b2530c13fd426", - "sha256:4916c10896721e472ee12c95cdc2891ce5890898d2f9907b1b4ae0f53588b710", - "sha256:527be2bfa8dc80f6f8ddd65242ba476a6c4fb4e3aedbf281dfbac1b1ed4165b1", - "sha256:58a70d93fb79dc585b21f9d72487b929a6fe58da0754fa4cb9f279bb92369396", - "sha256:5e4395bbf841693eaebaa5bb5c8f5cdbb1d139e07c975c682ec4e4f8126e03d2", - "sha256:6b5eed00e597b5b5773b4ca30bd48a5774ef1e96f2a45d105db5b4ebb4bca680", - "sha256:73ff61b1411e3fb0ba144b8f08d6749749775fe89688093e1efef9839d2dcc35", - "sha256:772e94c2c6864f2cd2ffbe58bb3bdefbe2a32afa0acb1a77e472aac831f83427", - "sha256:773c781216f8c2900b42a7b638d5b517bb134ae1acbebe4d1e8f1f41ea60eb4b", - "sha256:a0c772d791c38bbc77be659af29bb14c38ced151433592e326361610250c605b", - "sha256:b29b869cf58412ca5738d23691e96d8aff535e17390128a1a52717c9a109da4f", - "sha256:c1a9ff320fa699337e05edcaae79ef8c2880b52720bc031b219e5b5008ebbdef", - "sha256:cd3caef37a415fd0dae6148a1b6957a8c5f275a62cca02e18474608cb263640c", - "sha256:d5ec194c9c573aafaceebf05fc400656722793dac57f254cd4741f3c27ae57b4", - "sha256:da6e5e818d18459fa46fac0a4a4e543507fe1110e808101277c5a2b5bab0cd2d", - "sha256:e79d94ca58fcafef6395f6352383fa1a76922268fa02caa2272fff501c2fdc78", - "sha256:f3ef98d7b76da5eb19c37fda834d50262ff9167c65658d1d8f974d2e4d90676b", - "sha256:f4c8cabb46ff8e5d61f56a037974228e978f26bfefce4f61a4b1ac0ba7a2ab72" + "sha256:04ff808a5b90911829c55c4e26f75fa5ca8a2f5f36aa3a51f68e27033341d3e4", + "sha256:d9bdec0013ef1eb5a84ab39a3b3868911598afa494f5faa038647101504e2b81" ], "markers": "python_version >= '3.6'", - "version": "==0.18.0" + "version": "==3.0.6" + }, + "pyrsistent": { + "hashes": [ + "sha256:0e3e1fcc45199df76053026a51cc59ab2ea3fc7c094c6627e93b7b44cdae2c8c", + "sha256:1b34eedd6812bf4d33814fca1b66005805d3640ce53140ab8bbb1e2651b0d9bc", + "sha256:4ed6784ceac462a7d6fcb7e9b663e93b9a6fb373b7f43594f9ff68875788e01e", + "sha256:5d45866ececf4a5fff8742c25722da6d4c9e180daa7b405dc0a2a2790d668c26", + "sha256:636ce2dc235046ccd3d8c56a7ad54e99d5c1cd0ef07d9ae847306c91d11b5fec", + "sha256:6455fc599df93d1f60e1c5c4fe471499f08d190d57eca040c0ea182301321286", + "sha256:6bc66318fb7ee012071b2792024564973ecc80e9522842eb4e17743604b5e045", + "sha256:7bfe2388663fd18bd8ce7db2c91c7400bf3e1a9e8bd7d63bf7e77d39051b85ec", + "sha256:7ec335fc998faa4febe75cc5268a9eac0478b3f681602c1f27befaf2a1abe1d8", + "sha256:914474c9f1d93080338ace89cb2acee74f4f666fb0424896fcfb8d86058bf17c", + "sha256:b568f35ad53a7b07ed9b1b2bae09eb15cdd671a5ba5d2c66caee40dbf91c68ca", + "sha256:cdfd2c361b8a8e5d9499b9082b501c452ade8bbf42aef97ea04854f4a3f43b22", + "sha256:d1b96547410f76078eaf66d282ddca2e4baae8964364abb4f4dcdde855cd123a", + "sha256:d4d61f8b993a7255ba714df3aca52700f8125289f84f704cf80916517c46eb96", + "sha256:d7a096646eab884bf8bed965bad63ea327e0d0c38989fc83c5ea7b8a87037bfc", + "sha256:df46c854f490f81210870e509818b729db4488e1f30f2a1ce1698b2295a878d1", + "sha256:e24a828f57e0c337c8d8bb9f6b12f09dfdf0273da25fda9e314f0b684b415a07", + "sha256:e4f3149fd5eb9b285d6bfb54d2e5173f6a116fe19172686797c056672689daf6", + "sha256:e92a52c166426efbe0d1ec1332ee9119b6d32fc1f0bbfd55d5c1088070e7fc1b", + "sha256:f87cc2863ef33c709e237d4b5f4502a62a00fab450c9e020892e8e2ede5847f5", + "sha256:fd8da6d0124efa2f67d86fa70c851022f87c98e205f0594e1fae044e7119a5a6" + ], + "markers": "python_version >= '3.7'", + "version": "==0.18.1" }, "python-dateutil": { "hashes": [ @@ -726,11 +744,11 @@ }, "python-telegram-bot": { "hashes": [ - "sha256:44603dad5182f366c576d8c4a1a8f1e45d294621d712ff34ef1ae1b1b14de05d", - "sha256:b06691e55c35943267ee636d9aa702b3579155d2f32e0e2d6d7f11f0b5e727f0" + "sha256:833f39110f5d019b39a6c6fcbabd6ea1627eaaa0a26e618c0be099568672d791", + "sha256:d2c555431821f4ace0c1b7ce12af41999f01b793b275dee131f1034d08c01e3e" ], "index": "pypi", - "version": "==13.8.1" + "version": "==13.10" }, "pytz": { "hashes": [ @@ -749,35 +767,37 @@ }, "pywin32": { "hashes": [ - "sha256:2393c1a40dc4497fd6161b76801b8acd727c5610167762b7c3e9fd058ef4a6ab", - "sha256:251b7a9367355ccd1a4cd69cd8dd24bd57b29ad83edb2957cfa30f7ed9941efa", - "sha256:48dd4e348f1ee9538dd4440bf201ea8c110ea6d9f3a5010d79452e9fa80480d9", - "sha256:496df89f10c054c9285cc99f9d509e243f4e14ec8dfc6d78c9f0bf147a893ab1", - "sha256:543552e66936378bd2d673c5a0a3d9903dba0b0a87235ef0c584f058ceef5872", - "sha256:79cf7e6ddaaf1cd47a9e50cc74b5d770801a9db6594464137b1b86aa91edafcc", - "sha256:af5aea18167a31efcacc9f98a2ca932c6b6a6d91ebe31f007509e293dea12580", - "sha256:d3761ab4e8c5c2dbc156e2c9ccf38dd51f936dc77e58deb940ffbc4b82a30528", - "sha256:e372e477d938a49266136bff78279ed14445e00718b6c75543334351bf535259", - "sha256:fe21c2fb332d03dac29de070f191bdbf14095167f8f2165fdc57db59b1ecc006" + "sha256:2a09632916b6bb231ba49983fe989f2f625cea237219530e81a69239cd0c4559", + "sha256:51cb52c5ec6709f96c3f26e7795b0bf169ee0d8395b2c1d7eb2c029a5008ed51", + "sha256:5f9ec054f5a46a0f4dfd72af2ce1372f3d5a6e4052af20b858aa7df2df7d355b", + "sha256:6fed4af057039f309263fd3285d7b8042d41507343cd5fa781d98fcc5b90e8bb", + "sha256:793bf74fce164bcffd9d57bb13c2c15d56e43c9542a7b9687b4fccf8f8a41aba", + "sha256:79cbb862c11b9af19bcb682891c1b91942ec2ff7de8151e2aea2e175899cda34", + "sha256:7d3271c98434617a11921c5ccf74615794d97b079e22ed7773790822735cc352", + "sha256:aad484d52ec58008ca36bd4ad14a71d7dd0a99db1a4ca71072213f63bf49c7d9", + "sha256:b1675d82bcf6dbc96363fca747bac8bff6f6e4a447a4287ac652aa4b9adc796e", + "sha256:c268040769b48a13367221fced6d4232ed52f044ffafeda247bd9d2c6bdc29ca", + "sha256:d9b5d87ca944eb3aa4cd45516203ead4b37ab06b8b777c54aedc35975dec0dee", + "sha256:fcf44032f5b14fcda86028cdf49b6ebdaea091230eb0a757282aa656e4732439" ], "markers": "platform_system == 'Windows'", - "version": "==302" + "version": "==303" }, "redis": { "hashes": [ - "sha256:c8481cf414474e3497ec7971a1ba9b998c8efad0f0d289a009a5bbef040894f9", - "sha256:ccf692811f2c1fc7a92b466aa2599e4a6d2d73d5f736a2c70be600657c0da34a" + "sha256:07420a3fbedd8e012c31d4fadac943fb81568946da202c5a5bc237774e5280a0", + "sha256:bc97d18938ca18d66737d0ef88584a2073069589e4026813cfba9ad6df9a9f40" ], "index": "pypi", - "version": "==4.0.2" + "version": "==4.1.1" }, "requests": { "hashes": [ - "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24", - "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7" + "sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61", + "sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d" ], "index": "pypi", - "version": "==2.26.0" + "version": "==2.27.1" }, "rlp": { "hashes": [ @@ -788,35 +808,35 @@ }, "schema": { "hashes": [ - "sha256:cf97e4cd27e203ab6bb35968532de1ed8991bce542a646f0ff1d643629a4945d", - "sha256:fbb6a52eb2d9facf292f233adcc6008cffd94343c63ccac9a1cb1f3e6de1db17" + "sha256:f06717112c61895cabc4707752b88716e8420a8819d71404501e114f91043197", + "sha256:f3ffdeeada09ec34bf40d7d79996d9f7175db93b7a5065de0faa7f41083c1e6c" ], "index": "pypi", - "version": "==0.7.4" + "version": "==0.7.5" }, "six": { "hashes": [ "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", "version": "==1.16.0" }, "slack-bolt": { "hashes": [ - "sha256:747eb6452c5bfcea0a2cf0a3198d3f9397abc0b8c7d57eed63aee324bcbd52a3", - "sha256:e7a8444c0829e2320a16ca8c47782448a01455372488dd508ee0fb72bcac8141" + "sha256:12ade47fa61f66804715e54d0b3defe968d40b96d059afce1cb3bb9b4686bd05", + "sha256:be0a65a6d295101af75f4977c617a7702de7a6397e4e972fa026bccfea5f40e8" ], "index": "pypi", - "version": "==1.10.0" + "version": "==1.11.2" }, "slack-sdk": { "hashes": [ - "sha256:a384d91c10229f94a9b2cae2ec5af2a683a3d5aee1287c01238630ab42747287", - "sha256:f779ff3dc266491b02ad056d28038ec5d708b2a438a3a8f8794fb1121d8274e2" + "sha256:54f2a5f7419f1ab932af9e3200f7f2f93db96e0f0eb8ad7d3b4214aa9f124641", + "sha256:aae6ce057e286a5e7fe7a9f256e85b886eee556def8e04b82b08f699e64d7f67" ], "markers": "python_full_version >= '3.6.0'", - "version": "==3.12.0" + "version": "==3.13.0" }, "tenacity": { "hashes": [ @@ -883,19 +903,11 @@ }, "twilio": { "hashes": [ - "sha256:b61a1209136e7e3d0b9e50653a821ef6a81b87f3b7c513144e5f0d955dca5bba", - "sha256:fc3f5c34abd7b7cda9f4802909d01e65bf296a3b237fea4cd17e969cc838645a" + "sha256:91922bd2e347dd279868d2102404a7da056169da10a8b10be3fd9eb9c6bab391", + "sha256:ef2b38de9c06ae55570313af30cfc5c215c272cb54a8614da209be1a7d7b5ca2" ], "index": "pypi", - "version": "==7.3.1" - }, - "typing-extensions": { - "hashes": [ - "sha256:2cdf80e4e04866a9b3689a51869016d36db0814d84b8d8a568d22781d45d27ed", - "sha256:829704698b22e13ec9eaf959122315eabb370b0884400e9818334d8b677023d9" - ], - "markers": "python_version >= '3.6'", - "version": "==4.0.0" + "version": "==7.5.0" }, "tzdata": { "hashes": [ @@ -915,11 +927,11 @@ }, "urllib3": { "hashes": [ - "sha256:4987c65554f7a2dbf30c18fd48778ef124af6fab771a377103da0585e2336ece", - "sha256:c4fdf4019605b6e5423637e01bc9fe4daef873709a7973e195ceba0a62bbc844" + "sha256:000ca7f471a233c2251c6c7023ee85305721bfdf18621ebff4fd17a8653427ed", + "sha256:0e7c33d9a63e7ddfcb86780aac87befc2fbddf46c58dbb487e0855f7ceec283c" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", - "version": "==1.26.7" + "version": "==1.26.8" }, "varint": { "hashes": [ @@ -958,11 +970,11 @@ }, "web3": { "hashes": [ - "sha256:0e9ae7db064a3efee611af0c18d921cc7a4b320380a1f734b0c837518e62484b", - "sha256:24fdedb85eac0068f7c964e8b6713a5623e4a1e0d95ebabd1939fef933007c02" + "sha256:074163febd05780d66774a74e081fb7093285266fc7ea3541e71ec6cdbad8919", + "sha256:d4ba2e92b4759b43674fa0ae2b7303bc34cd5665a3252ab033c81a9acd01a38e" ], "index": "pypi", - "version": "==5.25.0" + "version": "==5.26.0" }, "websockets": { "hashes": [ @@ -1142,56 +1154,56 @@ "develop": { "coverage": { "hashes": [ - "sha256:046647b96969fda1ae0605f61288635209dd69dcd27ba3ec0bf5148bc157f954", - "sha256:06d009e8a29483cbc0520665bc46035ffe9ae0e7484a49f9782c2a716e37d0a0", - "sha256:0cde7d9fe2fb55ff68ebe7fb319ef188e9b88e0a3d1c9c5db7dd829cd93d2193", - "sha256:1de9c6f5039ee2b1860b7bad2c7bc3651fbeb9368e4c4d93e98a76358cdcb052", - "sha256:24ed38ec86754c4d5a706fbd5b52b057c3df87901a8610d7e5642a08ec07087e", - "sha256:27a3df08a855522dfef8b8635f58bab81341b2fb5f447819bc252da3aa4cf44c", - "sha256:310c40bed6b626fd1f463e5a83dba19a61c4eb74e1ac0d07d454ebbdf9047e9d", - "sha256:3348865798c077c695cae00da0924136bb5cc501f236cfd6b6d9f7a3c94e0ec4", - "sha256:35b246ae3a2c042dc8f410c94bcb9754b18179cdb81ff9477a9089dbc9ecc186", - "sha256:3f546f48d5d80a90a266769aa613bc0719cb3e9c2ef3529d53f463996dd15a9d", - "sha256:586d38dfc7da4a87f5816b203ff06dd7c1bb5b16211ccaa0e9788a8da2b93696", - "sha256:5d3855d5d26292539861f5ced2ed042fc2aa33a12f80e487053aed3bcb6ced13", - "sha256:610c0ba11da8de3a753dc4b1f71894f9f9debfdde6559599f303286e70aeb0c2", - "sha256:62646d98cf0381ffda301a816d6ac6c35fc97aa81b09c4c52d66a15c4bef9d7c", - "sha256:66af99c7f7b64d050d37e795baadf515b4561124f25aae6e1baa482438ecc388", - "sha256:675adb3b3380967806b3cbb9c5b00ceb29b1c472692100a338730c1d3e59c8b9", - "sha256:6e5a8c947a2a89c56655ecbb789458a3a8e3b0cbf4c04250331df8f647b3de59", - "sha256:7a39590d1e6acf6a3c435c5d233f72f5d43b585f5be834cff1f21fec4afda225", - "sha256:80cb70264e9a1d04b519cdba3cd0dc42847bf8e982a4d55c769b9b0ee7cdce1e", - "sha256:82fdcb64bf08aa5db881db061d96db102c77397a570fbc112e21c48a4d9cb31b", - "sha256:8492d37acdc07a6eac6489f6c1954026f2260a85a4c2bb1e343fe3d35f5ee21a", - "sha256:94f558f8555e79c48c422045f252ef41eb43becdd945e9c775b45ebfc0cbd78f", - "sha256:958ac66272ff20e63d818627216e3d7412fdf68a2d25787b89a5c6f1eb7fdd93", - "sha256:95a58336aa111af54baa451c33266a8774780242cab3704b7698d5e514840758", - "sha256:96129e41405887a53a9cc564f960d7f853cc63d178f3a182fdd302e4cab2745b", - "sha256:97ef6e9119bd39d60ef7b9cd5deea2b34869c9f0b9777450a7e3759c1ab09b9b", - "sha256:98d44a8136eebbf544ad91fef5bd2b20ef0c9b459c65a833c923d9aa4546b204", - "sha256:9d2c2e3ce7b8cc932a2f918186964bd44de8c84e2f9ef72dc616f5bb8be22e71", - "sha256:a300b39c3d5905686c75a369d2a66e68fd01472ea42e16b38c948bd02b29e5bd", - "sha256:a34fccb45f7b2d890183a263578d60a392a1a218fdc12f5bce1477a6a68d4373", - "sha256:a4d48e42e17d3de212f9af44f81ab73b9378a4b2b8413fd708d0d9023f2bbde4", - "sha256:af45eea024c0e3a25462fade161afab4f0d9d9e0d5a5d53e86149f74f0a35ecc", - "sha256:ba6125d4e55c0b8e913dad27b22722eac7abdcb1f3eab1bd090eee9105660266", - "sha256:bc1ee1318f703bc6c971da700d74466e9b86e0c443eb85983fb2a1bd20447263", - "sha256:c18725f3cffe96732ef96f3de1939d81215fd6d7d64900dcc4acfe514ea4fcbf", - "sha256:c8e9c4bcaaaa932be581b3d8b88b677489975f845f7714efc8cce77568b6711c", - "sha256:cc799916b618ec9fd00135e576424165691fec4f70d7dc12cfaef09268a2478c", - "sha256:cd2d11a59afa5001ff28073ceca24ae4c506da4355aba30d1e7dd2bd0d2206dc", - "sha256:d0a595a781f8e186580ff8e3352dd4953b1944289bec7705377c80c7e36c4d6c", - "sha256:d3c5f49ce6af61154060640ad3b3281dbc46e2e0ef2fe78414d7f8a324f0b649", - "sha256:d9a635114b88c0ab462e0355472d00a180a5fbfd8511e7f18e4ac32652e7d972", - "sha256:e5432d9c329b11c27be45ee5f62cf20a33065d482c8dec1941d6670622a6fb8f", - "sha256:eab14fdd410500dae50fd14ccc332e65543e7b39f6fc076fe90603a0e5d2f929", - "sha256:ebcc03e1acef4ff44f37f3c61df478d6e469a573aa688e5a162f85d7e4c3860d", - "sha256:fae3fe111670e51f1ebbc475823899524e3459ea2db2cb88279bbfb2a0b8a3de", - "sha256:fd92ece726055e80d4e3f01fff3b91f54b18c9c357c48fcf6119e87e2461a091", - "sha256:ffa545230ca2ad921ad066bf8fd627e7be43716b6e0fcf8e32af1b8188ccb0ab" + "sha256:01774a2c2c729619760320270e42cd9e797427ecfddd32c2a7b639cdc481f3c0", + "sha256:03b20e52b7d31be571c9c06b74746746d4eb82fc260e594dc662ed48145e9efd", + "sha256:0a7726f74ff63f41e95ed3a89fef002916c828bb5fcae83b505b49d81a066884", + "sha256:1219d760ccfafc03c0822ae2e06e3b1248a8e6d1a70928966bafc6838d3c9e48", + "sha256:13362889b2d46e8d9f97c421539c97c963e34031ab0cb89e8ca83a10cc71ac76", + "sha256:174cf9b4bef0db2e8244f82059a5a72bd47e1d40e71c68ab055425172b16b7d0", + "sha256:17e6c11038d4ed6e8af1407d9e89a2904d573be29d51515f14262d7f10ef0a64", + "sha256:215f8afcc02a24c2d9a10d3790b21054b58d71f4b3c6f055d4bb1b15cecce685", + "sha256:22e60a3ca5acba37d1d4a2ee66e051f5b0e1b9ac950b5b0cf4aa5366eda41d47", + "sha256:2641f803ee9f95b1f387f3e8f3bf28d83d9b69a39e9911e5bfee832bea75240d", + "sha256:276651978c94a8c5672ea60a2656e95a3cce2a3f31e9fb2d5ebd4c215d095840", + "sha256:3f7c17209eef285c86f819ff04a6d4cbee9b33ef05cbcaae4c0b4e8e06b3ec8f", + "sha256:3feac4084291642165c3a0d9eaebedf19ffa505016c4d3db15bfe235718d4971", + "sha256:49dbff64961bc9bdd2289a2bda6a3a5a331964ba5497f694e2cbd540d656dc1c", + "sha256:4e547122ca2d244f7c090fe3f4b5a5861255ff66b7ab6d98f44a0222aaf8671a", + "sha256:5829192582c0ec8ca4a2532407bc14c2f338d9878a10442f5d03804a95fac9de", + "sha256:5d6b09c972ce9200264c35a1d53d43ca55ef61836d9ec60f0d44273a31aa9f17", + "sha256:600617008aa82032ddeace2535626d1bc212dfff32b43989539deda63b3f36e4", + "sha256:619346d57c7126ae49ac95b11b0dc8e36c1dd49d148477461bb66c8cf13bb521", + "sha256:63c424e6f5b4ab1cf1e23a43b12f542b0ec2e54f99ec9f11b75382152981df57", + "sha256:6dbc1536e105adda7a6312c778f15aaabe583b0e9a0b0a324990334fd458c94b", + "sha256:6e1394d24d5938e561fbeaa0cd3d356207579c28bd1792f25a068743f2d5b282", + "sha256:86f2e78b1eff847609b1ca8050c9e1fa3bd44ce755b2ec30e70f2d3ba3844644", + "sha256:8bdfe9ff3a4ea37d17f172ac0dff1e1c383aec17a636b9b35906babc9f0f5475", + "sha256:8e2c35a4c1f269704e90888e56f794e2d9c0262fb0c1b1c8c4ee44d9b9e77b5d", + "sha256:92b8c845527eae547a2a6617d336adc56394050c3ed8a6918683646328fbb6da", + "sha256:9365ed5cce5d0cf2c10afc6add145c5037d3148585b8ae0e77cc1efdd6aa2953", + "sha256:9a29311bd6429be317c1f3fe4bc06c4c5ee45e2fa61b2a19d4d1d6111cb94af2", + "sha256:9a2b5b52be0a8626fcbffd7e689781bf8c2ac01613e77feda93d96184949a98e", + "sha256:a4bdeb0a52d1d04123b41d90a4390b096f3ef38eee35e11f0b22c2d031222c6c", + "sha256:a9c8c4283e17690ff1a7427123ffb428ad6a52ed720d550e299e8291e33184dc", + "sha256:b637c57fdb8be84e91fac60d9325a66a5981f8086c954ea2772efe28425eaf64", + "sha256:bf154ba7ee2fd613eb541c2bc03d3d9ac667080a737449d1a3fb342740eb1a74", + "sha256:c254b03032d5a06de049ce8bca8338a5185f07fb76600afff3c161e053d88617", + "sha256:c332d8f8d448ded473b97fefe4a0983265af21917d8b0cdcb8bb06b2afe632c3", + "sha256:c7912d1526299cb04c88288e148c6c87c0df600eca76efd99d84396cfe00ef1d", + "sha256:cfd9386c1d6f13b37e05a91a8583e802f8059bebfccde61a418c5808dea6bbfa", + "sha256:d5d2033d5db1d58ae2d62f095e1aefb6988af65b4b12cb8987af409587cc0739", + "sha256:dca38a21e4423f3edb821292e97cec7ad38086f84313462098568baedf4331f8", + "sha256:e2cad8093172b7d1595b4ad66f24270808658e11acf43a8f95b41276162eb5b8", + "sha256:e3db840a4dee542e37e09f30859f1612da90e1c5239a6a2498c473183a50e781", + "sha256:edcada2e24ed68f019175c2b2af2a8b481d3d084798b8c20d15d34f5c733fa58", + "sha256:f467bbb837691ab5a8ca359199d3429a11a01e6dfb3d9dcc676dc035ca93c0a9", + "sha256:f506af4f27def639ba45789fa6fde45f9a217da0be05f8910458e4557eed020c", + "sha256:f614fc9956d76d8a88a88bb41ddc12709caa755666f580af3a688899721efecd", + "sha256:f9afb5b746781fc2abce26193d1c817b7eb0e11459510fba65d2bd77fe161d9e", + "sha256:fb8b8ee99b3fffe4fd86f4c81b35a6bf7e4462cba019997af2fe679365db0c49" ], "index": "pypi", - "version": "==6.1.2" + "version": "==6.2" }, "freezegun": { "hashes": [ @@ -1222,7 +1234,7 @@ "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", "version": "==1.16.0" } } diff --git a/alerter/src/alerter/alerters/contract/chainlink.py b/alerter/src/alerter/alerters/contract/chainlink.py index 0e70a3e68..cf52ec79e 100644 --- a/alerter/src/alerter/alerters/contract/chainlink.py +++ b/alerter/src/alerter/alerters/contract/chainlink.py @@ -150,7 +150,8 @@ def _process_result(self, transformer_data: Dict, cl_alerts.ErrorNoSyncedDataSources, cl_alerts.SyncedDataSourcesFound, data_for_alerting, meta_data['node_parent_id'], - "", "", meta_data['last_monitored'], + meta_data['node_parent_id'], "", + meta_data['last_monitored'], MetricCode.ErrorNoSyncedDataSources.value, "", "Synced EVM data sources found!", None ) @@ -160,7 +161,8 @@ def _process_result(self, transformer_data: Dict, cl_alerts.ErrorContractsNotRetrieved, cl_alerts.ContractsNowRetrieved, data_for_alerting, meta_data['node_parent_id'], - "", "", meta_data['last_monitored'], + meta_data['node_parent_id'], "", + meta_data['last_monitored'], MetricCode.ErrorContractsNotRetrieved.value, "", "Chainlink contracts are now being retrieved!", None ) @@ -212,7 +214,7 @@ def _process_result(self, transformer_data: Dict, if (str_to_bool(configs.price_feed_not_observed['enabled']) and current_missed_observations is not None): sub_config = configs.price_feed_not_observed - self.alerting_factory.\ + self.alerting_factory. \ classify_thresholded_and_conditional_alert( current_missed_observations, sub_config, cl_alerts. @@ -240,7 +242,7 @@ def _process_result(self, transformer_data: Dict, 'deviation'] if current_deviation is not None: - self.alerting_factory.\ + self.alerting_factory. \ classify_thresholded_alert_contract( current_deviation, sub_config, cl_alerts.PriceFeedDeviationInreasedAboveThreshold, @@ -305,9 +307,8 @@ def _process_error(self, data: Dict, data_for_alerting: List) -> None: cl_alerts.ErrorContractsNotRetrieved, cl_alerts.ContractsNowRetrieved, data_for_alerting, meta_data['node_parent_id'], - "", "", meta_data['time'], - MetricCode.ErrorContractsNotRetrieved.value, - data['message'], + meta_data['node_parent_id'], "", meta_data['time'], + MetricCode.ErrorContractsNotRetrieved.value, data['message'], "Chainlink contracts are now being retrieved!", data['code'] ) @@ -316,7 +317,7 @@ def _process_error(self, data: Dict, data_for_alerting: List) -> None: cl_alerts.ErrorNoSyncedDataSources, cl_alerts.SyncedDataSourcesFound, data_for_alerting, meta_data['node_parent_id'], - "", "", meta_data['time'], + meta_data['node_parent_id'], "", meta_data['time'], MetricCode.ErrorNoSyncedDataSources.value, data['message'], "Synced EVM data sources found!", data['code'] ) diff --git a/alerter/src/alerter/alerts/contract/chainlink.py b/alerter/src/alerter/alerts/contract/chainlink.py index 07ae05690..86482562c 100644 --- a/alerter/src/alerter/alerts/contract/chainlink.py +++ b/alerter/src/alerter/alerts/contract/chainlink.py @@ -2,7 +2,7 @@ ChainlinkContractAlertCode) from src.alerter.alert_data import ChainlinkContractAlertData from src.alerter.alerts.alert import Alert -from src.alerter.grouped_alerts_metric_code.contract.\ +from src.alerter.grouped_alerts_metric_code.contract. \ chainlink_contract_metric_code \ import GroupedChainlinkContractAlertsMetricCode as MetricCode @@ -81,7 +81,7 @@ def __init__(self, origin_name: str, severity: str, "The Chainlink Node observing the price feed is {}." .format(proxy_address, origin_name), severity, timestamp, parent_id, origin_id, - MetricCode.ConsensusFailure) + MetricCode.ConsensusFailure, alert_data) class ErrorContractsNotRetrieved(Alert): diff --git a/alerter/src/alerter/grouped_alerts_metric_code/contract/chainlink_contract_metric_code.py b/alerter/src/alerter/grouped_alerts_metric_code/contract/chainlink_contract_metric_code.py index 5b50f7a8e..1e38a49f4 100644 --- a/alerter/src/alerter/grouped_alerts_metric_code/contract/chainlink_contract_metric_code.py +++ b/alerter/src/alerter/grouped_alerts_metric_code/contract/chainlink_contract_metric_code.py @@ -2,8 +2,8 @@ class GroupedChainlinkContractAlertsMetricCode(GroupedAlertsMetricCode): - PriceFeedNotObserved = 'price_feed_not_observed' - PriceFeedDeviation = 'price_feed_deviation' - ConsensusFailure = 'consensus_failure' - ErrorContractsNotRetrieved = 'contracts_not_retrieved' - ErrorNoSyncedDataSources = 'no_synced_data_sources' + PriceFeedNotObserved = 'cl_contract_price_feed_not_observed' + PriceFeedDeviation = 'cl_contract_price_feed_deviation' + ConsensusFailure = 'cl_contract_consensus_failure' + ErrorContractsNotRetrieved = 'cl_contract_contracts_not_retrieved' + ErrorNoSyncedDataSources = 'cl_contract_no_synced_data_sources' diff --git a/alerter/src/alerter/grouped_alerts_metric_code/github.py b/alerter/src/alerter/grouped_alerts_metric_code/github.py index 287518a21..3def9f26e 100644 --- a/alerter/src/alerter/grouped_alerts_metric_code/github.py +++ b/alerter/src/alerter/grouped_alerts_metric_code/github.py @@ -3,4 +3,4 @@ class GroupedGithubAlertsMetricCode(GroupedAlertsMetricCode): GithubRelease = 'github_release' - CannotAccessGithub = 'cannot_access_github' + CannotAccessGithub = 'github_cannot_access' diff --git a/alerter/src/alerter/grouped_alerts_metric_code/node/chainlink_node_metric_code.py b/alerter/src/alerter/grouped_alerts_metric_code/node/chainlink_node_metric_code.py index b7d109e42..f3614f1be 100644 --- a/alerter/src/alerter/grouped_alerts_metric_code/node/chainlink_node_metric_code.py +++ b/alerter/src/alerter/grouped_alerts_metric_code/node/chainlink_node_metric_code.py @@ -2,17 +2,17 @@ class GroupedChainlinkNodeAlertsMetricCode(GroupedAlertsMetricCode): - NoChangeInHeight = 'head_tracker_current_head' - NoChangeInTotalHeadersReceived = 'head_tracker_heads_received_total' - MaxUnconfirmedBlocksThreshold = 'max_unconfirmed_blocks' - ChangeInSourceNode = 'process_start_time_seconds' - GasBumpIncreasedOverNodeGasPriceLimit = \ - 'tx_manager_gas_bump_exceeds_limit_total' - NoOfUnconfirmedTxsThreshold = 'unconfirmed_transactions' - TotalErroredJobRunsThreshold = 'run_status_update_total' - EthBalanceThreshold = 'eth_balance_amount' - EthBalanceTopUp = 'eth_balance_amount_increase' - InvalidUrl = 'invalid_url' - MetricNotFound = 'metric_not_found' - NodeIsDown = 'node_is_down' - PrometheusSourceIsDown = 'prometheus_is_down' + NoChangeInHeight = 'cl_head_tracker_current_head' + NoChangeInTotalHeadersReceived = 'cl_head_tracker_heads_received_total' + MaxUnconfirmedBlocksThreshold = 'cl_max_unconfirmed_blocks' + ChangeInSourceNode = 'cl_process_start_time_seconds' + GasBumpIncreasedOverNodeGasPriceLimit = ( + 'cl_tx_manager_gas_bump_exceeds_limit_total') + NoOfUnconfirmedTxsThreshold = 'cl_unconfirmed_transactions' + TotalErroredJobRunsThreshold = 'cl_run_status_update_total' + EthBalanceThreshold = 'cl_eth_balance_amount' + EthBalanceTopUp = 'cl_eth_balance_amount_increase' + InvalidUrl = 'cl_invalid_url' + MetricNotFound = 'cl_metric_not_found' + NodeIsDown = 'cl_node_is_down' + PrometheusSourceIsDown = 'cl_prometheus_is_down' diff --git a/alerter/src/alerter/grouped_alerts_metric_code/node/evm_node_metric_code.py b/alerter/src/alerter/grouped_alerts_metric_code/node/evm_node_metric_code.py index 6cb324da0..055bd7812 100644 --- a/alerter/src/alerter/grouped_alerts_metric_code/node/evm_node_metric_code.py +++ b/alerter/src/alerter/grouped_alerts_metric_code/node/evm_node_metric_code.py @@ -2,7 +2,7 @@ class GroupedEVMNodeAlertsMetricCode(GroupedAlertsMetricCode): + NodeIsDown = 'evm_node_is_down' BlockHeightDifference = 'evm_block_syncing_block_height_difference' NoChangeInBlockHeight = 'evm_block_syncing_no_change_in_block_height' - NodeIsDown = 'evm_node_is_down' - InvalidUrl = 'invalid_url' + InvalidUrl = 'evm_invalid_url' diff --git a/alerter/src/alerter/grouped_alerts_metric_code/system.py b/alerter/src/alerter/grouped_alerts_metric_code/system.py index a85d0fde0..edffba023 100644 --- a/alerter/src/alerter/grouped_alerts_metric_code/system.py +++ b/alerter/src/alerter/grouped_alerts_metric_code/system.py @@ -3,9 +3,9 @@ class GroupedSystemAlertsMetricCode(GroupedAlertsMetricCode): SystemIsDown = 'system_is_down' - InvalidUrl = 'invalid_url' - OpenFileDescriptorsThreshold = 'open_file_descriptors' + InvalidUrl = 'system_invalid_url' + OpenFileDescriptorsThreshold = 'system_open_file_descriptors' SystemCPUUsageThreshold = 'system_cpu_usage' SystemRAMUsageThreshold = 'system_ram_usage' SystemStorageUsageThreshold = 'system_storage_usage' - MetricNotFound = 'metric_not_found' + MetricNotFound = 'system_metric_not_found' diff --git a/alerter/src/channels_manager/commands/handlers/slack_cmd_handlers.py b/alerter/src/channels_manager/commands/handlers/slack_cmd_handlers.py index bbc824094..46cb52020 100644 --- a/alerter/src/channels_manager/commands/handlers/slack_cmd_handlers.py +++ b/alerter/src/channels_manager/commands/handlers/slack_cmd_handlers.py @@ -513,7 +513,10 @@ def mute_callback(self, ack: Ack, say: Say, say("Performing mute...") # Expected: /panicmute or /panicmute List[] - inputted_severities = command.get('text', '').split(' ')[1:] + inputted_severities = command.get('text', '').split(' ') + inputted_severities = list(filter( + lambda severity: severity != '', inputted_severities) + ) unrecognized_severities = [] recognized_severities = [] @@ -608,7 +611,10 @@ def muteall_callback(self, ack: Ack, say: Say, say("Performing muteall...") # Expected: /muteall or /muteall List[] - inputted_severities = command.get('text', '').split(' ')[1:] + inputted_severities = command.get('text', '').split(' ') + inputted_severities = list(filter( + lambda severity: severity != '', inputted_severities) + ) unrecognized_severities = [] recognized_severities = [] diff --git a/alerter/src/data_store/redis/store_keys.py b/alerter/src/data_store/redis/store_keys.py index 978f819c9..e9562189c 100644 --- a/alerter/src/data_store/redis/store_keys.py +++ b/alerter/src/data_store/redis/store_keys.py @@ -72,17 +72,17 @@ _key_base_chain_monitorables_info = 'bc1' # alert_systemX_ -_key_alert_open_file_descriptors = 'alert_system1' +_key_alert_system_open_file_descriptors = 'alert_system1' _key_alert_system_cpu_usage = 'alert_system2' _key_alert_system_storage_usage = 'alert_system3' _key_alert_system_ram_usage = 'alert_system4' _key_alert_system_is_down = 'alert_system5' -_key_alert_metric_not_found = 'alert_system6' -_key_alert_invalid_url = 'alert_system7' +_key_alert_system_metric_not_found = 'alert_system6' +_key_alert_system_invalid_url = 'alert_system7' # alert_githubX_ _key_alert_github_release = 'alert_github1' -_key_alert_cannot_access_github = 'alert_github2' +_key_alert_github_cannot_access = 'alert_github2' # alert_cl_nodeX_ _key_alert_cl_head_tracker_current_head = 'alert_cl_node1' @@ -103,6 +103,9 @@ _key_alert_cl_contract_price_feed_not_observed = 'alert_cl_contract1' _key_alert_cl_contract_price_feed_deviation = 'alert_cl_contract2' _key_alert_cl_contract_consensus_failure = 'alert_cl_contract3' +# alert_cl_contractX +_key_alert_cl_contract_contracts_not_retrieved = 'alert_cl_contract4' +_key_alert_cl_contract_no_synced_data_sources = 'alert_cl_contract5' # alert_evm_nodeX_ _key_alert_evm_node_is_down = 'alert_evm_node1' @@ -131,8 +134,8 @@ def get_alerter_mute() -> str: @staticmethod def get_system_process_cpu_seconds_total(system_id: str) -> str: - return Keys._as_prefix(_key_system_process_cpu_seconds_total) \ - + system_id + return Keys._as_prefix(_key_system_process_cpu_seconds_total) + ( + system_id) @staticmethod def get_system_process_memory_usage(system_id: str) -> str: @@ -165,29 +168,29 @@ def get_system_network_transmit_bytes_per_second(system_id: str) -> str: @staticmethod def get_system_network_receive_bytes_per_second(system_id: str) -> str: - return Keys._as_prefix(_key_system_network_receive_bytes_per_second) \ - + system_id + return Keys._as_prefix(_key_system_network_receive_bytes_per_second) + ( + system_id) @staticmethod def get_system_network_receive_bytes_total(system_id: str) -> str: - return Keys._as_prefix(_key_system_network_receive_bytes_total) \ - + system_id + return Keys._as_prefix(_key_system_network_receive_bytes_total) + ( + system_id) @staticmethod def get_system_network_transmit_bytes_total(system_id: str) -> str: - return Keys._as_prefix(_key_system_network_transmit_bytes_total) \ - + system_id + return Keys._as_prefix(_key_system_network_transmit_bytes_total) + ( + system_id) @staticmethod def get_system_disk_io_time_seconds_total(system_id: str) -> str: - return Keys._as_prefix(_key_system_disk_io_time_seconds_total) \ - + system_id + return Keys._as_prefix(_key_system_disk_io_time_seconds_total) + ( + system_id) @staticmethod def get_system_disk_io_time_seconds_in_interval( system_id: str) -> str: - return Keys._as_prefix(_key_system_disk_io_time_seconds_in_interval) \ - + system_id + return Keys._as_prefix(_key_system_disk_io_time_seconds_in_interval) + ( + system_id) @staticmethod def get_system_went_down_at(system_id: str) -> str: @@ -203,8 +206,8 @@ def get_cl_node_current_height(cl_node_id: str) -> str: @staticmethod def get_cl_node_total_block_headers_received(cl_node_id: str) -> str: - return Keys._as_prefix(_key_cl_node_total_block_headers_received) \ - + cl_node_id + return Keys._as_prefix(_key_cl_node_total_block_headers_received) + ( + cl_node_id) @staticmethod def get_cl_node_max_pending_tx_delay(cl_node_id: str) -> str: @@ -212,8 +215,8 @@ def get_cl_node_max_pending_tx_delay(cl_node_id: str) -> str: @staticmethod def get_cl_node_process_start_time_seconds(cl_node_id: str) -> str: - return Keys._as_prefix(_key_cl_node_process_start_time_seconds) \ - + cl_node_id + return Keys._as_prefix(_key_cl_node_process_start_time_seconds) + ( + cl_node_id) @staticmethod def get_cl_node_total_gas_bumps(cl_node_id: str) -> str: @@ -221,8 +224,8 @@ def get_cl_node_total_gas_bumps(cl_node_id: str) -> str: @staticmethod def get_cl_node_total_gas_bumps_exceeds_limit(cl_node_id: str) -> str: - return Keys._as_prefix(_key_cl_node_total_gas_bumps_exceeds_limit) \ - + cl_node_id + return Keys._as_prefix(_key_cl_node_total_gas_bumps_exceeds_limit) + ( + cl_node_id) @staticmethod def get_cl_node_no_of_unconfirmed_txs(cl_node_id: str) -> str: @@ -242,18 +245,18 @@ def get_cl_node_eth_balance_info(cl_node_id: str) -> str: @staticmethod def get_cl_node_went_down_at_prometheus(cl_node_id: str) -> str: - return Keys._as_prefix(_key_cl_node_went_down_at_prometheus) + \ - cl_node_id + return Keys._as_prefix(_key_cl_node_went_down_at_prometheus) + ( + cl_node_id) @staticmethod def get_cl_node_last_prometheus_source_used(cl_node_id: str) -> str: - return Keys._as_prefix(_key_cl_node_last_prometheus_source_used) \ - + cl_node_id + return Keys._as_prefix(_key_cl_node_last_prometheus_source_used) + ( + cl_node_id) @staticmethod def get_cl_node_last_monitored_prometheus(cl_node_id: str) -> str: - return Keys._as_prefix(_key_cl_node_last_monitored_prometheus) \ - + cl_node_id + return Keys._as_prefix(_key_cl_node_last_monitored_prometheus) + ( + cl_node_id) @staticmethod def get_evm_node_current_height(evm_node_id: str) -> str: @@ -274,63 +277,63 @@ def get_evm_node_syncing(evm_node_id: str) -> str: @staticmethod def get_cl_contract_version(cl_node_id: str, contract_proxy_address: str) -> str: - return Keys._as_prefix(_key_cl_contract_version) + Keys._as_prefix( - cl_node_id) + contract_proxy_address + return Keys._as_prefix(_key_cl_contract_version) + ( + Keys._as_prefix(cl_node_id) + contract_proxy_address) @staticmethod def get_cl_contract_aggregator_address(cl_node_id: str, contract_proxy_address: str) -> str: - return Keys._as_prefix(_key_cl_contract_aggregator_address) + \ - Keys._as_prefix(cl_node_id) + contract_proxy_address + return Keys._as_prefix(_key_cl_contract_aggregator_address) + ( + Keys._as_prefix(cl_node_id) + contract_proxy_address) @staticmethod def get_cl_contract_latest_round(cl_node_id: str, contract_proxy_address: str) -> str: - return Keys._as_prefix(_key_cl_contract_latest_round) + \ - Keys._as_prefix(cl_node_id) + contract_proxy_address + return Keys._as_prefix(_key_cl_contract_latest_round) + ( + Keys._as_prefix(cl_node_id) + contract_proxy_address) @staticmethod def get_cl_contract_latest_answer(cl_node_id: str, contract_proxy_address: str) -> str: - return Keys._as_prefix(_key_cl_contract_latest_answer) + \ - Keys._as_prefix(cl_node_id) + contract_proxy_address + return Keys._as_prefix(_key_cl_contract_latest_answer) + ( + Keys._as_prefix(cl_node_id) + contract_proxy_address) @staticmethod def get_cl_contract_latest_timestamp(cl_node_id: str, contract_proxy_address: str) -> str: - return Keys._as_prefix(_key_cl_contract_latest_timestamp) + \ - Keys._as_prefix(cl_node_id) + contract_proxy_address + return Keys._as_prefix(_key_cl_contract_latest_timestamp) + ( + Keys._as_prefix(cl_node_id) + contract_proxy_address) @staticmethod def get_cl_contract_answered_in_round(cl_node_id: str, contract_proxy_address: str) -> str: - return Keys._as_prefix(_key_cl_contract_answered_in_round) + \ - Keys._as_prefix(cl_node_id) + contract_proxy_address + return Keys._as_prefix(_key_cl_contract_answered_in_round) + ( + Keys._as_prefix(cl_node_id) + contract_proxy_address) @staticmethod def get_cl_contract_withdrawable_payment(cl_node_id: str, contract_proxy_address: str ) -> str: - return Keys._as_prefix(_key_cl_contract_withdrawable_payment) + \ - Keys._as_prefix(cl_node_id) + contract_proxy_address + return Keys._as_prefix(_key_cl_contract_withdrawable_payment) + ( + Keys._as_prefix(cl_node_id) + contract_proxy_address) @staticmethod def get_cl_contract_owed_payment(cl_node_id: str, contract_proxy_address: str) -> str: - return Keys._as_prefix(_key_cl_contract_owed_payment) + \ - Keys._as_prefix(cl_node_id) + contract_proxy_address + return Keys._as_prefix(_key_cl_contract_owed_payment) + ( + Keys._as_prefix(cl_node_id) + contract_proxy_address) @staticmethod def get_cl_contract_last_monitored(cl_node_id: str, contract_proxy_address: str) -> str: - return Keys._as_prefix(_key_cl_contract_last_monitored) + \ - Keys._as_prefix(cl_node_id) + contract_proxy_address + return Keys._as_prefix(_key_cl_contract_last_monitored) + ( + Keys._as_prefix(cl_node_id) + contract_proxy_address) @staticmethod def get_cl_contract_last_round_observed( cl_node_id: str, contract_proxy_address: str) -> str: - return Keys._as_prefix(_key_cl_contract_last_round_observed) + \ - Keys._as_prefix(cl_node_id) + contract_proxy_address + return Keys._as_prefix(_key_cl_contract_last_round_observed) + ( + Keys._as_prefix(cl_node_id) + contract_proxy_address) @staticmethod def get_cl_contract_historical_rounds(cl_node_id: str, @@ -360,8 +363,9 @@ def get_config(routing_key: str) -> str: return Keys._as_prefix(_key_config) + routing_key @staticmethod - def get_alert_open_file_descriptors(origin_id: str) -> str: - return Keys._as_prefix(_key_alert_open_file_descriptors) + origin_id + def get_alert_system_open_file_descriptors(origin_id: str) -> str: + return Keys._as_prefix(_key_alert_system_open_file_descriptors) + ( + origin_id) @staticmethod def get_alert_system_cpu_usage(origin_id: str) -> str: @@ -380,20 +384,20 @@ def get_alert_system_is_down(origin_id: str) -> str: return Keys._as_prefix(_key_alert_system_is_down) + origin_id @staticmethod - def get_alert_invalid_url(origin_id: str) -> str: - return Keys._as_prefix(_key_alert_invalid_url) + origin_id + def get_alert_system_invalid_url(origin_id: str) -> str: + return Keys._as_prefix(_key_alert_system_invalid_url) + origin_id @staticmethod - def get_alert_metric_not_found(origin_id: str) -> str: - return Keys._as_prefix(_key_alert_metric_not_found) + origin_id + def get_alert_system_metric_not_found(origin_id: str) -> str: + return Keys._as_prefix(_key_alert_system_metric_not_found) + origin_id @staticmethod def get_alert_github_release(origin_id: str) -> str: return Keys._as_prefix(_key_alert_github_release) + origin_id @staticmethod - def get_alert_cannot_access_github(origin_id: str) -> str: - return Keys._as_prefix(_key_alert_cannot_access_github) + origin_id + def get_alert_github_cannot_access(origin_id: str) -> str: + return Keys._as_prefix(_key_alert_github_cannot_access) + origin_id @staticmethod def get_alert_cl_prometheus_is_down(origin_id: str) -> str: @@ -460,41 +464,48 @@ def get_alert_cl_head_tracker_current_head(origin_id: str) -> str: def get_alert_cl_contract_price_feed_not_observed( cl_node_id: str, contract_proxy_address: str) -> str: return Keys._as_prefix( - _key_alert_cl_contract_price_feed_not_observed) + \ - Keys._as_prefix(cl_node_id) + contract_proxy_address + _key_alert_cl_contract_price_feed_not_observed) + ( + Keys._as_prefix(cl_node_id) + contract_proxy_address) @staticmethod def get_alert_cl_contract_price_feed_deviation( cl_node_id: str, contract_proxy_address: str) -> str: - return Keys._as_prefix(_key_alert_cl_contract_price_feed_deviation) + \ - Keys._as_prefix(cl_node_id) + contract_proxy_address + return Keys._as_prefix(_key_alert_cl_contract_price_feed_deviation) + ( + Keys._as_prefix(cl_node_id) + contract_proxy_address) @staticmethod def get_alert_cl_contract_consensus_failure( cl_node_id: str, contract_proxy_address: str) -> str: - return Keys._as_prefix( - _key_alert_cl_contract_consensus_failure) + \ - Keys._as_prefix(cl_node_id) + contract_proxy_address + return Keys._as_prefix(_key_alert_cl_contract_consensus_failure) + ( + Keys._as_prefix(cl_node_id) + contract_proxy_address) + + @staticmethod + def get_alert_cl_contract_contracts_not_retrieved() -> str: + return _key_alert_cl_contract_contracts_not_retrieved + + @staticmethod + def get_alert_cl_contract_no_synced_data_sources() -> str: + return _key_alert_cl_contract_no_synced_data_sources @staticmethod - def get_alert_evm_evm_node_is_down(evm_node_id: str) -> str: + def get_alert_evm_node_is_down(evm_node_id: str) -> str: return Keys._as_prefix(_key_alert_evm_node_is_down) + evm_node_id @staticmethod - def get_alert_evm_evm_block_syncing_block_height_difference( + def get_alert_evm_block_syncing_block_height_difference( evm_node_id: str) -> str: return Keys._as_prefix( _key_alert_evm_block_syncing_block_height_difference) + evm_node_id @staticmethod - def get_alert_evm_evm_block_syncing_no_change_in_block_height( + def get_alert_evm_block_syncing_no_change_in_block_height( evm_node_id: str) -> str: return Keys._as_prefix( - _key_alert_evm_block_syncing_no_change_in_block_height) + \ - evm_node_id + _key_alert_evm_block_syncing_no_change_in_block_height) + ( + evm_node_id) @staticmethod - def get_alert_evm_evm_invalid_url( + def get_alert_evm_invalid_url( evm_node_id: str) -> str: return Keys._as_prefix(_key_alert_evm_invalid_url) + evm_node_id diff --git a/alerter/src/data_store/stores/alert.py b/alerter/src/data_store/stores/alert.py index a05123e5e..cdf6ed02c 100644 --- a/alerter/src/data_store/stores/alert.py +++ b/alerter/src/data_store/stores/alert.py @@ -17,10 +17,8 @@ from src.data_store.stores.store import Store from src.message_broker.rabbitmq.rabbitmq_api import RabbitMQApi from src.utils.constants.data import (EXPIRE_METRICS, - CHAINLINK_METRICS_TO_STORE, - SYSTEM_METRICS_TO_STORE, CHAINLINK_CONTRACT_METRICS_TO_STORE, - EVM_METRICS_TO_STORE) + CHAIN_SOURCED_METRICS) from src.utils.constants.rabbitmq import (STORE_EXCHANGE, HEALTH_CHECK_EXCHANGE, ALERT_STORE_INPUT_QUEUE_NAME, ALERT_STORE_INPUT_ROUTING_KEY, TOPIC) @@ -243,42 +241,33 @@ def _process_redis_store(self, alert: Dict) -> None: 'message': alert['message'], 'timestamp': alert['timestamp'], 'expiry': None} - key = alert['origin_id'] + origin_id = alert['origin_id'] + metric = alert['metric'] # Check if this metric cannot be overwritten and has to be deleted - if alert['metric'] in EXPIRE_METRICS: + if metric in EXPIRE_METRICS: metric_data['expiry'] = alert['timestamp'] + 600 - if alert['metric'] in CHAINLINK_METRICS_TO_STORE: - self.redis.hset( - Keys.get_hash_parent(alert['parent_id']), - eval('Keys.get_alert_cl_{}(key)'.format(alert['metric'])), - json.dumps(metric_data) - ) - elif alert['metric'] in SYSTEM_METRICS_TO_STORE: - self.redis.hset( - Keys.get_hash_parent(alert['parent_id']), - eval('Keys.get_alert_{}(key)'.format(alert['metric'])), - json.dumps(metric_data) - ) - elif alert['metric'] in EVM_METRICS_TO_STORE: - self.redis.hset( - Keys.get_hash_parent(alert['parent_id']), - eval('Keys.get_alert_evm_{}(key)'.format(alert['metric'])), - json.dumps(metric_data) - ) - elif alert['metric'] in CHAINLINK_CONTRACT_METRICS_TO_STORE: - contract_proxy_address = alert['alert_data'][ - 'contract_proxy_address'] - self.redis.hset( - Keys.get_hash_parent(alert['parent_id']), - eval('Keys.get_alert_cl_contract_{}(key, ' - 'contract_proxy_address)'.format(alert['metric'])), - json.dumps(metric_data) - ) + if metric in CHAINLINK_CONTRACT_METRICS_TO_STORE: + if metric in CHAIN_SOURCED_METRICS: + self.redis.hset( + Keys.get_hash_parent(alert['parent_id']), + eval('Keys.get_alert_{}()'.format( + metric)), + json.dumps(metric_data) + ) + else: + contract_proxy_address = alert['alert_data'][ + 'contract_proxy_address'] + self.redis.hset( + Keys.get_hash_parent(alert['parent_id']), + eval('Keys.get_alert_{}(origin_id, ' + 'contract_proxy_address)'.format(metric)), + json.dumps(metric_data) + ) else: self.redis.hset( Keys.get_hash_parent(alert['parent_id']), - eval('Keys.get_alert_{}(key)'.format(alert['metric'])), + eval('Keys.get_alert_{}(origin_id)'.format(metric)), json.dumps(metric_data) ) diff --git a/alerter/src/monitors/node/chainlink.py b/alerter/src/monitors/node/chainlink.py index 7b66ec48e..0a05417dd 100644 --- a/alerter/src/monitors/node/chainlink.py +++ b/alerter/src/monitors/node/chainlink.py @@ -36,8 +36,8 @@ def __init__(self, monitor_name: str, node_config: ChainlinkNodeConfig, 'head_tracker_heads_received_total': 'strict', 'max_unconfirmed_blocks': 'strict', 'process_start_time_seconds': 'strict', - 'tx_manager_num_gas_bumps_total': 'strict', - 'tx_manager_gas_bump_exceeds_limit_total': 'strict', + 'tx_manager_num_gas_bumps_total': 'optional', + 'tx_manager_gas_bump_exceeds_limit_total': 'optional', 'unconfirmed_transactions': 'strict', 'gas_updater_set_gas_price': 'optional', 'eth_balance': 'strict', @@ -205,50 +205,71 @@ def _process_retrieved_prometheus_data(self, data: Dict) -> Dict: } } - multiple_value_metrics = { - 'gas_updater_set_gas_price', - 'eth_balance', - 'run_status_update_total' + # The Chainlink team is pushing towards having multi-chain chainlink + # nodes. Although this change is not being suggested to node operators + # yet, the prometheus endpoint already supports multi-chains. From our + # side for now we will still assume that each node supports only one + # chain, thus for each metric we will consider the first value we find. + + # These are metrics with one value which are multi-node compatible + one_value_multi_node_compatible_metrics = { + 'head_tracker_current_head', + 'head_tracker_heads_received_total', + 'max_unconfirmed_blocks', + 'tx_manager_num_gas_bumps_total', + 'tx_manager_gas_bump_exceeds_limit_total', + 'unconfirmed_transactions', } - one_value_metrics = { - key for key in data_copy if key not in multiple_value_metrics - } - # Add each one value metric and its value to the processed data + for metric in one_value_multi_node_compatible_metrics: + processed_data['result']['data'][metric] = ( + None if data_copy[metric] is None + else data_copy[metric][list(data_copy[metric])[0]] + ) + self.logger.debug("%s %s: %s", self.node_config, metric, + processed_data['result']['data'][metric]) + + # These are metrics with one value which are not multi-node compatible + one_value_metrics = {'process_start_time_seconds'} for metric in one_value_metrics: - value = data_copy[metric] - self.logger.debug("%s %s: %s", self.node_config, metric, value) - processed_data['result']['data'][metric] = value + self.logger.debug("%s %s: %s", self.node_config, metric, + data_copy[metric]) + processed_data['result']['data'][metric] = data_copy[metric] # Add gas_updater_set_gas_price info to the processed data. Note we will - # process the first percentile object we find. It is very unlikely to - # find multiple. + # process the first percentile object we find. processed_data['result']['data']['gas_updater_set_gas_price'] = {} set_gas_price_dict = processed_data['result']['data'][ 'gas_updater_set_gas_price'] if data_copy['gas_updater_set_gas_price'] is not None: for _, data_subset in enumerate( data_copy['gas_updater_set_gas_price']): - if "percentile" in json.loads(data_subset): - set_gas_price_dict["percentile"] = json.loads(data_subset)[ + data_subset_json = json.loads(data_subset) + if "percentile" in data_subset_json: + set_gas_price_dict["percentile"] = data_subset_json[ "percentile"] set_gas_price_dict["price"] = data_copy[ 'gas_updater_set_gas_price'][data_subset] break else: processed_data['result']['data']['gas_updater_set_gas_price'] = None + self.logger.debug("%s gas_updater_set_gas_price: %s", self.node_config, + processed_data['result']['data'][ + 'gas_updater_set_gas_price']) # Add the ethereum balance to the processed data. We will monitor the - # first account we find. Note, it is very unlikely that a node is mapped - # to multiple addresses. + # first account we find. processed_data['result']['data']['eth_balance'] = {} ethereum_balance_dict = processed_data['result']['data']['eth_balance'] for _, data_subset in enumerate(data_copy['eth_balance']): - if "account" in json.loads(data_subset): - eth_address = json.loads(data_subset)['account'] + data_subset_json = json.loads(data_subset) + if "account" in data_subset_json: + eth_address = data_subset_json['account'] ethereum_balance_dict['address'] = eth_address ethereum_balance_dict['balance'] = data_copy['eth_balance'][ data_subset] break + self.logger.debug("%s eth_balance: %s", self.node_config, + processed_data['result']['data']['eth_balance']) # Add the number of error job runs to the processed data no_of_error_job_runs = 0 @@ -256,7 +277,9 @@ def _process_retrieved_prometheus_data(self, data: Dict) -> Dict: if data_copy['run_status_update_total'] is not None: for _, data_subset in enumerate( data_copy['run_status_update_total']): - if json.loads(data_subset)['status'] == 'errored': + data_subset_json = json.loads(data_subset) + if ('status' in data_subset_json + and data_subset_json['status'] == 'errored'): no_of_error_job_runs += 1 self.logger.debug("%s run_status_update_total_errors: %s", diff --git a/alerter/src/utils/constants/data.py b/alerter/src/utils/constants/data.py index e772fe1ed..facb60f67 100644 --- a/alerter/src/utils/constants/data.py +++ b/alerter/src/utils/constants/data.py @@ -1,3 +1,10 @@ +from src.alerter.grouped_alerts_metric_code.contract. \ + chainlink_contract_metric_code import ( + GroupedChainlinkContractAlertsMetricCode + ) +from src.alerter.grouped_alerts_metric_code.node.chainlink_node_metric_code \ + import GroupedChainlinkNodeAlertsMetricCode + VALID_CHAINLINK_SOURCES = ['prometheus'] RAW_TO_TRANSFORMED_CHAINLINK_METRICS = { 'head_tracker_current_head': 'current_height', @@ -16,30 +23,19 @@ 'max_pending_tx_delay', 'total_gas_bumps', 'total_gas_bumps_exceeds_limit', 'no_of_unconfirmed_txs', 'total_errored_job_runs'] -EXPIRE_METRICS = ['process_start_time_seconds', - 'tx_manager_gas_bump_exceeds_limit_total', - 'eth_balance_amount_increase'] -CHAINLINK_METRICS_TO_STORE = ['head_tracker_current_head', - 'head_tracker_heads_received_total', - 'max_unconfirmed_blocks', - 'process_start_time_seconds', - 'tx_manager_gas_bump_exceeds_limit_total', - 'unconfirmed_transactions', - 'run_status_update_total', - 'eth_balance_amount', - 'eth_balance_amount_increase', - 'invalid_url', - 'metric_not_found', - 'node_is_down', - 'prometheus_is_down'] -SYSTEM_METRICS_TO_STORE = ['open_file_descriptors', - 'system_cpu_usage', - 'system_storage_usage', - 'system_ram_usage', - 'system_is_down'] -CHAINLINK_CONTRACT_METRICS_TO_STORE = ['price_feed_not_observed', - 'price_feed_deviation', - 'consensus_failure'] -EVM_METRICS_TO_STORE = ['evm_node_is_down', - 'evm_block_syncing_block_height_difference', - 'evm_block_syncing_no_change_in_block_height'] +EXPIRE_METRICS = [ + GroupedChainlinkNodeAlertsMetricCode.ChangeInSourceNode, + GroupedChainlinkNodeAlertsMetricCode.GasBumpIncreasedOverNodeGasPriceLimit, + GroupedChainlinkNodeAlertsMetricCode.EthBalanceTopUp +] +CHAINLINK_CONTRACT_METRICS_TO_STORE = [ + GroupedChainlinkContractAlertsMetricCode.PriceFeedNotObserved, + GroupedChainlinkContractAlertsMetricCode.PriceFeedDeviation, + GroupedChainlinkContractAlertsMetricCode.ConsensusFailure, + GroupedChainlinkContractAlertsMetricCode.ErrorContractsNotRetrieved, + GroupedChainlinkContractAlertsMetricCode.ErrorNoSyncedDataSources +] +CHAIN_SOURCED_METRICS = [ + GroupedChainlinkContractAlertsMetricCode.ErrorContractsNotRetrieved, + GroupedChainlinkContractAlertsMetricCode.ErrorNoSyncedDataSources +] diff --git a/alerter/test/alerter/alerters/contract/test_chainlink.py b/alerter/test/alerter/alerters/contract/test_chainlink.py index a7ae67bf7..802d382c0 100644 --- a/alerter/test/alerter/alerters/contract/test_chainlink.py +++ b/alerter/test/alerter/alerters/contract/test_chainlink.py @@ -654,15 +654,15 @@ def test_process_result_does_not_classify_if_metrics_disabled( self.assertEqual(2, mock_error_alert.call_count) call_1 = call( 5019, ErrorContractsNotRetrieved, ContractsNowRetrieved, - data_for_alerting, self.test_parent_id, '', '', + data_for_alerting, self.test_parent_id, self.test_parent_id, '', self.test_latest_timestamp_2, - MetricCode.ErrorContractsNotRetrieved.value, "", + MetricCode.ErrorContractsNotRetrieved.value, '', "Chainlink contracts are now being retrieved!", None) call_2 = call( 5018, ErrorNoSyncedDataSources, SyncedDataSourcesFound, - data_for_alerting, self.test_parent_id, '', '', + data_for_alerting, self.test_parent_id, self.test_parent_id, '', self.test_latest_timestamp_2, - MetricCode.ErrorNoSyncedDataSources.value, "", + MetricCode.ErrorNoSyncedDataSources.value, '', "Synced EVM data sources found!", None) self.assertTrue(call_1 in calls) self.assertTrue(call_2 in calls) @@ -718,15 +718,15 @@ def test_process_result_classifies_correctly_if_data_valid( self.assertEqual(2, mock_error_alert.call_count) call_1 = call( 5018, ErrorNoSyncedDataSources, SyncedDataSourcesFound, - data_for_alerting, self.test_parent_id, "", - "", meta_data['last_monitored'], - MetricCode.ErrorNoSyncedDataSources.value, "", + data_for_alerting, self.test_parent_id, self.test_parent_id, '', + meta_data['last_monitored'], + MetricCode.ErrorNoSyncedDataSources.value, '', "Synced EVM data sources found!", None) call_2 = call( 5019, ErrorContractsNotRetrieved, ContractsNowRetrieved, - data_for_alerting, self.test_parent_id, "", "", + data_for_alerting, self.test_parent_id, self.test_parent_id, '', meta_data['last_monitored'], - MetricCode.ErrorContractsNotRetrieved.value, "", + MetricCode.ErrorContractsNotRetrieved.value, '', "Chainlink contracts are now being retrieved!", None) self.assertTrue(call_1 in calls) self.assertTrue(call_2 in calls) @@ -862,7 +862,7 @@ def test_process_error_classifies_correctly_if_data_valid( self.assertEqual(2, mock_error_alert.call_count) call_1 = call( 5019, ErrorContractsNotRetrieved, ContractsNowRetrieved, - data_for_alerting, self.test_parent_id, '', '', + data_for_alerting, self.test_parent_id, self.test_parent_id, '', self.test_last_monitored, MetricCode.ErrorContractsNotRetrieved.value, self.test_exception.message, @@ -870,7 +870,7 @@ def test_process_error_classifies_correctly_if_data_valid( self.test_exception.code) call_2 = call( 5018, ErrorNoSyncedDataSources, SyncedDataSourcesFound, - data_for_alerting, self.test_parent_id, '', '', + data_for_alerting, self.test_parent_id, self.test_parent_id, '', self.test_last_monitored, MetricCode.ErrorNoSyncedDataSources.value, self.test_exception.message, diff --git a/alerter/test/alerter/factory/test_alerting_factory.py b/alerter/test/alerter/factory/test_alerting_factory.py index 63174585c..e1e34411b 100644 --- a/alerter/test/alerter/factory/test_alerting_factory.py +++ b/alerter/test/alerter/factory/test_alerting_factory.py @@ -1144,9 +1144,10 @@ def test_classify_thresh_time_win_warn_alert_if_below_critical_above_warn( expected_alert_1 = MaxUnconfirmedBlocksDecreasedBelowThresholdAlert( self.test_node_name, current - 1, 'INFO', alert_timestamp, 'CRITICAL', self.test_parent_id, self.test_node_id) + duration = pad + 60 expected_alert_2 = MaxUnconfirmedBlocksIncreasedAboveThresholdAlert( self.test_node_name, current - 1, 'WARNING', alert_timestamp, - pad + 60, 'WARNING', self.test_parent_id, self.test_node_id + duration, 'WARNING', self.test_parent_id, self.test_node_id ) self.assertEqual(2, len(data_for_alerting)) self.assertEqual(expected_alert_1.alert_data, data_for_alerting[0]) @@ -1995,8 +1996,8 @@ def test_classify_thresholded_raises_critical_if_repeat_elapsed( # First critical below threshold alert current = int(self.evm_node_alerts_config - .evm_block_syncing_block_height_difference[ - 'critical_threshold']) + 1 + .evm_block_syncing_block_height_difference[ + 'critical_threshold']) + 1 self.test_evm_factory_instance.classify_thresholded_alert( current, self.evm_node_alerts_config @@ -2111,8 +2112,8 @@ def test_classify_thresh_info_alert_if_below_thresh_and_alert_sent( # First below threshold alert current = int(self.evm_node_alerts_config - .evm_block_syncing_block_height_difference[ - threshold_var]) + 1 + .evm_block_syncing_block_height_difference[ + threshold_var]) + 1 self.test_evm_factory_instance.classify_thresholded_alert( current, self.evm_node_alerts_config @@ -2131,8 +2132,8 @@ def test_classify_thresh_info_alert_if_below_thresh_and_alert_sent( # critical <= warning. current = int( self.evm_node_alerts_config - .evm_block_syncing_block_height_difference[ - 'warning_threshold']) - 1 + .evm_block_syncing_block_height_difference[ + 'warning_threshold']) - 1 alert_timestamp = datetime.now().timestamp() self.test_evm_factory_instance.classify_thresholded_alert( current, @@ -2180,8 +2181,8 @@ def test_classify_thresh_warn_alert_if_below_critical_above_warn( # Send critical decrease below threshold alert current = int(self.evm_node_alerts_config - .evm_block_syncing_block_height_difference[ - 'critical_threshold']) + 1 + .evm_block_syncing_block_height_difference[ + 'critical_threshold']) + 1 self.test_evm_factory_instance.classify_thresholded_alert( current, self.evm_node_alerts_config @@ -2197,8 +2198,8 @@ def test_classify_thresh_warn_alert_if_below_critical_above_warn( # Check that 2 alerts are raised, below critical and above warning current = int(self.evm_node_alerts_config - .evm_block_syncing_block_height_difference[ - 'critical_threshold']) - 1 + .evm_block_syncing_block_height_difference[ + 'critical_threshold']) - 1 alert_timestamp = datetime.now().timestamp() + 10 self.test_evm_factory_instance.classify_thresholded_alert( current, diff --git a/alerter/test/channels_manager/commands/handlers/test_slack_cmd_handlers.py b/alerter/test/channels_manager/commands/handlers/test_slack_cmd_handlers.py index 70958f8c8..708fdd84c 100644 --- a/alerter/test/channels_manager/commands/handlers/test_slack_cmd_handlers.py +++ b/alerter/test/channels_manager/commands/handlers/test_slack_cmd_handlers.py @@ -1310,19 +1310,19 @@ def test_mute_callback_does_not_mute_chains_if_user_not_authorised( chain_name)) @parameterized.expand([ - ("/panicmute BAD_SEVERITY",), - ("/panicmute bad_severity INFO CRITICAL",), - ("/panicmute 123 bad_sev",), ("/panicmute None",), ("/panicmute ",), + ("BAD_SEVERITY",), + ("bad_severity INFO CRITICAL",), + ("123 bad_sev",), ("None",), ]) @mock.patch.object(SlackCommandHandlers, "_authorise") @mock.patch.object(Say, '__call__') def test_mute_callback_does_not_mute_chains_if_unrecognized_severities( - self, inputted_command, mock_say, mock_authorise) -> None: + self, inputted_text, mock_say, mock_authorise) -> None: # To make sure that there are no persistent keys from other tests. self.test_redis.delete_all_unsafe() mock_authorise.return_value = True mock_say.return_value = None - self.test_command = {'text': inputted_command} + self.test_command = {'text': inputted_text} self.test_slack_command_handlers.mute_callback(self.test_ack, self.test_say, @@ -1337,23 +1337,26 @@ def test_mute_callback_does_not_mute_chains_if_unrecognized_severities( chain_name)) @parameterized.expand([ - ("/panicmute INFO",), ("/panicmute CRITICAL",), ("/panicmute error",), - ("/panicmute WARNING",), ("/panicmute INFO WARNING",), - ("/panicmute ERROR critical",), - ("/panicmute ERROR critical INFO",), - ("/panicmute WARNING critical INFO",), - ("/panicmute ERROR critical info warning",), ("/panicmute",) + ("INFO",), ("CRITICAL",), ("error",), + ("WARNING",), ("INFO WARNING",), + ("ERROR critical",), + ("ERROR critical INFO",), + ("WARNING critical INFO",), + ("ERROR critical info warning",), ("",) ]) @mock.patch.object(SlackCommandHandlers, "_authorise") @mock.patch.object(Say, '__call__') def test_mute_callback_mutes_chains_correctly_first_time( - self, inputted_command, mock_say, mock_authorise) -> None: + self, inputted_text, mock_say, mock_authorise) -> None: # To make sure that there are no persistent keys from other tests. self.test_redis.delete_all_unsafe() mock_say.return_value = None mock_authorise.return_value = True - self.test_command = {'text': inputted_command} - inputted_severities = inputted_command.split(' ')[1:] + self.test_command = {'text': inputted_text} + inputted_severities = inputted_text.split(' ') + inputted_severities = list(filter( + lambda severity: severity != '', inputted_severities) + ) if not inputted_severities: inputted_severities_upper = ['CRITICAL', 'INFO', 'ERROR', 'WARNING'] else: @@ -1384,27 +1387,27 @@ def test_mute_callback_mutes_chains_correctly_first_time( self.fail("Expected a mute key for {}".format(chain_name)) @parameterized.expand([ - ("/panicmute INFO", "INFO",), ("/panicmute CRITICAL", "WARNING",), - ("/panicmute error", "CRITICAL",), ("/panicmute WARNING", "ERROR",), - ("/panicmute INFO WARNING", "WARNING",), - ("/panicmute ERROR critical", "INFO",), - ("/panicmute ERROR critical warning", "CRITICAL",), - ("/panicmute WARNING critical INFO", "ERROR",), - ("/panicmute ERROR critical info warning", "ERROR WARNING",), - ("/panicmute", "INFO CRITICAL WARNING ERROR",) + ("INFO", "INFO",), ("CRITICAL", "WARNING",), + ("error", "CRITICAL",), ("WARNING", "ERROR",), + ("INFO WARNING", "WARNING",), + ("ERROR critical", "INFO",), + ("ERROR critical warning", "CRITICAL",), + ("WARNING critical INFO", "ERROR",), + ("ERROR critical info warning", "ERROR WARNING",), + ("", "INFO CRITICAL WARNING ERROR",) ]) @mock.patch.object(SlackCommandHandlers, "_authorise") @mock.patch.object(Say, '__call__') def test_mute_callback_mutes_chains_correctly_already_muted( - self, inputted_command, first_round_muted_severities, + self, inputted_text, first_round_muted_severities, mock_say, mock_authorise) -> None: # To make sure that there are no persistent keys from other tests. self.test_redis.delete_all_unsafe() mock_say.return_value = None mock_authorise.return_value = True - self.test_command = {'text': inputted_command} - inputted_severities = set(inputted_command.split(' ')[1:]) + self.test_command = {'text': inputted_text} + inputted_severities = set(inputted_text.split(' ')) if not inputted_severities: inputted_severities_upper = {'CRITICAL', 'INFO', 'ERROR', 'WARNING'} else: @@ -1453,20 +1456,19 @@ def test_mute_callback_mutes_chains_correctly_already_muted( self.fail("Expected a mute key for {}".format(chain_name)) @parameterized.expand([ - ("/panicmute BAD_SEVERITY", ["BAD_SEVERITY"],), - ("/panicmute bad_severity INFO CRITICAL", ["bad_severity"],), - ("/panicmute 123 bad_sev", ["123", "bad_sev"],), - ("/panicmute None", ["None"]), - ("/panicmute ", ["", ""]), + ("BAD_SEVERITY", ["BAD_SEVERITY"],), + ("bad_severity INFO CRITICAL", ["bad_severity"],), + ("123 bad_sev", ["123", "bad_sev"],), + ("None", ["None"]), ]) @mock.patch.object(SlackCommandHandlers, "_authorise") @mock.patch.object(Say, '__call__') def test_mute_callback_sends_correct_replies_if_unrecognized_severities( - self, inputted_command, unrecognised_severities, mock_say, + self, inputted_text, unrecognised_severities, mock_say, mock_authorise) -> None: mock_authorise.return_value = True mock_say.return_value = None - self.test_command = {'text': inputted_command} + self.test_command = {'text': inputted_text} chain_names = [chain_name for _, chain_name in self.test_associated_chains.items()] @@ -1486,6 +1488,7 @@ def test_mute_callback_sends_correct_replies_if_unrecognized_severities( "" \ "" \ "" \ + "" \ "and PANIC will automatically mute all alerts for {}".format( ', '.join(unrecognised_severities), ', '.join(chain_names)) expected_calls = [call("Performing mute..."), call(expected_reply)] @@ -1523,7 +1526,7 @@ def test_mute_callback_sends_correct_replies_if_error_when_muting( mock_say.return_value = None mock_authorise.return_value = True mock_hexists_unsafe.side_effect = muting_error - self.test_command = {'text': '/panicmute INFO'} + self.test_command = {'text': 'INFO'} self.test_slack_command_handlers.mute_callback(self.test_ack, self.test_say, @@ -1534,28 +1537,28 @@ def test_mute_callback_sends_correct_replies_if_error_when_muting( self.assertEqual(expected_calls, actual_calls) @parameterized.expand([ - ("/panicmute INFO", ["INFO"],), ("/panicmute CRITICAL", ["CRITICAL"],), - ("/panicmute error", ["ERROR"],), ("/panicmute WARNING", ["WARNING"],), - ("/panicmute INFO WARNING", ["INFO", "WARNING"],), - ("/panicmute ERROR critical", ["ERROR", "CRITICAL"],), - ("/panicmute ERROR critical INFO", ["ERROR", "CRITICAL", "INFO"],), - ("/panicmute WARNING critical INFO", ["WARNING", "CRITICAL", "INFO"],), - ("/panicmute ERROR critical info warning", ["ERROR", "CRITICAL", "INFO", - "WARNING"]), - ("/panicmute", ["INFO", "WARNING", "CRITICAL", "ERROR"],) + ("INFO", ["INFO"],), ("CRITICAL", ["CRITICAL"],), + ("error", ["ERROR"],), ("WARNING", ["WARNING"],), + ("INFO WARNING", ["INFO", "WARNING"],), + ("ERROR critical", ["ERROR", "CRITICAL"],), + ("ERROR critical INFO", ["ERROR", "CRITICAL", "INFO"],), + ("WARNING critical INFO", ["WARNING", "CRITICAL", "INFO"],), + ("ERROR critical info warning", ["ERROR", "CRITICAL", "INFO", + "WARNING"]), + ("", ["INFO", "WARNING", "CRITICAL", "ERROR"],) ]) @mock.patch.object(RedisApi, "hset_unsafe") @mock.patch.object(RedisApi, "hexists_unsafe") @mock.patch.object(SlackCommandHandlers, "_authorise") @mock.patch.object(Say, '__call__') def test_mute_callback_sends_correct_replies_if_mute_successful( - self, input_command, inputted_severities, mock_say, + self, inputted_text, inputted_severities, mock_say, mock_authorise, mock_hexists_unsafe, mock_hset_unsafe) -> None: mock_say.return_value = None mock_authorise.return_value = True mock_hexists_unsafe.return_value = False mock_hset_unsafe.return_value = None - self.test_command = {'text': input_command} + self.test_command = {'text': inputted_text} chain_names = [chain_name for _, chain_name in self.test_associated_chains.items()] @@ -1791,18 +1794,18 @@ def test_muteall_callback_does_not_mute_all_if_user_not_authorised( self.fail("Did not expect a muteall key to be set.") @parameterized.expand([ - ("/muteall BAD_SEVERITY",), ("/muteall bad_severity INFO CRITICAL",), - ("/muteall 123 bad_sev",), ("/muteall None",), ("/muteall ",), + ("BAD_SEVERITY",), ("bad_severity INFO CRITICAL",), + ("123 bad_sev",), ("None",), ]) @mock.patch.object(SlackCommandHandlers, "_authorise") @mock.patch.object(Say, '__call__') def test_muteall_callback_does_not_mute_all_if_unrecognised_severities( - self, inputted_command, mock_say, mock_authorise) -> None: + self, inputted_text, mock_say, mock_authorise) -> None: # To make sure that there are no persistent keys from other tests. self.test_redis.delete_all_unsafe() mock_authorise.return_value = True mock_say.return_value = None - self.test_command = {'text': inputted_command} + self.test_command = {'text': inputted_text} self.test_slack_command_handlers.muteall_callback(self.test_ack, self.test_say, @@ -1813,22 +1816,25 @@ def test_muteall_callback_does_not_mute_all_if_unrecognised_severities( self.fail("Did not expect a muteall key to be set.") @parameterized.expand([ - ("/muteall INFO",), ("/muteall CRITICAL",), ("/muteall error",), - ("/muteall WARNING",), ("/muteall INFO WARNING",), - ("/muteall ERROR critical",), ("/muteall ERROR critical INFO",), - ("/muteall WARNING critical INFO",), - ("/muteall ERROR critical info warning",), ("/muteall",) + ("INFO",), ("CRITICAL",), ("error",), + ("WARNING",), ("INFO WARNING",), + ("ERROR critical",), ("ERROR critical INFO",), + ("WARNING critical INFO",), + ("ERROR critical info warning",), ("",), (" ",) ]) @mock.patch.object(SlackCommandHandlers, "_authorise") @mock.patch.object(Say, '__call__') def test_muteall_callback_mutes_all_chains_correctly_first_time( - self, inputted_command, mock_say, mock_authorise) -> None: + self, inputted_text, mock_say, mock_authorise) -> None: # To make sure that there are no persistent keys from other tests. self.test_redis.delete_all_unsafe() mock_say.return_value = None mock_authorise.return_value = True - self.test_command = {'text': inputted_command} - inputted_severities = inputted_command.split(' ')[1:] + self.test_command = {'text': inputted_text} + inputted_severities = inputted_text.split(' ') + inputted_severities = list(filter( + lambda severity: severity != '', inputted_severities) + ) if not inputted_severities: inputted_severities_upper = ['CRITICAL', 'INFO', 'ERROR', 'WARNING'] else: @@ -1855,27 +1861,27 @@ def test_muteall_callback_mutes_all_chains_correctly_first_time( self.fail("Expected a muteall key to be set.") @parameterized.expand([ - ("/muteall INFO", "INFO",), ("/muteall CRITICAL", "WARNING",), - ("/muteall error", "CRITICAL",), ("/muteall WARNING", "ERROR",), - ("/muteall INFO WARNING", "WARNING",), - ("/muteall ERROR critical", "INFO",), - ("/muteall ERROR critical warning", "CRITICAL",), - ("/muteall WARNING critical INFO", "ERROR",), - ("/muteall ERROR critical info warning", "ERROR WARNING",), - ("/muteall", "INFO CRITICAL WARNING ERROR",) + ("INFO", "INFO",), ("CRITICAL", "WARNING",), + ("error", "CRITICAL",), ("WARNING", "ERROR",), + ("INFO WARNING", "WARNING",), + ("ERROR critical", "INFO",), + ("ERROR critical warning", "CRITICAL",), + ("WARNING critical INFO", "ERROR",), + ("ERROR critical info warning", "ERROR WARNING",), + ("", "INFO CRITICAL WARNING ERROR",) ]) @mock.patch.object(SlackCommandHandlers, "_authorise") @mock.patch.object(Say, '__call__') def test_muteall_callback_mutes_all_chains_correctly_already_muted( - self, inputted_command, first_round_muted_severities, + self, inputted_text, first_round_muted_severities, mock_say, mock_authorise) -> None: # To make sure that there are no persistent keys from other tests. self.test_redis.delete_all_unsafe() mock_say.return_value = None mock_authorise.return_value = True - self.test_command = {'text': inputted_command} - inputted_severities = set(inputted_command.split(' ')[1:]) + self.test_command = {'text': inputted_text} + inputted_severities = set(inputted_text.split(' ')) if not inputted_severities: inputted_severities_upper = {'CRITICAL', 'INFO', 'ERROR', 'WARNING'} else: @@ -1918,20 +1924,19 @@ def test_muteall_callback_mutes_all_chains_correctly_already_muted( self.fail("Expected a muteall key to be set.") @parameterized.expand([ - ("/panicmute BAD_SEVERITY", ["BAD_SEVERITY"],), - ("/panicmute bad_severity INFO CRITICAL", ["bad_severity"],), - ("/panicmute 123 bad_sev", ["123", "bad_sev"],), - ("/panicmute None", ["None"]), - ("/panicmute ", ["", ""]), + ("BAD_SEVERITY", ["BAD_SEVERITY"],), + ("bad_severity INFO CRITICAL", ["bad_severity"],), + ("123 bad_sev", ["123", "bad_sev"],), + ("None", ["None"]), ]) @mock.patch.object(SlackCommandHandlers, "_authorise") @mock.patch.object(Say, '__call__') def test_muteall_callback_sends_correct_replies_if_unrecognized_severities( - self, inputted_command, unrecognised_severities, mock_say, + self, inputted_text, unrecognised_severities, mock_say, mock_authorise) -> None: mock_authorise.return_value = True mock_say.return_value = None - self.test_command = {'text': inputted_command} + self.test_command = {'text': inputted_text} self.test_slack_command_handlers.muteall_callback(self.test_ack, self.test_say, @@ -1980,7 +1985,7 @@ def test_muteall_callback_sends_correct_replies_if_error_when_muting( mock_say.return_value = None mock_authorise.return_value = True mock_exists_unsafe.side_effect = muting_error - self.test_command = {'text': "/muteall INFO"} + self.test_command = {'text': "INFO"} self.test_slack_command_handlers.muteall_callback(self.test_ack, self.test_say, @@ -1991,28 +1996,31 @@ def test_muteall_callback_sends_correct_replies_if_error_when_muting( self.assertEqual(expected_calls, actual_calls) @parameterized.expand([ - ("/muteall INFO", ["INFO"],), ("/muteall CRITICAL", ["CRITICAL"],), - ("/muteall error", ["ERROR"],), ("/muteall WARNING", ["WARNING"],), - ("/muteall INFO WARNING", ["INFO", "WARNING"],), - ("/muteall ERROR critical", ["ERROR", "CRITICAL"],), - ("/muteall ERROR critical INFO", ["ERROR", "CRITICAL", "INFO"],), - ("/muteall WARNING critical INFO", ["WARNING", "CRITICAL", "INFO"],), - ("/muteall ERROR critical info warning", ["ERROR", "CRITICAL", "INFO", - "WARNING"]), - ("/muteall", ["INFO", "WARNING", "CRITICAL", "ERROR"],) + ("INFO", ["INFO"],), ("CRITICAL", ["CRITICAL"],), + ("error", ["ERROR"],), ("WARNING", ["WARNING"],), + ("INFO WARNING", ["INFO", "WARNING"],), + ("ERROR critical", ["ERROR", "CRITICAL"],), + ("ERROR critical INFO", ["ERROR", "CRITICAL", "INFO"],), + ("WARNING critical INFO", ["WARNING", "CRITICAL", "INFO"],), + ("ERROR critical info warning", ["ERROR", "CRITICAL", "INFO", + "WARNING"]), + ("ERROR critical info warning", ["ERROR", "CRITICAL", "INFO", + "WARNING"]), + ("", ["INFO", "WARNING", "CRITICAL", "ERROR"],), + (" ", ["INFO", "WARNING", "CRITICAL", "ERROR"],) ]) @mock.patch.object(RedisApi, "set_unsafe") @mock.patch.object(RedisApi, "exists_unsafe") @mock.patch.object(SlackCommandHandlers, "_authorise") @mock.patch.object(Say, '__call__') def test_muteall_callback_sends_correct_replies_if_mute_successful( - self, input_command, inputted_severities, mock_say, + self, inputted_text, inputted_severities, mock_say, mock_authorise, mock_exists_unsafe, mock_set_unsafe) -> None: mock_say.return_value = None mock_authorise.return_value = True mock_exists_unsafe.return_value = False mock_set_unsafe.return_value = None - self.test_command = {'text': input_command} + self.test_command = {'text': inputted_text} self.test_slack_command_handlers.muteall_callback(self.test_ack, self.test_say, diff --git a/alerter/test/data_store/stores/test_alert_store.py b/alerter/test/data_store/stores/test_alert_store.py index 0abe1d1c2..6a5937e67 100644 --- a/alerter/test/data_store/stores/test_alert_store.py +++ b/alerter/test/data_store/stores/test_alert_store.py @@ -101,6 +101,7 @@ def setUp(self) -> None: self.parent_id = 'test_parent_id' self.parent_id2 = 'test_parent_id2' + self.parent_id3 = 'test_parent_id3' self.alert_id = 'test_alert_id' self.origin_id = 'test_origin_id' self.alert_name = 'test_alert' @@ -128,7 +129,7 @@ def setUp(self) -> None: self.alert_id_4 = 'test_alert_id_4' self.origin_id_4 = 'test_origin_id_4' self.alert_name_4 = 'test_alert_4' - self.metric_4 = 'node_is_down' + self.metric_4 = 'cl_node_is_down' self.severity_4 = 'info' self.message_4 = 'alert message 4' self.value_4 = 'alert_code_4' @@ -136,7 +137,7 @@ def setUp(self) -> None: self.alert_id_5 = 'test_alert_id_5' self.origin_id_5 = 'test_origin_id_5' self.alert_name_5 = 'test_alert_5' - self.metric_5 = 'price_feed_not_observed' + self.metric_5 = 'cl_contract_price_feed_not_observed' self.severity_5 = 'info' self.message_5 = 'alert message 5' self.value_5 = 'alert_code_5' @@ -149,12 +150,14 @@ def setUp(self) -> None: self.message_6 = 'alert message 6' self.value_6 = 'alert_code_6' + self.metric_7 = 'cl_contract_no_synced_data_sources' + self.last_monitored = datetime(2012, 1, 1).timestamp() self.none = None # We do not want to reset `github_release` for Github metrics as we # will lose the pending upgrades - self.github_alert_metrics = ['cannot_access_github'] + self.github_alert_metrics = ['github_cannot_access'] # Normal alerts self.alert_data_1 = { @@ -226,6 +229,11 @@ def setUp(self) -> None: self.alert_data_5_1['parent_id'] = self.parent_id2 self.alert_data_5_1['alert_data']['contract_proxy_address'] = \ '0xA5F7146D3cbB5a50Da36b8AC3857C48Ed3BF3bd9' + self.alert_data_5_2 = copy.deepcopy(self.alert_data_5) + self.alert_data_5_2['parent_id'] = self.parent_id3 + self.alert_data_5_2['origin_id'] = self.parent_id3 + self.alert_data_5_2['metric'] = self.metric_7 + del self.alert_data_5_2['alert_data'] self.alert_data_6 = { 'parent_id': self.parent_id, 'origin_id': self.origin_id_6, @@ -258,7 +266,7 @@ def setUp(self) -> None: self.alert_data_github_1['metric'] = 'github_release' self.alert_data_github_2 = copy.deepcopy(self.alert_data_1) - self.alert_data_github_2['metric'] = 'cannot_access_github' + self.alert_data_github_2['metric'] = 'github_cannot_access' self.alert_data_github_3 = copy.deepcopy(self.alert_data_2) self.alert_data_github_3['metric'] = 'github_release' @@ -327,6 +335,18 @@ def setUp(self) -> None: 'message': self.message_5, 'timestamp': self.last_monitored, } + self.alert_internal_chainlink_contract_3 = { + 'parent_id': self.parent_id3, + 'origin_id': ChainlinkContractAlerter.__name__, + 'alert_code': { + 'name': 'internal_alert_1', + 'code': 'internal_alert_1', + }, + 'severity': self.internal, + 'metric': self.metric_7, + 'message': self.message_5, + 'timestamp': self.last_monitored, + } self.alert_internal_chainlink_contract_all_chains = { 'parent_id': None, 'origin_id': ChainlinkContractAlerter.__name__, @@ -760,14 +780,14 @@ def test_process_redis_store_chainlink_removes_all_chainlink_metrics_for_all_cha self.test_store._process_redis_store(self.alert_data_4) chain_hash_1 = Keys.get_hash_parent(self.alert_data_4['parent_id']) metric_key_1 = eval( - "Keys.get_alert_cl_{}(self.alert_data_4['origin_id'])".format( + "Keys.get_alert_{}(self.alert_data_4['origin_id'])".format( self.alert_data_4['metric'])) self.assertTrue(self.redis.hexists(chain_hash_1, metric_key_1)) self.test_store._process_redis_store(self.alert_data_4_1) chain_hash_2 = Keys.get_hash_parent(self.alert_data_4_1['parent_id']) metric_key_2 = eval( - "Keys.get_alert_cl_{}(self.alert_data_4_1['origin_id'])".format( + "Keys.get_alert_{}(self.alert_data_4_1['origin_id'])".format( self.alert_data_4_1['metric'])) self.assertTrue(self.redis.hexists(chain_hash_2, metric_key_2)) @@ -784,14 +804,14 @@ def test_process_redis_store_chainlink_removes_all_chainlink_metrics_for_one_cha self.test_store._process_redis_store(self.alert_data_4) chain_hash_1 = Keys.get_hash_parent(self.alert_data_4['parent_id']) metric_key_1 = eval( - "Keys.get_alert_cl_{}(self.alert_data_4['origin_id'])".format( + "Keys.get_alert_{}(self.alert_data_4['origin_id'])".format( self.alert_data_4['metric'])) self.assertTrue(self.redis.hexists(chain_hash_1, metric_key_1)) self.test_store._process_redis_store(self.alert_data_4_1) chain_hash_2 = Keys.get_hash_parent(self.alert_data_4_1['parent_id']) metric_key_2 = eval( - "Keys.get_alert_cl_{}(self.alert_data_4_1['origin_id'])".format( + "Keys.get_alert_{}(self.alert_data_4_1['origin_id'])".format( self.alert_data_4_1['metric'])) self.assertTrue(self.redis.hexists(chain_hash_2, metric_key_2)) @@ -808,7 +828,7 @@ def test_process_redis_store_cl_contract_removes_all_cl_contracts_metrics_for_al self.test_store._process_redis_store(self.alert_data_5) chain_hash_1 = Keys.get_hash_parent(self.alert_data_5['parent_id']) metric_key_1 = eval( - "Keys.get_alert_cl_contract_{}(self.alert_data_5['origin_id'], " + "Keys.get_alert_{}(self.alert_data_5['origin_id'], " "self.alert_data_5['alert_data']['contract_proxy_address'])". format(self.alert_data_5['metric'])) self.assertTrue(self.redis.hexists(chain_hash_1, metric_key_1)) @@ -816,16 +836,26 @@ def test_process_redis_store_cl_contract_removes_all_cl_contracts_metrics_for_al self.test_store._process_redis_store(self.alert_data_5_1) chain_hash_2 = Keys.get_hash_parent(self.alert_data_5_1['parent_id']) metric_key_2 = eval( - "Keys.get_alert_cl_contract_{}(self.alert_data_5_1['origin_id'], " + "Keys.get_alert_{}(self.alert_data_5_1['origin_id'], " "self.alert_data_5_1['alert_data']['contract_proxy_address'])". format(self.alert_data_5_1['metric'])) self.assertTrue(self.redis.hexists(chain_hash_2, metric_key_2)) + self.test_store._process_redis_store(self.alert_data_5_2) + chain_hash_3 = Keys.get_hash_parent(self.alert_data_5_2['parent_id']) + metric_key_3 = eval( + "Keys.get_alert_{}()".format( + self.alert_data_5_2['metric'])) + self.assertTrue(self.redis.hexists(chain_hash_3, metric_key_3)) + self.test_store._process_redis_store( self.alert_internal_chainlink_contract_all_chains) + self.test_store._process_redis_store( + self.alert_internal_chainlink_contract_3) self.assertFalse(self.redis.hexists(chain_hash_1, metric_key_1)) self.assertFalse(self.redis.hexists(chain_hash_2, metric_key_2)) + self.assertFalse(self.redis.hexists(chain_hash_3, metric_key_3)) def test_process_redis_store_cl_contract_removes_all_cl_contract_metrics_for_one_chain( self) -> None: @@ -834,7 +864,7 @@ def test_process_redis_store_cl_contract_removes_all_cl_contract_metrics_for_one self.test_store._process_redis_store(self.alert_data_5) chain_hash_1 = Keys.get_hash_parent(self.alert_data_5['parent_id']) metric_key_1 = eval( - "Keys.get_alert_cl_contract_{}(self.alert_data_5['origin_id'], " + "Keys.get_alert_{}(self.alert_data_5['origin_id'], " "self.alert_data_5['alert_data']['contract_proxy_address'])". format(self.alert_data_5['metric'])) self.assertTrue(self.redis.hexists(chain_hash_1, metric_key_1)) @@ -842,16 +872,24 @@ def test_process_redis_store_cl_contract_removes_all_cl_contract_metrics_for_one self.test_store._process_redis_store(self.alert_data_5_1) chain_hash_2 = Keys.get_hash_parent(self.alert_data_5_1['parent_id']) metric_key_2 = eval( - "Keys.get_alert_cl_contract_{}(self.alert_data_5_1['origin_id'], " + "Keys.get_alert_{}(self.alert_data_5_1['origin_id'], " "self.alert_data_5_1['alert_data']['contract_proxy_address'])". format(self.alert_data_5_1['metric'])) self.assertTrue(self.redis.hexists(chain_hash_2, metric_key_2)) + self.test_store._process_redis_store(self.alert_data_5_2) + chain_hash_3 = Keys.get_hash_parent(self.alert_data_5_2['parent_id']) + metric_key_3 = eval( + "Keys.get_alert_{}()".format( + self.alert_data_5_2['metric'])) + self.assertTrue(self.redis.hexists(chain_hash_3, metric_key_3)) + self.test_store._process_redis_store( self.alert_internal_chainlink_contract_1) self.assertFalse(self.redis.hexists(chain_hash_1, metric_key_1)) self.assertTrue(self.redis.hexists(chain_hash_2, metric_key_2)) + self.assertTrue(self.redis.hexists(chain_hash_3, metric_key_3)) def test_process_redis_store_evm_node_removes_all_evm_node_metrics_for_all_chains( self) -> None: @@ -860,14 +898,14 @@ def test_process_redis_store_evm_node_removes_all_evm_node_metrics_for_all_chain self.test_store._process_redis_store(self.alert_data_6) chain_hash_1 = Keys.get_hash_parent(self.alert_data_6['parent_id']) metric_key_1 = eval( - "Keys.get_alert_evm_{}(self.alert_data_6['origin_id'])". + "Keys.get_alert_{}(self.alert_data_6['origin_id'])". format(self.alert_data_6['metric'])) self.assertTrue(self.redis.hexists(chain_hash_1, metric_key_1)) self.test_store._process_redis_store(self.alert_data_6_1) chain_hash_2 = Keys.get_hash_parent(self.alert_data_6_1['parent_id']) metric_key_2 = eval( - "Keys.get_alert_evm_{}(self.alert_data_6_1['origin_id'])". + "Keys.get_alert_{}(self.alert_data_6_1['origin_id'])". format(self.alert_data_6_1['metric'])) self.assertTrue(self.redis.hexists(chain_hash_2, metric_key_2)) @@ -884,14 +922,14 @@ def test_process_redis_store_evm_node_removes_all_evm_node_metrics_for_one_chain self.test_store._process_redis_store(self.alert_data_6) chain_hash_1 = Keys.get_hash_parent(self.alert_data_6['parent_id']) metric_key_1 = eval( - "Keys.get_alert_evm_{}(self.alert_data_6['origin_id'])". + "Keys.get_alert_{}(self.alert_data_6['origin_id'])". format(self.alert_data_6['metric'])) self.assertTrue(self.redis.hexists(chain_hash_1, metric_key_1)) self.test_store._process_redis_store(self.alert_data_6_1) chain_hash_2 = Keys.get_hash_parent(self.alert_data_6_1['parent_id']) metric_key_2 = eval( - "Keys.get_alert_evm_{}(self.alert_data_6_1['origin_id'])". + "Keys.get_alert_{}(self.alert_data_6_1['origin_id'])". format(self.alert_data_6_1['metric'])) self.assertTrue(self.redis.hexists(chain_hash_2, metric_key_2)) diff --git a/alerter/test/data_store/stores/test_config_store.py b/alerter/test/data_store/stores/test_config_store.py index 0ac311614..6eb2ffd7e 100644 --- a/alerter/test/data_store/stores/test_config_store.py +++ b/alerter/test/data_store/stores/test_config_store.py @@ -350,7 +350,7 @@ def setUp(self) -> None: "auth_token": "test_auth_token", "twilio_phone_no": "test_phone_number", "twilio_phone_numbers_to_dial_valid": - "test_phone_numbers_to_dial_valid", + "test_phone_numbers_to_dial_valid", "parent_ids": "chain_name_7f4bc842-21b1-4bcb-8ab9-d86e08149548," "chain_name_94aafe04-8287-463a-8416-0401852b3ca2,GENERAL", diff --git a/alerter/test/monitors/node/test_chainlink.py b/alerter/test/monitors/node/test_chainlink.py index f25ba38ad..d691ac977 100644 --- a/alerter/test/monitors/node/test_chainlink.py +++ b/alerter/test/monitors/node/test_chainlink.py @@ -73,64 +73,76 @@ def setUp(self) -> None: 'head_tracker_heads_received_total': 'strict', 'max_unconfirmed_blocks': 'strict', 'process_start_time_seconds': 'strict', - 'tx_manager_num_gas_bumps_total': 'strict', - 'tx_manager_gas_bump_exceeds_limit_total': 'strict', + 'tx_manager_num_gas_bumps_total': 'optional', + 'tx_manager_gas_bump_exceeds_limit_total': 'optional', 'unconfirmed_transactions': 'strict', 'gas_updater_set_gas_price': 'optional', 'eth_balance': 'strict', 'run_status_update_total': 'optional', } self.retrieved_prometheus_data_example = { - 'eth_balance': {'{"account": "eth_add_1"}': 26.043292035081947}, + 'eth_balance': { + '{"account": "eth_add_1", "evmChainID": "56"}': + 26.043292035081947 + }, 'gas_updater_set_gas_price': { - '{"percentile": "20%"}': 5000000000.0 + '{"percentile": "20%", "evmChainID": "56"}': 5000000000.0 }, - 'head_tracker_current_head': 6924314.0, - 'head_tracker_heads_received_total': 26392.0, - 'max_unconfirmed_blocks': 0.0, + 'head_tracker_current_head': {'{"evmChainID": "56"}': 6924314.0}, + 'head_tracker_heads_received_total': { + '{"evmChainID": "56"}': 26392.0 + }, + 'max_unconfirmed_blocks': {'{"evmChainID": "56"}': 0.0}, 'process_start_time_seconds': 1619431240.24, 'run_status_update_total': { - '{"from_status": "", "job_spec_id": ' + '{"evmChainID": "56", "from_status": "", "job_spec_id": ' '"03ba2f182d5e4245b8492e7f8672482e", ' '"status": "in_progress"}': 129.0, - '{"from_status": "", "job_spec_id": ' + '{"evmChainID": "56", "from_status": "", "job_spec_id": ' '"0b7dd91f5e8a40d8b0493fc0799fe5d3", ' '"status": "in_progress"}': 189.0, - '{"from_status": "in_progress", "job_spec_id": ' - '"03ba2f182d5e4245b8492e7f8672482e", ' + '{"evmChainID": "56", "from_status": "in_progress", ' + '"job_spec_id": "03ba2f182d5e4245b8492e7f8672482e", ' '"status": "completed"}': 389.0, - '{"from_status": "in_progress", "job_spec_id": ' - '"03ba2f182d5e4245b8492e7f8672482e", "status": ' + '{"evmChainID": "56", "from_status": "in_progress", ' + '"job_spec_id": "03ba2f182d5e4245b8492e7f8672482e", "status": ' '"pending_outgoing_confirmations"}': 1898.0, - '{"from_status": "in_progress", "job_spec_id": ' - '"0b7dd91f5e8a40d8b0493fc0799fe5d3", ' + '{"evmChainID": "56", "from_status": "in_progress", ' + '"job_spec_id": "0b7dd91f5e8a40d8b0493fc0799fe5d3", ' '"status": "completed"}': 569.0, - '{"from_status": "in_progress", "job_spec_id": ' - '"0b7dd91f5e8a40d8b0493fc0799fe5d3", ' + '{"evmChainID": "56", "from_status": "in_progress", ' + '"job_spec_id": "0b7dd91f5e8a40d8b0493fc0799fe5d3", ' '"status": "pending_outgoing_confirmations"}': 2780.0, - '{"from_status": "in_progress", "job_spec_id": ' - '"2aacf8ce6827410dae6ff2ce68938edb", "status": "errored"}': 1.0, - '{"from_status": "in_progress", "job_spec_id": ' - '"3cc0a79b77f8404fa193c1e56b3f29bf", ' + '{"evmChainID": "56", "from_status": "in_progress", ' + '"job_spec_id": "2aacf8ce6827410dae6ff2ce68938edb", ' + '"status": "errored"}': 1.0, + '{"evmChainID": "56", "from_status": "in_progress", ' + '"job_spec_id": "3cc0a79b77f8404fa193c1e56b3f29bf", ' '"status": "errored"}': 90.0, - '{"from_status": "in_progress", ' + '{"evmChainID": "56", "from_status": "in_progress", ' '"job_spec_id": "4ae35b033a294c3db78a45db9ada9a57", ' '"status": "errored"}': 1.0, - '{"from_status": "in_progress", "job_spec_id": ' - '"7594586a567d4700b1a794f3363569e1", "status": "errored"}': 1.0, - '{"from_status": "in_progress", "job_spec_id": ' - '"834275814b3b46de83aa7770dbc90912", "status": "errored"}': 4.0, - '{"from_status": "in_progress", "job_spec_id": ' - '"8d2cde397b17415486bbd79de84c901e", ' + '{"evmChainID": "56", "from_status": "in_progress", ' + '"job_spec_id": "7594586a567d4700b1a794f3363569e1", ' + '"status": "errored"}': 1.0, + '{"evmChainID": "56", "from_status": "in_progress", ' + '"job_spec_id": "834275814b3b46de83aa7770dbc90912", ' + '"status": "errored"}': 4.0, + '{"evmChainID": "56", "from_status": "in_progress", ' + '"job_spec_id": "8d2cde397b17415486bbd79de84c901e", ' '"status": "errored"}': 112.0, - '{"from_status": "in_progress", "job_spec_id": ' - '"d0dd062c26794ff1a9b9460cd5d529f6", "status": "errored"}': 2.0, - '{"from_status": "in_progress", "job_spec_id": ' - '"f2e35bcb37b04198a9241121cd936572", "status": "errored"}': 4.0, + '{"evmChainID": "56", "from_status": "in_progress", ' + '"job_spec_id": "d0dd062c26794ff1a9b9460cd5d529f6", ' + '"status": "errored"}': 2.0, + '{"evmChainID": "56", "from_status": "in_progress", ' + '"job_spec_id": "f2e35bcb37b04198a9241121cd936572", ' + '"status": "errored"}': 4.0, }, - 'tx_manager_gas_bump_exceeds_limit_total': 0.0, - 'tx_manager_num_gas_bumps_total': 2031.0, - 'unconfirmed_transactions': 1.0 + 'tx_manager_gas_bump_exceeds_limit_total': { + '{"evmChainID": "56"}': 0.0 + }, + 'tx_manager_num_gas_bumps_total': {'{"evmChainID": "56"}': 2031.0}, + 'unconfirmed_transactions': {'{"evmChainID": "56"}': 1.0} } self.retrieved_prometheus_data_example_optionals_none = copy.deepcopy( self.retrieved_prometheus_data_example) @@ -138,6 +150,10 @@ def setUp(self) -> None: 'gas_updater_set_gas_price'] = None self.retrieved_prometheus_data_example_optionals_none[ 'run_status_update_total'] = None + self.retrieved_prometheus_data_example_optionals_none[ + 'tx_manager_gas_bump_exceeds_limit_total'] = None + self.retrieved_prometheus_data_example_optionals_none[ + 'tx_manager_num_gas_bumps_total'] = None self.processed_prometheus_data_example = { 'head_tracker_current_head': 6924314.0, 'head_tracker_heads_received_total': 26392.0, @@ -162,6 +178,10 @@ def setUp(self) -> None: 'gas_updater_set_gas_price'] = None self.processed_prometheus_data_example_optionals_none[ 'run_status_update_total_errors'] = 0 + self.processed_prometheus_data_example_optionals_none[ + 'tx_manager_gas_bump_exceeds_limit_total'] = None + self.processed_prometheus_data_example_optionals_none[ + 'tx_manager_num_gas_bumps_total'] = None self.test_exception = PANICException('test_exception', 1) self.node_config = ChainlinkNodeConfig( self.node_id, self.parent_id, self.node_name, self.monitor_node, diff --git a/docker-compose-tests.yml b/docker-compose-tests.yml index 5d8f00b38..24b0aef91 100644 --- a/docker-compose-tests.yml +++ b/docker-compose-tests.yml @@ -82,7 +82,7 @@ services: build: context: './' dockerfile: './alerter/Tests_Dockerfile' - image: 'simplyvc/panic_alerter_tests:0.3.1' + image: 'simplyvc/panic_alerter_tests:0.3.2' logging: driver: "json-file" options: @@ -107,4 +107,4 @@ networks: - subnet: 172.19.0.0/24 volumes: - db-data: \ No newline at end of file + db-data: diff --git a/docker-compose.yml b/docker-compose.yml index 133679b4e..6e8ff8d8a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -18,7 +18,7 @@ services: build: context: './' dockerfile: './web-installer/Dockerfile' - image: 'simplyvc/panic_installer:0.3.1' + image: 'simplyvc/panic_installer:0.3.2' logging: driver: "json-file" options: @@ -117,7 +117,7 @@ services: build: context: './' dockerfile: './alerter/Alerter_Dockerfile' - image: 'simplyvc/panic_alerter:0.3.1' + image: 'simplyvc/panic_alerter:0.3.2' logging: driver: "json-file" options: @@ -175,7 +175,7 @@ services: build: context: './' dockerfile: './alerter/Health_Checker_Dockerfile' - image: 'simplyvc/alerter_health_checker:0.3.1' + image: 'simplyvc/alerter_health_checker:0.3.2' logging: driver: "json-file" options: diff --git a/docs/CHANGE_LOG.md b/docs/CHANGE_LOG.md index f03edbd8d..356549e80 100644 --- a/docs/CHANGE_LOG.md +++ b/docs/CHANGE_LOG.md @@ -1,7 +1,14 @@ -Change the contents of this file to this: - # Change Log +## 0.3.2 + +Released on 21st January 2022 + +- Set `tx_manager_num_gas_bumps_total` and `tx_manager_gas_bump_exceeds_limit_total` as optional metrics, depending on whether they are being exposed by the Prometheus endpoint or not. This fixes the issue with `MetricNotFoundError` alerts being raised repetitively. +- Fixed bug in slack commands when muting multiple severities. +- ChainlinkNodeMonitor is now compatible with multi-chain nodes prometheus data. Note: It is still assumed that each chainlink node is associated to one chain for now. +- Refactored Alert Store together with some error codes, and updated data store with missing chainlink contract alert keys. + ## 0.3.1 Released on 6th January 2022 diff --git a/slack_manifest.yaml b/slack_manifest.yaml index 09f1d3239..261ebc420 100644 --- a/slack_manifest.yaml +++ b/slack_manifest.yaml @@ -1,6 +1,3 @@ -_metadata: - major_version: 1 - minor_version: 1 display_information: name: PANIC Notifications features: @@ -12,25 +9,28 @@ features: description: Gives a live status of PANIC's components should_escape: false - command: /unmuteall - description: Unmutes all alert severities on all channels for all chains being - monitored. + description: Unmutes all alert severities on all channels for all chains being monitored. should_escape: false - command: /muteall - description: Mutes List() on all channels for every chain being - monitored. If the list of severities is not given, all alerts for all - chains are muted on all channels. + description: Mutes List() on all channels for every chain being monitored. If the list of severities is not given, all alerts for all chains are muted on all channels. usage_hint: severity1 severity2 should_escape: false - command: /unmute - description: Unmutes all alert severities on all channels for chains Kusama, - binance smart chain. + description: Unmutes all alert severities on all channels for chains linked to this slack channel. should_escape: false - command: /panicmute - description: Mutes List() on all channels for chains Kusama, binance - smart chain. If the list of severities is not given, all alerts for - chains Kusama, binance smart chain are muted on all channels. + description: Mutes List() on all channels for chains linked to this slack channel. If the list of severities is not given, all alerts for chains linked to this slack channel are muted on all channels. usage_hint: severity1 severity2 should_escape: false + - command: /start + description: Welcome message + should_escape: false + - command: /help + description: Available Commands + should_escape: false + - command: /ping + description: Ping the Slack Commands Handler + should_escape: false oauth_config: scopes: bot: diff --git a/web-installer/package-lock.json b/web-installer/package-lock.json index a14f43a31..5dbde16c7 100644 --- a/web-installer/package-lock.json +++ b/web-installer/package-lock.json @@ -1,12 +1,12 @@ { "name": "webinstaller", - "version": "0.3.1", + "version": "0.3.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "webinstaller", - "version": "0.3.1", + "version": "0.3.2", "license": "Apache 2.0", "dependencies": { "@material-ui/core": "^4.11.0", diff --git a/web-installer/package.json b/web-installer/package.json index f3255ef28..24d14a092 100644 --- a/web-installer/package.json +++ b/web-installer/package.json @@ -1,6 +1,6 @@ { "name": "webinstaller", - "version": "0.3.1", + "version": "0.3.2", "private": true, "dependencies": { "@material-ui/core": "^4.11.0", @@ -75,4 +75,4 @@ "eslint-plugin-react": "^7.20.6", "eslint-plugin-react-hooks": "^4.1.0" } -} +} \ No newline at end of file