From ff68f2078ab650557ace65161e6a089c359f31bd Mon Sep 17 00:00:00 2001 From: Philipp Kilian <43444352+PhilippKilian@users.noreply.github.com> Date: Fri, 19 May 2023 09:44:05 +0200 Subject: [PATCH] Multiple fixes (#110) * async: fix async errors * async: fix cluster group filtering check in node status check * pass_through: check is meeting exists, before continuing * constant: fix typo * CHANGELOG.md: update for 3.0.4 fixes --- CHANGELOG.md | 6 ++++++ b3lb/rest/classes/api.py | 36 +++++++++++++++++++++--------------- b3lb/rest/classes/checks.py | 2 +- b3lb/rest/views.py | 4 ++-- 4 files changed, 30 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9292a75..5a52ad3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # ChangeLog +## 3.0.4 - 2023-05-19 + +Fixes: +- fix cluster group filtering check in node status check routine +- add check for meeting existence, before continuing in pass through routine + ## 3.0.3 - 2023-05-18 Fixes: diff --git a/b3lb/rest/classes/api.py b/b3lb/rest/classes/api.py index 1d6a307..2e7dc84 100644 --- a/b3lb/rest/classes/api.py +++ b/b3lb/rest/classes/api.py @@ -33,7 +33,7 @@ from requests import get from rest.b3lb.metrics import incr_metric, update_create_metrics from rest.models import ClusterGroup, ClusterGroupRelation, Meeting, Metric, Node, Parameter, Record, RecordSet, Secret, SecretMeetingList, SecretMetricsList, Stats, RECORD_PROFILE_DESCRIPTION_LENGTH, MEETING_NAME_LENGTH -from typing import Any, Dict, List, Literal +from typing import Any, Dict, List, Literal, Union from urllib.parse import urlencode from xmltodict import parse @@ -50,6 +50,7 @@ RETURN_STRING_CREATE_LIMIT_REACHED = '\r\nFAILED\r\nMeeting/Attendee limit reached.\r\n' RETURN_STRING_CREATE_NO_NODE_AVAILABE = '\r\nFAILED\r\nNo Node available.\r\n' RETURN_STRING_IS_MEETING_RUNNING_FALSE = '\r\nSUCCESS\r\nfalse\r\n' +RETURN_STRING_GET_MEETING_INFO_FALSE = '\r\nFAILED\r\nnotFound\r\nA meeting with that ID does not exist\r\n' RETURN_STRING_GET_RECORDING_TEXT_TRACKS_NOTHING_FOUND_JSON = '{"response":{"returncode":"FAILED","messageKey":"noRecordings","message":"No recording found"}}' RETURN_STRING_GET_RECORDING_NO_RECORDINGS = '\r\nSUCCESS\r\n\r\nnoRecordings\r\nThere are no recordings for the meeting(s).\r\n' RETURN_STRING_MISSING_MEETING_ID = '\r\nFAILED\r\nmissingParamMeetingID\r\nYou must specify a meeting ID for the meeting.\r\n' @@ -71,8 +72,8 @@ class ClientB3lbRequest: endpoint: str checksum: str stats_token: str - node: Node - secret: Secret + node: Union[Node, None] + secret: Union[Secret, None] state: str ENDPOINTS_PASS_THROUGH: List[str] ENDPOINTS: Dict[str, Any] @@ -86,7 +87,7 @@ async def create(self) -> HttpResponse: if not self.meeting_id: return HttpResponse(RETURN_STRING_MISSING_MEETING_ID, content_type=CONTENT_TYPE) - if not await sync_to_async(self.is_meeting)(): + if not await self.is_meeting(): if not await sync_to_async(self.is_node_free)(): return HttpResponse(RETURN_STRING_CREATE_NO_NODE_AVAILABE, content_type=CONTENT_TYPE) elif not await sync_to_async(self.is_in_limit)(): @@ -106,7 +107,7 @@ async def join(self) -> HttpResponse: """ if not self.meeting_id: return HttpResponse(RETURN_STRING_MISSING_MEETING_ID, content_type=CONTENT_TYPE) - if not await sync_to_async(self.is_meeting)(): + if not await self.is_meeting(): return HttpResponseBadRequest() await sync_to_async(self.check_parameters)() await sync_to_async(incr_metric)(Metric.JOINED, self.secret, self.node) @@ -232,7 +233,7 @@ async def is_meeting_running(self) -> HttpResponse: Checks meeting from B3LB database. Send client request to node and return response to client if exists otherwise return hardcoded answer. """ - if not await sync_to_async(self.is_meeting)(): + if not await self.is_meeting(): return HttpResponse(RETURN_STRING_IS_MEETING_RUNNING_FALSE, content_type=CONTENT_TYPE) return await self.pass_through() @@ -241,7 +242,12 @@ async def pass_through(self) -> HttpResponse: Multiple BBB endpoints. Send client request to correct node and return node response to client. """ - self.set_node_by_meeting_id() + if not self.meeting_id: + return HttpResponse(RETURN_STRING_MISSING_MEETING_ID, content_type=CONTENT_TYPE) + if not await self.is_meeting(): + return HttpResponse(RETURN_STRING_GET_MEETING_INFO_FALSE, content_type=CONTENT_TYPE) + if not self.node: + await self.set_node_by_meeting_id() async with ClientSession() as session: if self.request.method == "POST": async with session.post(await sync_to_async(self.get_node_endpoint_url_encoded)(), data=self.body) as res: @@ -420,9 +426,9 @@ def is_in_limit(self) -> bool: return False return True - def is_meeting(self) -> bool: + async def is_meeting(self) -> bool: if self.meeting_id: - self.set_node_by_meeting_id() + await self.set_node_by_meeting_id() if self.node: return True return False @@ -504,11 +510,11 @@ def get_tenant_statistic(self) -> str: return dumps(statistic) ## Setter Routines ## - def set_node_by_meeting_id(self): + async def set_node_by_meeting_id(self): self.node = None if self.meeting_id: try: - meeting = Meeting.objects.get(id=self.meeting_id, secret=self.secret) + meeting = await sync_to_async(Meeting.objects.select_related("node").get)(id=self.meeting_id, secret=self.secret) if not meeting.node.has_errors: self.node = meeting.node except ObjectDoesNotExist: @@ -531,7 +537,7 @@ def set_node_by_lowest_workload(self): if lowest_node_list: self.node = lowest_node_list[randint(0, len(lowest_node_list) - 1)] - def set_secret_by_slug_and_slug_id(self, slug: str, sub_id: int): + async def set_secret_by_slug_and_slug_id(self, slug: str, sub_id: int): if not slug: search = SLUG_REGEX.search(self.get_forwarded_host()) if search: @@ -539,7 +545,7 @@ def set_secret_by_slug_and_slug_id(self, slug: str, sub_id: int): sub_id = int(search.group(3) or 0) if slug: try: - self.secret = Secret.objects.select_related("tenant", "tenant__asset").get(tenant__slug=slug.upper(), sub_id=sub_id) + self.secret = await sync_to_async(Secret.objects.select_related("tenant", "tenant__asset").get)(tenant__slug=slug.upper(), sub_id=sub_id) except ObjectDoesNotExist: pass @@ -582,7 +588,7 @@ class NodeB3lbRequest: """ BACKENDS: Dict[str, Dict[Literal["methods", "function"], Any]] request: HttpRequest - meeting: Meeting + meeting: Union[Meeting, None] backend: str endpoint: str meeting_id: str @@ -633,7 +639,7 @@ async def endpoint_delegation(self) -> HttpResponse: def full_endpoint(self) -> str: return f"{self.backend}/{self.endpoint}" - def get_record_set_by_nonce(self) -> RecordSet: + def get_record_set_by_nonce(self) -> Union[RecordSet, None]: try: record_set = RecordSet.objects.get(nonce=self.nonce) except ObjectDoesNotExist: diff --git a/b3lb/rest/classes/checks.py b/b3lb/rest/classes/checks.py index 56c2504..eb4c923 100644 --- a/b3lb/rest/classes/checks.py +++ b/b3lb/rest/classes/checks.py @@ -21,7 +21,7 @@ def add_meeting_to_stats(self, meeting_id: str): self.meeting_stats[meeting_id][param] = "" def get_meetings_url(self) -> str: - sha = SHA_ALGORITHMS_BY_STRING[ClusterGroupRelation.objects.get(cluster=self.node.cluster).cluster_group.sha_function]() + sha = SHA_ALGORITHMS_BY_STRING[ClusterGroupRelation.objects.filter(cluster=self.node.cluster)[0].cluster_group.sha_function]() sha.update(f"getMeetings{self.node.secret}".encode()) return f"{self.node.api_base_url}getMeetings?checksum={sha.hexdigest()}" diff --git a/b3lb/rest/views.py b/b3lb/rest/views.py index 8a69bf5..a14c07e 100644 --- a/b3lb/rest/views.py +++ b/b3lb/rest/views.py @@ -35,7 +35,7 @@ async def bbb_entrypoint(request: HttpRequest, endpoint: str = "", slug: str = " if not b3lb.is_allowed_method(): return HttpResponseNotAllowed(b3lb.allowed_methods()) - await sync_to_async(b3lb.set_secret_by_slug_and_slug_id)(slug, sub_id) + await b3lb.set_secret_by_slug_and_slug_id(slug, sub_id) if not await sync_to_async(b3lb.is_authorized)(): return HttpResponse("Unauthorized", status=401) return await b3lb.endpoint_delegation() @@ -63,7 +63,7 @@ async def stats(request: HttpRequest, slug: str = "", sub_id: int = 0) -> HttpRe if not b3lb.is_allowed_method(): return HttpResponseNotAllowed(b3lb.allowed_methods()) - b3lb.set_secret_by_slug_and_slug_id(slug, sub_id) + await b3lb.set_secret_by_slug_and_slug_id(slug, sub_id) return await b3lb.endpoint_delegation()