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()