Skip to content

Commit 7cd3709

Browse files
committed
Configurator: URL-quote vhosts
This raised an error when applying rules the the 'default' vhost, '/',
1 parent 3696615 commit 7cd3709

File tree

1 file changed

+22
-13
lines changed

1 file changed

+22
-13
lines changed

src/zocalo/util/rabbitmq.py

+22-13
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import pathlib
99
import secrets
1010
import urllib
11+
import urllib.parse
1112
import urllib.request
1213
from typing import Any, Dict, List, Optional, Tuple, Union
1314

@@ -20,6 +21,11 @@
2021
logger = logging.getLogger("zocalo.util.rabbitmq")
2122

2223

24+
def _quote(arg: str) -> str:
25+
"""URL-quote a VHost name (which can contain /)"""
26+
return urllib.parse.quote(arg, safe=[])
27+
28+
2329
class MessageStats(BaseModel):
2430
publish: Optional[int] = Field(None, description="Count of messages published.")
2531

@@ -750,7 +756,7 @@ def bindings(
750756
) -> List[BindingInfo]:
751757
endpoint = "bindings"
752758
if vhost is not None:
753-
endpoint = f"{endpoint}/{vhost}"
759+
endpoint = f"{endpoint}/{_quote(vhost)}"
754760
_check = {source, destination, destination_type}
755761
if None in _check and len(_check) > 1:
756762
raise ValueError(
@@ -789,7 +795,9 @@ def bindings_delete(
789795
):
790796
# If properties_key is not specified then all bindings between the specified
791797
# source and destination are deleted
792-
endpoint = f"bindings/{vhost}/e/{source}/{destination_type}/{destination}"
798+
endpoint = (
799+
f"bindings/{_quote(vhost)}/e/{source}/{destination_type}/{destination}"
800+
)
793801
if properties_key is None:
794802
dest_map = {"queue": "q", "exchange": "e"}
795803

@@ -834,11 +842,11 @@ def exchanges(
834842
) -> Union[List[ExchangeInfo], ExchangeInfo]:
835843
endpoint = "exchanges"
836844
if vhost is not None and name is not None:
837-
endpoint = f"{endpoint}/{vhost}/{name}/"
845+
endpoint = f"{endpoint}/{_quote(vhost)}/{name}/"
838846
response = self.get(endpoint)
839847
return ExchangeInfo(**response.json())
840848
elif vhost is not None:
841-
endpoint = f"{endpoint}/{vhost}/"
849+
endpoint = f"{endpoint}/{_quote(vhost)}/"
842850
elif name is not None:
843851
raise ValueError("name can not be set without vhost")
844852
response = self.get(endpoint)
@@ -853,19 +861,19 @@ def exchange_declare(self, exchange: ExchangeSpec):
853861
response.raise_for_status()
854862

855863
def exchange_delete(self, vhost: str, name: str, if_unused: bool = False):
856-
endpoint = f"exchanges/{vhost}/{name}"
864+
endpoint = f"exchanges/{_quote(vhost)}/{name}"
857865
response = self.delete(endpoint, params={"if-unused": if_unused})
858866
response.raise_for_status()
859867

860868
def policies(self, vhost: Optional[str] = None) -> List[PolicySpec]:
861869
endpoint = "policies"
862870
if vhost is not None:
863-
endpoint = f"{endpoint}/{vhost}/"
871+
endpoint = f"{endpoint}/{_quote(vhost)}/"
864872
response = self.get(endpoint)
865873
return [PolicySpec(**p) for p in response.json()]
866874

867875
def policy(self, vhost: str, name: str) -> PolicySpec:
868-
endpoint = f"policies/{vhost}/{name}/"
876+
endpoint = f"policies/{_quote(vhost)}/{name}/"
869877
response = self.get(endpoint)
870878
return PolicySpec(**response.json())
871879

@@ -880,7 +888,7 @@ def set_policy(self, policy: PolicySpec):
880888
response.raise_for_status()
881889

882890
def clear_policy(self, vhost: str, name: str):
883-
endpoint = f"policies/{vhost}/{name}/"
891+
endpoint = f"policies/{_quote(vhost)}/{name}/"
884892
response = self.delete(endpoint)
885893
response.raise_for_status()
886894

@@ -889,11 +897,11 @@ def queues(
889897
) -> Union[List[QueueInfo], QueueInfo]:
890898
endpoint = "queues"
891899
if vhost is not None and name is not None:
892-
endpoint = f"{endpoint}/{vhost}/{name}"
900+
endpoint = f"{endpoint}/{_quote(vhost)}/{name}"
893901
response = self.get(endpoint)
894902
return QueueInfo(**response.json())
895903
elif vhost is not None:
896-
endpoint = f"{endpoint}/{vhost}"
904+
endpoint = f"{endpoint}/{_quote(vhost)}"
897905
elif name is not None:
898906
raise ValueError("name can not be set without vhost")
899907
response = self.get(endpoint)
@@ -910,7 +918,8 @@ def queue_declare(self, queue: QueueSpec):
910918
def queue_delete(
911919
self, vhost: str, name: str, if_unused: bool = False, if_empty: bool = False
912920
):
913-
endpoint = f"queues/{vhost}/{name}"
921+
logger.debug(f"Deleting queue {_quote(vhost)}/{name}")
922+
endpoint = f"queues/{_quote(vhost)}/{name}"
914923
response = self.delete(
915924
endpoint, params={"if-unused": if_unused, "if-empty": if_empty}
916925
)
@@ -931,7 +940,7 @@ def permissions(
931940
) -> List[PermissionSpec] | PermissionSpec:
932941
endpoint = "permissions"
933942
if vhost is not None and user is not None:
934-
endpoint = f"{endpoint}/{vhost}/{user}/"
943+
endpoint = f"{endpoint}/{_quote(vhost)}/{user}/"
935944
response = self.get(endpoint)
936945
return PermissionSpec(**response.json())
937946
elif vhost is not None or user is not None:
@@ -950,7 +959,7 @@ def set_permissions(self, permission: PermissionSpec):
950959
response.raise_for_status()
951960

952961
def clear_permissions(self, vhost: str, user: str):
953-
endpoint = f"permissions/{vhost}/{user}/"
962+
endpoint = f"permissions/{_quote(vhost)}/{user}/"
954963
response = self.delete(endpoint)
955964
response.raise_for_status()
956965

0 commit comments

Comments
 (0)