Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 3 additions & 18 deletions src/sentry/lang/native/symbolicator.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,9 @@
from sentry.lang.native.utils import Backoff
from sentry.models.project import Project
from sentry.net.http import Session
from sentry.objectstore import get_attachments_session
from sentry.objectstore import get_attachments_session, get_symbolicator_url
from sentry.options.rollout import in_random_rollout
from sentry.utils import metrics
from sentry.utils.env import in_test_environment

MAX_ATTEMPTS = 3

Expand Down Expand Up @@ -198,8 +197,7 @@ def process_minidump(

if minidump.stored_id:
session = get_attachments_session(self.project.organization_id, self.project.id)
storage_url = session.object_url(minidump.stored_id)
storage_url = maybe_rewrite_objectstore_url(storage_url)
storage_url = get_symbolicator_url(session, minidump.stored_id)
json: dict[str, Any] = {
"platform": platform,
"sources": sources,
Expand Down Expand Up @@ -244,8 +242,7 @@ def process_applecrashreport(self, platform: str, report: CachedAttachment):

if report.stored_id:
session = get_attachments_session(self.project.organization_id, self.project.id)
storage_url = session.object_url(report.stored_id)
storage_url = maybe_rewrite_objectstore_url(storage_url)
storage_url = get_symbolicator_url(session, report.stored_id)
json: dict[str, Any] = {
"platform": platform,
"sources": sources,
Expand Down Expand Up @@ -540,15 +537,3 @@ def query_task(self, task_id):

def reset_worker_id(self):
self.worker_id = uuid.uuid4().hex


def maybe_rewrite_objectstore_url(url: str) -> str:
"""
This is needed during development/testing to make Symbolicator reach Objectstore.
This is because Sentry can reach Objectstore on 127.0.0.1 but Symbolicator cannot, as it's running in its own container.

Note: if you are using a local (not containerized) instance of Symbolicator, you need to disable this logic.
"""
if settings.IS_DEV or in_test_environment():
url = url.replace("127.0.0.1", "objectstore")
return url
50 changes: 50 additions & 0 deletions src/sentry/objectstore/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import subprocess
from datetime import timedelta
from urllib.parse import urlparse, urlunparse

from django.conf import settings
from objectstore_client import Client, MetricsBackend, Session, TimeToLive, Usecase
from objectstore_client.metrics import Tags

from sentry.utils import metrics as sentry_metrics
from sentry.utils.env import in_test_environment

__all__ = ["get_attachments_session"]

Expand Down Expand Up @@ -49,3 +53,49 @@ def get_attachments_session(org: int, project: int) -> Session:
)

return _ATTACHMENTS_CLIENT.session(_ATTACHMENTS_USECASE, org=org, project=project)


_IS_SYMBOLICATOR_CONTAINER: bool | None = None


def get_symbolicator_url(session: Session, key: str) -> str:
"""
Gets the URL that Symbolicator shall use to access the object at the given key in Objectstore.

In prod, this is simply the `object_url` returned by `objectstore_client`, as both Sentry and Symbolicator
will talk to Objectstore using the same hostname.

While in development or testing, we might need to replace the hostname, depending on how Symbolicator is running.
This function runs a `docker ps` to automatically return the correct URL in the following 2 cases:
- Symbolicator running in Docker (possibly via `devservices`) -- this mirrors `sentry`'s CI.
If this is detected, we replace Objectstore's hostname with the one reachable in the Docker network.

Note that this approach doesn't work if Objectstore is running both locally and in Docker, as we'll always
rewrite the URL to the Docker one, so Sentry and Symbolicator might attempt to talk to 2 different Objectstores.
- Symbolicator running locally -- this mirrors `symbolicator`'s CI.
In this case, we don't need to rewrite the URL.
"""
global _IS_SYMBOLICATOR_CONTAINER # Cached to avoid running `docker ps` multiple times

url = session.object_url(key)
if not (settings.IS_DEV or in_test_environment()):
return url

if _IS_SYMBOLICATOR_CONTAINER is None:
try:
docker_ps = subprocess.run(
["docker", "ps", "--format", "{{.Names}}"], capture_output=True, text=True
)
_IS_SYMBOLICATOR_CONTAINER = "symbolicator" in docker_ps.stdout
except Exception:
_IS_SYMBOLICATOR_CONTAINER = False

if not _IS_SYMBOLICATOR_CONTAINER:
return url

replacement = "objectstore"
parsed = urlparse(url)
if parsed.port:
replacement += f":{parsed.port}"
updated = parsed._replace(netloc=replacement)
return urlunparse(updated)
Loading