Skip to content

Commit

Permalink
Multiple fixes (#110)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
PhilippKilian authored May 19, 2023
1 parent b819aa5 commit ff68f20
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 18 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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:
Expand Down
36 changes: 21 additions & 15 deletions b3lb/rest/classes/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -50,6 +50,7 @@
RETURN_STRING_CREATE_LIMIT_REACHED = '<response>\r\n<returncode>FAILED</returncode>\r\n<message>Meeting/Attendee limit reached.</message>\r\n</response>'
RETURN_STRING_CREATE_NO_NODE_AVAILABE = '<response>\r\n<returncode>FAILED</returncode>\r\n<message>No Node available.</message>\r\n</response>'
RETURN_STRING_IS_MEETING_RUNNING_FALSE = '<response>\r\n<returncode>SUCCESS</returncode>\r\n<running>false</running>\r\n</response>'
RETURN_STRING_GET_MEETING_INFO_FALSE = '<response>\r\n<returncode>FAILED</returncode>\r\n<messageKey>notFound</messageKey>\r\n<message>A meeting with that ID does not exist</message>\r\n</response>'
RETURN_STRING_GET_RECORDING_TEXT_TRACKS_NOTHING_FOUND_JSON = '{"response":{"returncode":"FAILED","messageKey":"noRecordings","message":"No recording found"}}'
RETURN_STRING_GET_RECORDING_NO_RECORDINGS = '<response>\r\n<returncode>SUCCESS</returncode>\r\n<recordings></recordings>\r\n<messageKey>noRecordings</messageKey>\r\n<message>There are no recordings for the meeting(s).</message>\r\n</response>'
RETURN_STRING_MISSING_MEETING_ID = '<response>\r\n<returncode>FAILED</returncode>\r\n<messageKey>missingParamMeetingID</messageKey>\r\n<message>You must specify a meeting ID for the meeting.</message>\r\n</response>'
Expand All @@ -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]
Expand All @@ -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)():
Expand All @@ -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)
Expand Down Expand Up @@ -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()

Expand All @@ -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:
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand All @@ -531,15 +537,15 @@ 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:
slug = search.group(1).upper()
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

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion b3lb/rest/classes/checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()}"

Expand Down
4 changes: 2 additions & 2 deletions b3lb/rest/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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()


Expand Down

0 comments on commit ff68f20

Please sign in to comment.