diff --git a/.env b/.env index fba9a1f4389c4a8593b3a8adca627acf438afc29..00c4a532427036fa7956104783e39e6f580a7a6c 100644 --- a/.env +++ b/.env @@ -15,3 +15,10 @@ DEFAULT_DAILY_FEED_TIME=13:00 CERN_OIDC_CLIENT_ID=notifications-dev CERN_OIDC_CLIENT_SECRET=fill-me + +# Auditing +# ETCD_HOST=localhost +# ETCD_PORT=2379 +# AUDITING=true +# ETCD_USER=audituser +# ETCD_PASSWORD=fill-me diff --git a/.isort.cfg b/.isort.cfg index a05ae595fe43b6724964b71320837cb73016a486..3c7785a099cb0fd12dcb388bcc032017d9e02e35 100644 --- a/.isort.cfg +++ b/.isort.cfg @@ -4,4 +4,4 @@ multi_line_output=3 include_trailing_comma=True lines_after_imports=2 not_skip=__init__.py -known_third_party=dateutil,megabus,psycopg2,pytest,requests,sqlalchemy,stomp,yaml +known_third_party=dateutil,etcd3,megabus,psycopg2,pytest,requests,sqlalchemy,stomp,yaml diff --git a/Makefile b/Makefile index adb6692fb7306c2009b54eb33671d83a5ad4afc2..99e756358ae067353f28bab608382a1d6c312001 100644 --- a/Makefile +++ b/Makefile @@ -42,6 +42,7 @@ docker-rebuild-env: .PHONY: docker-build-env docker-build-env-local: + docker-compose -f docker-compose.local.yml build docker-compose -f docker-compose.local.yml up --remove-orphans .PHONY: docker-build-env-local diff --git a/docker-compose.full.yml b/docker-compose.full.yml index e129dc5488483dd058e9e81fa2d2d77cc0edae59..90d68c2dc14db5c0c51220b0a458c95f2e951bcf 100644 --- a/docker-compose.full.yml +++ b/docker-compose.full.yml @@ -56,8 +56,24 @@ services: timeout: 5s retries: 5 + etcd: + image: bitnami/etcd:3.5.1 + volumes: + - etcd-data:/bitnami/etcd/data:rw + entrypoint: /opt/bitnami/etcd/bin/etcd + command: + - '--listen-client-urls=http://0.0.0.0:2379' + - '--advertise-client-urls=http://etcd:2379' + - '--data-dir=/bitnami/etcd/data' + networks: + - default + ports: + - 2379:2379 + - 2380:2380 + networks: default: volumes: pgsql-data: + etcd-data: diff --git a/docker-compose.job.yml b/docker-compose.job.yml index 6dfe1e14a2e24e3e79fc5dfc3536c55497375394..dc5a47d7b1bc13b4a5a7da8db296040832781884 100644 --- a/docker-compose.job.yml +++ b/docker-compose.job.yml @@ -62,8 +62,24 @@ services: timeout: 5s retries: 5 + etcd: + image: bitnami/etcd:3.5.1 + volumes: + - etcd-data:/bitnami/etcd/data:rw + entrypoint: /opt/bitnami/etcd/bin/etcd + command: + - '--listen-client-urls=http://0.0.0.0:2379' + - '--advertise-client-urls=http://etcd:2379' + - '--data-dir=/bitnami/etcd/data' + networks: + - default + ports: + - 2379:2379 + - 2380:2380 + networks: default: volumes: pgsql-data: + etcd-data: diff --git a/docker-compose.local.yml b/docker-compose.local.yml index 53f34b23855d9ea335c399f89de17a11f7f385c0..9e4f5540b24884156089ccec4980b9fd2a5dde15 100644 --- a/docker-compose.local.yml +++ b/docker-compose.local.yml @@ -19,5 +19,6 @@ services: extra_hosts: - "activemq:127.0.0.1" - "pg_db:127.0.0.1" + - "etcd:127.0.0.1" networks: default: diff --git a/docker-compose.test.yml b/docker-compose.test.yml index 7641ceec297998c3c8ee4fa1c7f91f4f103fced9..47cfe0c55ce33636ad4ead51cdf6b9617005652b 100644 --- a/docker-compose.test.yml +++ b/docker-compose.test.yml @@ -55,8 +55,24 @@ services: timeout: 5s retries: 5 + etcd: + image: bitnami/etcd:3.5.1 + volumes: + - etcd-data:/bitnami/etcd/data:rw + entrypoint: /opt/bitnami/etcd/bin/etcd + command: + - '--listen-client-urls=http://0.0.0.0:2379' + - '--advertise-client-urls=http://etcd:2379' + - '--data-dir=/bitnami/etcd/data' + networks: + - default + ports: + - 2379:2379 + - 2380:2380 + networks: default: volumes: pgsql-data: + etcd-data: diff --git a/notifications_routing/auditing.py b/notifications_routing/auditing.py new file mode 100644 index 0000000000000000000000000000000000000000..51eac8f08e19b0bc43156d243d74df69f70fcff2 --- /dev/null +++ b/notifications_routing/auditing.py @@ -0,0 +1,52 @@ +"""Auditing Router definition.""" +import json +import logging +import uuid +from datetime import datetime + +import etcd3 + +from notifications_routing.config import Config + + +client = etcd3.client( + host=Config.ETCD_HOST, port=Config.ETCD_PORT, user=Config.ETCD_USER, password=Config.ETCD_PASSWORD +) + + +def audit_notification(notification_id, value, user_id=None, key=None): + """Put audit notification information into audit DB.""" + if Config.AUDITING is False: + logging.info("Audit disabled") + return + + if not key: + key = uuid.uuid4() + try: + client.put( + ( + f"/notifications/{notification_id}/{Config.AUDIT_ID}" + f"/{'target_users/' + user_id + '/' if user_id else ''}{key}" + ), + json.dumps({"date": datetime.now().strftime("%d/%m/%Y %H:%M:%S"), **value}), + ) + except Exception: + logging.exception("Error auditing to etcd3:") + + +def get_audit_notification(notification_id, key, user_id=None): + """Get audit notification information from audit DB.""" + if Config.AUDITING is False: + logging.info("Audit disabled") + return + + try: + return client.get( + ( + f"/notifications/{notification_id}/{Config.AUDIT_ID}" + f"/{'target_users/' + user_id + '/' if user_id else ''}{key}" + ) + )[0] + except Exception: + logging.exception("Error getting from etcd") + return None diff --git a/notifications_routing/config.py b/notifications_routing/config.py index 0c3ee9d5399525c6a4e44b12ca1b05adc9ec3ae4..5a518846e75530df6d9af81bc003e11a39aab945 100644 --- a/notifications_routing/config.py +++ b/notifications_routing/config.py @@ -61,6 +61,14 @@ class Config: FREQUENCY_TYPE = os.getenv("FREQUENCY_TYPE", "DAILY") FEED_QUEUE = os.getenv("FEED_QUEUE", "email-daily") + # Etcd auditing + ETCD_HOST = os.getenv("ETCD_HOST", "localhost") + ETCD_PORT = os.getenv("ETCD_PORT", 2379) + AUDITING = os.getenv("AUDITING", False) + ETCD_USER = os.getenv("ETCD_USER", None) + ETCD_PASSWORD = os.getenv("ETCD_PASSWORD", None) + AUDIT_ID = os.getenv("AUDIT_ID", "router") + class DevelopmentConfig(Config): """Development configuration overrides.""" diff --git a/notifications_routing/preferences.py b/notifications_routing/preferences.py index 7ce9cf950a20c06f907e45248dcca50d7addf3a0..a8fad14fdafa9efb818c28127c8e30e0eaf740e6 100644 --- a/notifications_routing/preferences.py +++ b/notifications_routing/preferences.py @@ -6,6 +6,7 @@ from typing import Dict, List, Set import megabus from megabus import Publisher +from notifications_routing.auditing import audit_notification from notifications_routing.config import Config from notifications_routing.data_source.data_source import DataSource from notifications_routing.data_source.postgres.postgres_data_source import UserFeedNotification @@ -118,11 +119,27 @@ def apply_user_preferences( create_feed_notification( data_source, message, user, preference.method, preference.scheduledTime, preference.scheduledDay ) + audit_notification( + message[OutputMessageKeys.ID], + {"event": "Preference added to feed", "method": preference.method}, + user_id=user[data_source.EMAIL], + ) continue if preference.method == "LIVE": for device in preference.devices: send_to_device(publisher, message, device) + audit_notification( + message[OutputMessageKeys.ID], + { + "event": "Sent to consumer", + "method": preference.method, + "device": device.type, + "subtype": device.subtype, + "token": device.token, + }, + user_id=user[data_source.EMAIL], + ) continue logging.error("Invalid delivery method: %s", preference.method) @@ -185,7 +202,7 @@ def apply_all( email: str, user_devices: Dict[str, List[str]], ): - """Specific implementation of apply default preferences. + """Specific implementation to send to all devices for Critical notifications. :param publisher: Publisher object used to publish messages :param message: message object @@ -194,7 +211,17 @@ def apply_all( """ logging.debug("Applying to all types/devices") for device in user_devices[DataSource.DEVICES]: - send_to_device(publisher, message, email, device) + send_to_device(publisher, message, device) + audit_notification( + message[OutputMessageKeys.ID], + { + "event": "Critical sent to consumer", + "device": device.type, + "subtype": device.subtype, + "token": device.token, + }, + user_id=email, + ) def apply_default_preferences(publisher: megabus.Publisher, message: Dict, email: str): @@ -207,6 +234,11 @@ def apply_default_preferences(publisher: megabus.Publisher, message: Dict, email """ logging.debug("Applying default preference") send_live_email(publisher, message, email) + audit_notification( + message[OutputMessageKeys.ID], + {"event": "Default sent to consumer", "device": "MAIL", "token": email}, + user_id=email, + ) def send_live_email(publisher: Publisher, message: Dict, email: str): diff --git a/notifications_routing/router.py b/notifications_routing/router.py index d5523d6ceff56c06b4a07de7761a4ff5506b0f48..ff21379f24f84e0b0d2717827286f90c4ca88264 100644 --- a/notifications_routing/router.py +++ b/notifications_routing/router.py @@ -5,6 +5,7 @@ from typing import Dict, List import megabus +from notifications_routing.auditing import audit_notification from notifications_routing.config import Config from notifications_routing.data_source.data_source import DataSource from notifications_routing.exceptions import NotFoundDataSourceError @@ -136,6 +137,7 @@ class Router(megabus.Listener): def process_target_users(self, message): """Process unique users list, if targeted, intersection or standard post.""" if OutputMessageKeys.PRIVATE in message and message[OutputMessageKeys.PRIVATE]: + audit_notification(message[OutputMessageKeys.ID], {"event": "Start processing targeted notification"}) logging.debug("Processing direct notification %s", message[OutputMessageKeys.ID]) target_users = self.get_target_users( message[OutputMessageKeys.CHANNEL_ID], @@ -157,6 +159,7 @@ class Router(megabus.Listener): return target_users else: + audit_notification(message[OutputMessageKeys.ID], {"event": "Start processing"}) logging.debug("Processing general notification %s", message[OutputMessageKeys.ID]) target_users = self.get_channel_users(message[OutputMessageKeys.CHANNEL_ID]) if not target_users: @@ -171,6 +174,10 @@ class Router(megabus.Listener): if not target_users: return + audit_notification( + message[OutputMessageKeys.ID], + {"event": "Expanded recipients", "total": len(target_users), "targets": target_users}, + ) for user in target_users: # Never logged in users, apply default preferences has_logged_in = self.data_source.LAST_LOGIN in user and user.get(self.data_source.LAST_LOGIN) @@ -189,6 +196,11 @@ class Router(megabus.Listener): if self.data_source.is_user_mute_active( user[self.data_source.USER_ID], message[OutputMessageKeys.CHANNEL_ID] ): + audit_notification( + message[OutputMessageKeys.ID], + {"event": "Mute active, skipped user"}, + user_id=user[self.data_source.EMAIL], + ) logging.info( "MUTE enabled for user %s for channel %s, skipping", user[self.data_source.USER_ID], diff --git a/poetry.lock b/poetry.lock index 098237b81b1131b63bd24725cf28786c810a75e9..299ef968fba3f372529f03e85ce39512de4ec9c2 100644 --- a/poetry.lock +++ b/poetry.lock @@ -76,6 +76,20 @@ category = "main" optional = false python-versions = "*" +[[package]] +name = "etcd3" +version = "0.12.0" +description = "Python client for the etcd3 API" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +grpcio = ">=1.27.1" +protobuf = ">=3.6.1" +six = ">=1.12.0" +tenacity = ">=6.1.0" + [[package]] name = "filelock" version = "3.0.12" @@ -129,6 +143,20 @@ python-versions = ">=3.5" [package.dependencies] python-dateutil = ">=2.7" +[[package]] +name = "grpcio" +version = "1.43.0" +description = "HTTP/2-based RPC framework" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +six = ">=1.5.2" + +[package.extras] +protobuf = ["grpcio-tools (>=1.43.0)"] + [[package]] name = "identify" version = "1.5.13" @@ -259,6 +287,14 @@ pyyaml = ">=5.1" toml = "*" virtualenv = ">=20.0.8" +[[package]] +name = "protobuf" +version = "3.19.1" +description = "Protocol Buffers" +category = "main" +optional = false +python-versions = ">=3.5" + [[package]] name = "psycopg2-binary" version = "2.8.6" @@ -444,6 +480,17 @@ python-versions = ">=3.6,<4.0" [package.dependencies] docopt = ">=0.6.2,<0.7.0" +[[package]] +name = "tenacity" +version = "8.0.1" +description = "Retry code until it succeeds" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.extras] +doc = ["reno", "sphinx", "tornado (>=4.5)"] + [[package]] name = "toml" version = "0.10.2" @@ -508,7 +555,7 @@ testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake [metadata] lock-version = "1.1" python-versions = "^3.6.1" -content-hash = "085e85979548b6fe588d4d23b17d33e006cfc68da2e354f5029b1263a8b76681" +content-hash = "933a7b5055a264bb68623147be5d5b07314c1d3b6412b08a13b3410f573d2697" [metadata.files] appdirs = [ @@ -546,6 +593,9 @@ distlib = [ docopt = [ {file = "docopt-0.6.2.tar.gz", hash = "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"}, ] +etcd3 = [ + {file = "etcd3-0.12.0.tar.gz", hash = "sha256:89a704cb389bf0a010a1fa050ce19342d23bf6371ebda1c21cfe8ff3ed488726"}, +] filelock = [ {file = "filelock-3.0.12-py3-none-any.whl", hash = "sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"}, {file = "filelock-3.0.12.tar.gz", hash = "sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59"}, @@ -565,6 +615,52 @@ freezegun = [ {file = "freezegun-1.1.0-py2.py3-none-any.whl", hash = "sha256:2ae695f7eb96c62529f03a038461afe3c692db3465e215355e1bb4b0ab408712"}, {file = "freezegun-1.1.0.tar.gz", hash = "sha256:177f9dd59861d871e27a484c3332f35a6e3f5d14626f2bf91be37891f18927f3"}, ] +grpcio = [ + {file = "grpcio-1.43.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:a4e786a8ee8b30b25d70ee52cda6d1dbba2a8ca2f1208d8e20ed8280774f15c8"}, + {file = "grpcio-1.43.0-cp310-cp310-macosx_10_10_universal2.whl", hash = "sha256:af9c3742f6c13575c0d4147a8454da0ff5308c4d9469462ff18402c6416942fe"}, + {file = "grpcio-1.43.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:fdac966699707b5554b815acc272d81e619dd0999f187cd52a61aef075f870ee"}, + {file = "grpcio-1.43.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e463b4aa0a6b31cf2e57c4abc1a1b53531a18a570baeed39d8d7b65deb16b7e"}, + {file = "grpcio-1.43.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f11d05402e0ac3a284443d8a432d3dfc76a6bd3f7b5858cddd75617af2d7bd9b"}, + {file = "grpcio-1.43.0-cp310-cp310-win32.whl", hash = "sha256:c36f418c925a41fccada8f7ae9a3d3e227bfa837ddbfddd3d8b0ac252d12dda9"}, + {file = "grpcio-1.43.0-cp310-cp310-win_amd64.whl", hash = "sha256:772b943f34374744f70236bbbe0afe413ed80f9ae6303503f85e2b421d4bca92"}, + {file = "grpcio-1.43.0-cp36-cp36m-linux_armv7l.whl", hash = "sha256:cbc9b83211d905859dcf234ad39d7193ff0f05bfc3269c364fb0d114ee71de59"}, + {file = "grpcio-1.43.0-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:fb7229fa2a201a0c377ff3283174ec966da8f9fd7ffcc9a92f162d2e7fc9025b"}, + {file = "grpcio-1.43.0-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:17b75f220ee6923338155b4fcef4c38802b9a57bc57d112c9599a13a03e99f8d"}, + {file = "grpcio-1.43.0-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:6620a5b751b099b3b25553cfc03dfcd873cda06f9bb2ff7e9948ac7090e20f05"}, + {file = "grpcio-1.43.0-cp36-cp36m-manylinux_2_17_aarch64.whl", hash = "sha256:1898f999383baac5fcdbdef8ea5b1ef204f38dc211014eb6977ac6e55944d738"}, + {file = "grpcio-1.43.0-cp36-cp36m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:47b6821238d8978014d23b1132713dac6c2d72cbb561cf257608b1673894f90a"}, + {file = "grpcio-1.43.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80398e9fb598060fa41050d1220f5a2440fe74ff082c36dda41ac3215ebb5ddd"}, + {file = "grpcio-1.43.0-cp36-cp36m-win32.whl", hash = "sha256:0110310eff07bb69782f53b7a947490268c4645de559034c43c0a635612e250f"}, + {file = "grpcio-1.43.0-cp36-cp36m-win_amd64.whl", hash = "sha256:45401d00f2ee46bde75618bf33e9df960daa7980e6e0e7328047191918c98504"}, + {file = "grpcio-1.43.0-cp37-cp37m-linux_armv7l.whl", hash = "sha256:af78ac55933811e6a25141336b1f2d5e0659c2f568d44d20539b273792563ca7"}, + {file = "grpcio-1.43.0-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:8b2b9dc4d7897566723b77422e11c009a0ebd397966b165b21b89a62891a9fdf"}, + {file = "grpcio-1.43.0-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:77ef653f966934b3bfdd00e4f2064b68880eb40cf09b0b99edfa5ee22a44f559"}, + {file = "grpcio-1.43.0-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:e95b5d62ec26d0cd0b90c202d73e7cb927c369c3358e027225239a4e354967dc"}, + {file = "grpcio-1.43.0-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:04239e8f71db832c26bbbedb4537b37550a39d77681d748ab4678e58dd6455d6"}, + {file = "grpcio-1.43.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b4a7152187a49767a47d1413edde2304c96f41f7bc92cc512e230dfd0fba095"}, + {file = "grpcio-1.43.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8cc936a29c65ab39714e1ba67a694c41218f98b6e2a64efb83f04d9abc4386b"}, + {file = "grpcio-1.43.0-cp37-cp37m-win32.whl", hash = "sha256:577e024c8dd5f27cd98ba850bc4e890f07d4b5942e5bc059a3d88843a2f48f66"}, + {file = "grpcio-1.43.0-cp37-cp37m-win_amd64.whl", hash = "sha256:138f57e3445d4a48d9a8a5af1538fdaafaa50a0a3c243f281d8df0edf221dc02"}, + {file = "grpcio-1.43.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:08cf25f2936629db062aeddbb594bd76b3383ab0ede75ef0461a3b0bc3a2c150"}, + {file = "grpcio-1.43.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:01f4b887ed703fe82ebe613e1d2dadea517891725e17e7a6134dcd00352bd28c"}, + {file = "grpcio-1.43.0-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:0aa8285f284338eb68962fe1a830291db06f366ea12f213399b520c062b01f65"}, + {file = "grpcio-1.43.0-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:0edbfeb6729aa9da33ce7e28fb7703b3754934115454ae45e8cc1db601756fd3"}, + {file = "grpcio-1.43.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:c354017819201053d65212befd1dcb65c2d91b704d8977e696bae79c47cd2f82"}, + {file = "grpcio-1.43.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50cfb7e1067ee5e00b8ab100a6b7ea322d37ec6672c0455106520b5891c4b5f5"}, + {file = "grpcio-1.43.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:57f1aeb65ed17dfb2f6cd717cc109910fe395133af7257a9c729c0b9604eac10"}, + {file = "grpcio-1.43.0-cp38-cp38-win32.whl", hash = "sha256:fa26a8bbb3fe57845acb1329ff700d5c7eaf06414c3e15f4cb8923f3a466ef64"}, + {file = "grpcio-1.43.0-cp38-cp38-win_amd64.whl", hash = "sha256:ade8b79a6b6aea68adb9d4bfeba5d647667d842202c5d8f3ba37ac1dc8e5c09c"}, + {file = "grpcio-1.43.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:124e718faf96fe44c98b05f3f475076be8b5198bb4c52a13208acf88a8548ba9"}, + {file = "grpcio-1.43.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:2f96142d0abc91290a63ba203f01649e498302b1b6007c67bad17f823ecde0cf"}, + {file = "grpcio-1.43.0-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:31e6e489ccd8f08884b9349a39610982df48535881ec34f05a11c6e6b6ebf9d0"}, + {file = "grpcio-1.43.0-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:0e731f660e1e68238f56f4ce11156f02fd06dc58bc7834778d42c0081d4ef5ad"}, + {file = "grpcio-1.43.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:1f16725a320460435a8a5339d8b06c4e00d307ab5ad56746af2e22b5f9c50932"}, + {file = "grpcio-1.43.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a4b4543e13acb4806917d883d0f70f21ba93b29672ea81f4aaba14821aaf9bb0"}, + {file = "grpcio-1.43.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:594aaa0469f4fca7773e80d8c27bf1298e7bbce5f6da0f084b07489a708f16ab"}, + {file = "grpcio-1.43.0-cp39-cp39-win32.whl", hash = "sha256:5449ae564349e7a738b8c38583c0aad954b0d5d1dd3cea68953bfc32eaee11e3"}, + {file = "grpcio-1.43.0-cp39-cp39-win_amd64.whl", hash = "sha256:bdf41550815a831384d21a498b20597417fd31bd084deb17d31ceb39ad9acc79"}, + {file = "grpcio-1.43.0.tar.gz", hash = "sha256:735d9a437c262ab039d02defddcb9f8f545d7009ae61c0114e19dda3843febe5"}, +] identify = [ {file = "identify-1.5.13-py2.py3-none-any.whl", hash = "sha256:9dfb63a2e871b807e3ba62f029813552a24b5289504f5b071dea9b041aee9fe4"}, {file = "identify-1.5.13.tar.gz", hash = "sha256:70b638cf4743f33042bebb3b51e25261a0a10e80f978739f17e7fd4837664a66"}, @@ -609,6 +705,32 @@ pre-commit = [ {file = "pre_commit-2.9.3-py2.py3-none-any.whl", hash = "sha256:6c86d977d00ddc8a60d68eec19f51ef212d9462937acf3ea37c7adec32284ac0"}, {file = "pre_commit-2.9.3.tar.gz", hash = "sha256:ee784c11953e6d8badb97d19bc46b997a3a9eded849881ec587accd8608d74a4"}, ] +protobuf = [ + {file = "protobuf-3.19.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d80f80eb175bf5f1169139c2e0c5ada98b1c098e2b3c3736667f28cbbea39fc8"}, + {file = "protobuf-3.19.1-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:a529e7df52204565bcd33738a7a5f288f3d2d37d86caa5d78c458fa5fabbd54d"}, + {file = "protobuf-3.19.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28ccea56d4dc38d35cd70c43c2da2f40ac0be0a355ef882242e8586c6d66666f"}, + {file = "protobuf-3.19.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:8b30a7de128c46b5ecb343917d9fa737612a6e8280f440874e5cc2ba0d79b8f6"}, + {file = "protobuf-3.19.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5935c8ce02e3d89c7900140a8a42b35bc037ec07a6aeb61cc108be8d3c9438a6"}, + {file = "protobuf-3.19.1-cp36-cp36m-win32.whl", hash = "sha256:74f33edeb4f3b7ed13d567881da8e5a92a72b36495d57d696c2ea1ae0cfee80c"}, + {file = "protobuf-3.19.1-cp36-cp36m-win_amd64.whl", hash = "sha256:038daf4fa38a7e818dd61f51f22588d61755160a98db087a046f80d66b855942"}, + {file = "protobuf-3.19.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e51561d72efd5bd5c91490af1f13e32bcba8dab4643761eb7de3ce18e64a853"}, + {file = "protobuf-3.19.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:6e8ea9173403219239cdfd8d946ed101f2ab6ecc025b0fda0c6c713c35c9981d"}, + {file = "protobuf-3.19.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db3532d9f7a6ebbe2392041350437953b6d7a792de10e629c1e4f5a6b1fe1ac6"}, + {file = "protobuf-3.19.1-cp37-cp37m-win32.whl", hash = "sha256:615b426a177780ce381ecd212edc1e0f70db8557ed72560b82096bd36b01bc04"}, + {file = "protobuf-3.19.1-cp37-cp37m-win_amd64.whl", hash = "sha256:d8919368410110633717c406ab5c97e8df5ce93020cfcf3012834f28b1fab1ea"}, + {file = "protobuf-3.19.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:71b0250b0cfb738442d60cab68abc166de43411f2a4f791d31378590bfb71bd7"}, + {file = "protobuf-3.19.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:3cd0458870ea7d1c58e948ac8078f6ba8a7ecc44a57e03032ed066c5bb318089"}, + {file = "protobuf-3.19.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:655264ed0d0efe47a523e2255fc1106a22f6faab7cc46cfe99b5bae085c2a13e"}, + {file = "protobuf-3.19.1-cp38-cp38-win32.whl", hash = "sha256:b691d996c6d0984947c4cf8b7ae2fe372d99b32821d0584f0b90277aa36982d3"}, + {file = "protobuf-3.19.1-cp38-cp38-win_amd64.whl", hash = "sha256:e7e8d2c20921f8da0dea277dfefc6abac05903ceac8e72839b2da519db69206b"}, + {file = "protobuf-3.19.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fd390367fc211cc0ffcf3a9e149dfeca78fecc62adb911371db0cec5c8b7472d"}, + {file = "protobuf-3.19.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:d83e1ef8cb74009bebee3e61cc84b1c9cd04935b72bca0cbc83217d140424995"}, + {file = "protobuf-3.19.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36d90676d6f426718463fe382ec6274909337ca6319d375eebd2044e6c6ac560"}, + {file = "protobuf-3.19.1-cp39-cp39-win32.whl", hash = "sha256:e7b24c11df36ee8e0c085e5b0dc560289e4b58804746fb487287dda51410f1e2"}, + {file = "protobuf-3.19.1-cp39-cp39-win_amd64.whl", hash = "sha256:77d2fadcf369b3f22859ab25bd12bb8e98fb11e05d9ff9b7cd45b711c719c002"}, + {file = "protobuf-3.19.1-py2.py3-none-any.whl", hash = "sha256:e813b1c9006b6399308e917ac5d298f345d95bb31f46f02b60cd92970a9afa17"}, + {file = "protobuf-3.19.1.tar.gz", hash = "sha256:62a8e4baa9cb9e064eb62d1002eca820857ab2138440cb4b3ea4243830f94ca7"}, +] psycopg2-binary = [ {file = "psycopg2-binary-2.8.6.tar.gz", hash = "sha256:11b9c0ebce097180129e422379b824ae21c8f2a6596b159c7659e2e5a00e1aa0"}, {file = "psycopg2_binary-2.8.6-cp27-cp27m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:d14b140a4439d816e3b1229a4a525df917d6ea22a0771a2a78332273fd9528a4"}, @@ -765,6 +887,10 @@ sqlalchemy = [ {file = "stomp.py-6.1.0-py3-none-any.whl", hash = "sha256:8a1ed68cd8b12f41ba56a8dfeff995e7866d1d47ed7f53aaa78da3bea44696b8"}, {file = "stomp.py-6.1.0.tar.gz", hash = "sha256:1f6c7e1e5089b1d8a75161e66533cabb9895de5121cc3900cb7e12c41c1bda18"}, ] +tenacity = [ + {file = "tenacity-8.0.1-py3-none-any.whl", hash = "sha256:f78f4ea81b0fabc06728c11dc2a8c01277bfc5181b321a4770471902e3eb844a"}, + {file = "tenacity-8.0.1.tar.gz", hash = "sha256:43242a20e3e73291a28bcbcacfd6e000b02d3857a9a9fff56b297a27afdc932f"}, +] toml = [ {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, diff --git a/pyproject.toml b/pyproject.toml index 7bd870453a5bdecb35d10304a2840a4dd6a6e6ee..861134262090ca6aec8a6816f5d71e104789fa90 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,6 +32,7 @@ pyyaml = "^5.3.1" sentry-sdk = "^0.19.2" SQLAlchemy = "1.3.20" python-dateutil = "^2.8.1" +etcd3 = "^0.12.0" [tool.poetry.dev-dependencies] pre-commit = "~2.9.2" diff --git a/scripts/send.py b/scripts/send.py index c27e23983abcf405ef52dd312e115d5dc9272766..71ca0863c7b1ecd67156e37a7c1a40837e36e87c 100644 --- a/scripts/send.py +++ b/scripts/send.py @@ -17,6 +17,7 @@ message_body = r"""{"id":1,"target":{"primaryKey":1,"id":"The Best Notifications "users":[],"summary":"sub test EO","tags":null, "link":"http://cds.cern.ch/record/2687667", "contentType":null, +"private":false, "imgUrl":"http://cds.cern.ch/record/2687667/files/CLICtd.png?subformat=icon-640", "priority":"NORMAL"} """ conn.send(body=message_body, destination="/queue/np.routing", headers={"persistent": "true"})