|
| 1 | +import subprocess |
1 | 2 | from datetime import timedelta |
| 3 | +from urllib.parse import urlparse, urlunparse |
2 | 4 |
|
| 5 | +from django.conf import settings |
3 | 6 | from objectstore_client import Client, MetricsBackend, Session, TimeToLive, Usecase |
4 | 7 | from objectstore_client.metrics import Tags |
5 | 8 |
|
6 | 9 | from sentry.utils import metrics as sentry_metrics |
| 10 | +from sentry.utils.env import in_test_environment |
7 | 11 |
|
8 | 12 | __all__ = ["get_attachments_session"] |
9 | 13 |
|
@@ -49,3 +53,49 @@ def get_attachments_session(org: int, project: int) -> Session: |
49 | 53 | ) |
50 | 54 |
|
51 | 55 | return _ATTACHMENTS_CLIENT.session(_ATTACHMENTS_USECASE, org=org, project=project) |
| 56 | + |
| 57 | + |
| 58 | +_IS_SYMBOLICATOR_CONTAINER: bool | None = None |
| 59 | + |
| 60 | + |
| 61 | +def get_symbolicator_url(session: Session, key: str) -> str: |
| 62 | + """ |
| 63 | + Gets the URL that Symbolicator shall use to access the object at the given key in Objectstore. |
| 64 | +
|
| 65 | + In prod, this is simply the `object_url` returned by `objectstore_client`, as both Sentry and Symbolicator |
| 66 | + will talk to Objectstore using the same hostname. |
| 67 | +
|
| 68 | + While in development or testing, we might need to replace the hostname, depending on how Symbolicator is running. |
| 69 | + This function runs a `docker ps` to automatically return the correct URL in the following 2 cases: |
| 70 | + - Symbolicator running in Docker (possibly via `devservices`) -- this mirrors `sentry`'s CI. |
| 71 | + If this is detected, we replace Objectstore's hostname with the one reachable in the Docker network. |
| 72 | +
|
| 73 | + Note that this approach doesn't work if Objectstore is running both locally and in Docker, as we'll always |
| 74 | + rewrite the URL to the Docker one, so Sentry and Symbolicator might attempt to talk to 2 different Objectstores. |
| 75 | + - Symbolicator running locally -- this mirrors `symbolicator`'s CI. |
| 76 | + In this case, we don't need to rewrite the URL. |
| 77 | + """ |
| 78 | + global _IS_SYMBOLICATOR_CONTAINER # Cached to avoid running `docker ps` multiple times |
| 79 | + |
| 80 | + url = session.object_url(key) |
| 81 | + if not (settings.IS_DEV or in_test_environment()): |
| 82 | + return url |
| 83 | + |
| 84 | + if _IS_SYMBOLICATOR_CONTAINER is None: |
| 85 | + try: |
| 86 | + docker_ps = subprocess.run( |
| 87 | + ["docker", "ps", "--format", "{{.Names}}"], capture_output=True, text=True |
| 88 | + ) |
| 89 | + _IS_SYMBOLICATOR_CONTAINER = "symbolicator" in docker_ps.stdout |
| 90 | + except Exception: |
| 91 | + _IS_SYMBOLICATOR_CONTAINER = False |
| 92 | + |
| 93 | + if not _IS_SYMBOLICATOR_CONTAINER: |
| 94 | + return url |
| 95 | + |
| 96 | + replacement = "objectstore" |
| 97 | + parsed = urlparse(url) |
| 98 | + if parsed.port: |
| 99 | + replacement += f":{parsed.port}" |
| 100 | + updated = parsed._replace(netloc=replacement) |
| 101 | + return urlunparse(updated) |
0 commit comments