diff --git a/.envrc b/.envrc
index 9a12b7dfa033e9..74a14fb3a3f6ba 100644
--- a/.envrc
+++ b/.envrc
@@ -122,7 +122,6 @@ else
exec > >(tee "$_SENTRY_LOG_FILE")
exec 2>&1
debug "Development errors will be reported to Sentry.io. If you wish to opt-out, set SENTRY_DEVENV_NO_REPORT as an env variable."
- # This will allow `sentry devservices` errors to be reported
export SENTRY_DEVSERVICES_DSN=https://23670f54c6254bfd9b7de106637808e9@o1.ingest.sentry.io/1492057
fi
diff --git a/Makefile b/Makefile
index 1f9bc9a9902445..a30f06ef07207d 100644
--- a/Makefile
+++ b/Makefile
@@ -173,7 +173,7 @@ test-tools:
@echo ""
# JavaScript relay tests are meant to be run within Symbolicator test suite, as they are parametrized to verify both processing pipelines during migration process.
-# Running Locally: Run `sentry devservices up kafka` before starting these tests
+# Running Locally: Run `devservices up` before starting these tests
test-symbolicator:
@echo "--> Running symbolicator tests"
python3 -b -m pytest tests/symbolicator -vv --cov . --cov-report="xml:.artifacts/symbolicator.coverage.xml" --junit-xml=.artifacts/symbolicator.junit.xml -o junit_suite_name=symbolicator
diff --git a/bin/split-silo-database b/bin/split-silo-database
index 5273084ad34299..49dc924c917aa0 100755
--- a/bin/split-silo-database
+++ b/bin/split-silo-database
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-import os
import click
from django.apps import apps
@@ -32,12 +31,7 @@ def split_database(tables: list[str], source: str, destination: str, reset: bool
command.extend([">", f"/tmp/{destination}-tables.sql"])
with get_docker_client() as client:
- postgres_container = (
- "sentry-postgres-1"
- if os.environ.get("USE_OLD_DEVSERVICES") != "1"
- else "sentry_postgres"
- )
- postgres = client.containers.get(postgres_container)
+ postgres = client.containers.get("sentry-postgres-1")
if verbose:
click.echo(f">> Running {' '.join(command)}")
diff --git a/config/chartcuterie/.gitkeep b/config/chartcuterie/.gitkeep
deleted file mode 100644
index e69de29bb2d1d6..00000000000000
diff --git a/config/clickhouse/dist_config.xml b/config/clickhouse/dist_config.xml
deleted file mode 100644
index a2f21d89412a7f..00000000000000
--- a/config/clickhouse/dist_config.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-
- 0.3
-
-
-
-
-
- localhost
- 9000
-
-
-
-
-
-
- 1
- 1
-
-
-
diff --git a/config/clickhouse/loc_config.xml b/config/clickhouse/loc_config.xml
deleted file mode 100644
index 327d60661b29da..00000000000000
--- a/config/clickhouse/loc_config.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
- 0.3
-
- 1
-
-
diff --git a/config/relay/config.yml b/config/relay/config.yml
deleted file mode 100644
index 6674d442063cf9..00000000000000
--- a/config/relay/config.yml
+++ /dev/null
@@ -1,22 +0,0 @@
----
-relay:
- upstream: 'http://host.docker.internal:8001/'
- host: 0.0.0.0
- port: 7899
-logging:
- level: INFO
- enable_backtraces: false
-limits:
- shutdown_timeout: 0
-processing:
- enabled: true
- kafka_config:
- - {name: 'bootstrap.servers', value: 'sentry_kafka:9093'}
- # The maximum attachment chunk size is 1MB. Together with some meta data,
- # messages will never get larger than 2MB in total.
- - {name: 'message.max.bytes', value: 2097176}
- topics:
- metrics_transactions: ingest-performance-metrics
- metrics_sessions: ingest-metrics
- spans: ingest-spans
- redis: redis://sentry_redis:6379
diff --git a/config/relay/credentials.json b/config/relay/credentials.json
deleted file mode 100644
index 1d37e82fd62789..00000000000000
--- a/config/relay/credentials.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "secret_key": "OxE6Du8quMxWj19f7YDCpIxm6XyU9nWGQJkMWFlkchA",
- "public_key": "SMSesqan65THCV6M4qs4kBzPai60LzuDn-xNsvYpuP8",
- "id": "88888888-4444-4444-8444-cccccccccccc"
-}
diff --git a/config/symbolicator/config.yml b/config/symbolicator/config.yml
deleted file mode 100644
index 290d752a6dd04c..00000000000000
--- a/config/symbolicator/config.yml
+++ /dev/null
@@ -1,11 +0,0 @@
-bind: '0.0.0.0:3021'
-logging:
- level: 'debug'
- format: 'pretty'
- enable_backtraces: true
-
-# explicitly disable caches as it's not something we want in tests. in
-# development it may be less ideal. perhaps we should do the same thing as we
-# do with relay one day (one container per test/session), although that will be
-# slow
-cache_dir: null
diff --git a/devenv/sync.py b/devenv/sync.py
index f6e88f9a30eb41..806dfd4cfeb87c 100644
--- a/devenv/sync.py
+++ b/devenv/sync.py
@@ -143,8 +143,6 @@ def main(context: dict[str, str]) -> int:
FRONTEND_ONLY = os.environ.get("SENTRY_DEVENV_FRONTEND_ONLY") is not None
SKIP_FRONTEND = os.environ.get("SENTRY_DEVENV_SKIP_FRONTEND") is not None
- USE_OLD_DEVSERVICES = os.environ.get("USE_OLD_DEVSERVICES") == "1"
-
if constants.DARWIN and os.path.exists(f"{constants.root}/bin/colima"):
binroot = f"{reporoot}/.devenv/bin"
colima.uninstall(binroot)
@@ -264,41 +262,11 @@ def main(context: dict[str, str]) -> int:
print("Skipping python migrations since SENTRY_DEVENV_FRONTEND_ONLY is set.")
return 0
- if USE_OLD_DEVSERVICES:
- # Ensure new devservices is not being used, otherwise ports will conflict
- proc.run(
- (f"{venv_dir}/bin/devservices", "down"),
- pathprepend=f"{reporoot}/.devenv/bin",
- exit=True,
- )
- # TODO: check healthchecks for redis and postgres to short circuit this
- proc.run(
- (
- f"{venv_dir}/bin/{repo}",
- "devservices",
- "up",
- "redis",
- "postgres",
- ),
- pathprepend=f"{reporoot}/.devenv/bin",
- exit=True,
- )
- else:
- # Ensure old sentry devservices is not being used, otherwise ports will conflict
- proc.run(
- (
- f"{venv_dir}/bin/{repo}",
- "devservices",
- "down",
- ),
- pathprepend=f"{reporoot}/.devenv/bin",
- exit=True,
- )
- proc.run(
- (f"{venv_dir}/bin/devservices", "up", "--mode", "migrations"),
- pathprepend=f"{reporoot}/.devenv/bin",
- exit=True,
- )
+ proc.run(
+ (f"{venv_dir}/bin/devservices", "up", "--mode", "migrations"),
+ pathprepend=f"{reporoot}/.devenv/bin",
+ exit=True,
+ )
if not run_procs(
repo,
@@ -315,16 +283,12 @@ def main(context: dict[str, str]) -> int:
):
return 1
- postgres_container = (
- "sentry_postgres" if os.environ.get("USE_OLD_DEVSERVICES") == "1" else "sentry-postgres-1"
- )
-
# faster prerequisite check than starting up sentry and running createuser idempotently
stdout = proc.run(
(
"docker",
"exec",
- postgres_container,
+ "sentry-postgres-1",
"psql",
"sentry",
"postgres",
diff --git a/scripts/lib.sh b/scripts/lib.sh
index 702b5fae34b6af..cbdbf39844938c 100755
--- a/scripts/lib.sh
+++ b/scripts/lib.sh
@@ -8,10 +8,6 @@
# shellcheck disable=SC2001 # https://github.com/koalaman/shellcheck/wiki/SC2001
POSTGRES_CONTAINER="sentry-postgres-1"
-USE_OLD_DEVSERVICES=${USE_OLD_DEVSERVICES:-"0"}
-if [ "$USE_OLD_DEVSERVICES" == "1" ]; then
- POSTGRES_CONTAINER="sentry_postgres"
-fi
venv_name=".venv"
@@ -44,7 +40,7 @@ init-config() {
}
run-dependent-services() {
- sentry devservices up
+ devservices up
}
create-db() {
diff --git a/scripts/upgrade-postgres.sh b/scripts/upgrade-postgres.sh
index 9f3de7f32a6042..af6695cb2ea9dc 100755
--- a/scripts/upgrade-postgres.sh
+++ b/scripts/upgrade-postgres.sh
@@ -1,10 +1,6 @@
#!/bin/bash
POSTGRES_CONTAINER="sentry-postgres-1"
-USE_OLD_DEVSERVICES=${USE_OLD_DEVSERVICES:-"0"}
-if [ "$USE_OLD_DEVSERVICES" == "1" ]; then
- POSTGRES_CONTAINER="sentry_postgres"
-fi
OLD_VERSION="9.6"
NEW_VERSION="14"
diff --git a/src/sentry/conf/server.py b/src/sentry/conf/server.py
index 4729196954a8c9..01f89e249dc11d 100644
--- a/src/sentry/conf/server.py
+++ b/src/sentry/conf/server.py
@@ -227,20 +227,8 @@ def env(
NODE_MODULES_ROOT = os.path.normpath(NODE_MODULES_ROOT)
-DEVSERVICES_CONFIG_DIR = os.path.normpath(
- os.path.join(PROJECT_ROOT, os.pardir, os.pardir, "config")
-)
-
SENTRY_DISTRIBUTED_CLICKHOUSE_TABLES = False
-RELAY_CONFIG_DIR = os.path.join(DEVSERVICES_CONFIG_DIR, "relay")
-
-SYMBOLICATOR_CONFIG_DIR = os.path.join(DEVSERVICES_CONFIG_DIR, "symbolicator")
-
-# XXX(epurkhiser): The generated chartucterie config.js file will be stored
-# here. This directory may not exist until that file is generated.
-CHARTCUTERIE_CONFIG_DIR = os.path.join(DEVSERVICES_CONFIG_DIR, "chartcuterie")
-
sys.path.insert(0, os.path.normpath(os.path.join(PROJECT_ROOT, os.pardir)))
DATABASES = {
@@ -2092,271 +2080,6 @@ def custom_parameter_sort(parameter: dict) -> tuple[str, int]:
# This flag activates the objectstore in devservices
SENTRY_USE_OBJECTSTORE = False
-# SENTRY_DEVSERVICES = {
-# "service-name": lambda settings, options: (
-# {
-# "image": "image-name:version",
-# # optional ports to expose
-# "ports": {"internal-port/tcp": external-port},
-# # optional command
-# "command": ["exit 1"],
-# optional mapping of volumes
-# "volumes": {"volume-name": {"bind": "/path/in/container"}},
-# # optional statement to test if service should run
-# "only_if": lambda settings, options: True,
-# # optional environment variables
-# "environment": {
-# "ENV_VAR": "1",
-# }
-# }
-# )
-# }
-
-
-SENTRY_DEVSERVICES: dict[str, Callable[[Any, Any], dict[str, Any]]] = {
- "redis": lambda settings, options: (
- {
- "image": "ghcr.io/getsentry/image-mirror-library-redis:5.0-alpine",
- "ports": {"6379/tcp": 6379},
- "command": [
- "redis-server",
- "--appendonly",
- "yes",
- "--save",
- "60",
- "20",
- "--auto-aof-rewrite-percentage",
- "100",
- "--auto-aof-rewrite-min-size",
- "64mb",
- ],
- "volumes": {"redis": {"bind": "/data"}},
- }
- ),
- "redis-cluster": lambda settings, options: (
- {
- "image": "ghcr.io/getsentry/docker-redis-cluster:7.0.10",
- "ports": {f"700{idx}/tcp": f"700{idx}" for idx in range(6)},
- "volumes": {"redis-cluster": {"bind": "/redis-data"}},
- "environment": {"IP": "0.0.0.0"},
- "only_if": settings.SENTRY_DEV_USE_REDIS_CLUSTER,
- }
- ),
- "rabbitmq": lambda settings, options: (
- {
- "image": "ghcr.io/getsentry/image-mirror-library-rabbitmq:3-management",
- "ports": {"5672/tcp": 5672, "15672/tcp": 15672},
- "environment": {"IP": "0.0.0.0"},
- "only_if": settings.SENTRY_DEV_USE_RABBITMQ,
- }
- ),
- "postgres": lambda settings, options: (
- {
- "image": f"ghcr.io/getsentry/image-mirror-library-postgres:{PG_VERSION}-alpine",
- "ports": {"5432/tcp": 5432},
- "environment": {
- "POSTGRES_DB": "sentry",
- "POSTGRES_HOST_AUTH_METHOD": "trust",
- },
- "volumes": {
- "postgres": {"bind": "/var/lib/postgresql/data"},
- "wal2json": {"bind": "/wal2json"},
- },
- "command": [
- "postgres",
- "-c",
- "wal_level=logical",
- "-c",
- "max_replication_slots=1",
- "-c",
- "max_wal_senders=1",
- ],
- }
- ),
- "kafka": lambda settings, options: (
- {
- "image": "ghcr.io/getsentry/image-mirror-confluentinc-cp-kafka:7.5.0",
- "ports": {"9092/tcp": 9092},
- # https://docs.confluent.io/platform/current/installation/docker/config-reference.html#cp-kakfa-example
- "environment": {
- "KAFKA_PROCESS_ROLES": "broker,controller",
- "KAFKA_CONTROLLER_QUORUM_VOTERS": "1@127.0.0.1:29093",
- "KAFKA_CONTROLLER_LISTENER_NAMES": "CONTROLLER",
- "KAFKA_NODE_ID": "1",
- "CLUSTER_ID": "MkU3OEVBNTcwNTJENDM2Qk",
- "KAFKA_LISTENERS": "PLAINTEXT://0.0.0.0:29092,INTERNAL://0.0.0.0:9093,EXTERNAL://0.0.0.0:9092,CONTROLLER://0.0.0.0:29093",
- "KAFKA_ADVERTISED_LISTENERS": "PLAINTEXT://127.0.0.1:29092,INTERNAL://sentry_kafka:9093,EXTERNAL://127.0.0.1:9092",
- "KAFKA_LISTENER_SECURITY_PROTOCOL_MAP": "PLAINTEXT:PLAINTEXT,INTERNAL:PLAINTEXT,EXTERNAL:PLAINTEXT,CONTROLLER:PLAINTEXT",
- "KAFKA_INTER_BROKER_LISTENER_NAME": "PLAINTEXT",
- "KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR": "1",
- "KAFKA_OFFSETS_TOPIC_NUM_PARTITIONS": "1",
- "KAFKA_LOG_RETENTION_HOURS": "24",
- "KAFKA_MESSAGE_MAX_BYTES": "50000000",
- "KAFKA_MAX_REQUEST_SIZE": "50000000",
- },
- "volumes": {"kafka": {"bind": "/var/lib/kafka/data"}},
- "only_if": "kafka" in settings.SENTRY_EVENTSTREAM
- or settings.SENTRY_USE_RELAY
- or settings.SENTRY_DEV_PROCESS_SUBSCRIPTIONS
- or settings.SENTRY_USE_PROFILING,
- }
- ),
- "clickhouse": lambda settings, options: (
- {
- "image": (
- "ghcr.io/getsentry/image-mirror-altinity-clickhouse-server:23.8.11.29.altinitystable"
- ),
- "ports": {"9000/tcp": 9000, "9009/tcp": 9009, "8123/tcp": 8123},
- "ulimits": [{"name": "nofile", "soft": 262144, "hard": 262144}],
- # The arm image does not properly load the MAX_MEMORY_USAGE_RATIO
- # from the environment in loc_config.xml, thus, hard-coding it there
- "volumes": {
- (
- "clickhouse_dist"
- if settings.SENTRY_DISTRIBUTED_CLICKHOUSE_TABLES
- else "clickhouse"
- ): {"bind": "/var/lib/clickhouse"},
- os.path.join(
- settings.DEVSERVICES_CONFIG_DIR,
- "clickhouse",
- (
- "dist_config.xml"
- if settings.SENTRY_DISTRIBUTED_CLICKHOUSE_TABLES
- else "loc_config.xml"
- ),
- ): {"bind": "/etc/clickhouse-server/config.d/sentry.xml"},
- },
- }
- ),
- "snuba": lambda settings, options: (
- {
- "image": "ghcr.io/getsentry/snuba:latest",
- "ports": {"1218/tcp": 1218, "1219/tcp": 1219},
- "command": ["devserver"]
- + (["--no-workers"] if "snuba" in settings.SENTRY_EVENTSTREAM else []),
- "environment": {
- "PYTHONUNBUFFERED": "1",
- "SNUBA_SETTINGS": "docker",
- "DEBUG": "1",
- "CLICKHOUSE_HOST": "{containers[clickhouse][name]}",
- "CLICKHOUSE_PORT": "9000",
- "CLICKHOUSE_HTTP_PORT": "8123",
- "DEFAULT_BROKERS": (
- ""
- if "snuba" in settings.SENTRY_EVENTSTREAM
- else "{containers[kafka][name]}:9093"
- ),
- "REDIS_HOST": "{containers[redis][name]}",
- "REDIS_PORT": "6379",
- "REDIS_DB": "1",
- "ENABLE_SENTRY_METRICS_DEV": "1" if settings.SENTRY_USE_METRICS_DEV else "",
- "ENABLE_PROFILES_CONSUMER": "1" if settings.SENTRY_USE_PROFILING else "",
- "ENABLE_SPANS_CONSUMER": "1" if settings.SENTRY_USE_SPANS else "",
- "ENABLE_ISSUE_OCCURRENCE_CONSUMER": (
- "1" if settings.SENTRY_USE_ISSUE_OCCURRENCE else ""
- ),
- "ENABLE_AUTORUN_MIGRATION_SEARCH_ISSUES": "1",
- # TODO: remove setting
- "ENABLE_GROUP_ATTRIBUTES_CONSUMER": (
- "1" if settings.SENTRY_USE_GROUP_ATTRIBUTES else ""
- ),
- },
- "only_if": "snuba" in settings.SENTRY_EVENTSTREAM
- or "kafka" in settings.SENTRY_EVENTSTREAM,
- # we don't build linux/arm64 snuba images anymore
- # apple silicon users should have working emulation under colima 0.6.2
- # or docker desktop
- "platform": "linux/amd64",
- }
- ),
- "taskbroker": lambda settings, options: (
- {
- "image": "ghcr.io/getsentry/taskbroker:latest",
- "ports": {"50051/tcp": 50051},
- "environment": {
- "TASKBROKER_KAFKA_CLUSTER": (
- "sentry_kafka"
- if os.environ.get("USE_OLD_DEVSERVICES") == "1"
- else "kafka-kafka-1"
- ),
- },
- "only_if": settings.SENTRY_USE_TASKBROKER,
- "platform": "linux/amd64",
- }
- ),
- "bigtable": lambda settings, options: (
- {
- "image": "ghcr.io/getsentry/cbtemulator:d28ad6b63e461e8c05084b8c83f1c06627068c04",
- "ports": {"8086/tcp": 8086},
- # NEED_BIGTABLE is set by CI so we don't have to pass
- # --skip-only-if when compiling which services to run.
- "only_if": os.environ.get("NEED_BIGTABLE", False)
- or "bigtable" in settings.SENTRY_NODESTORE,
- }
- ),
- "memcached": lambda settings, options: (
- {
- "image": "ghcr.io/getsentry/image-mirror-library-memcached:1.5-alpine",
- "ports": {"11211/tcp": 11211},
- "only_if": "memcached" in settings.CACHES.get("default", {}).get("BACKEND"),
- }
- ),
- "symbolicator": lambda settings, options: (
- {
- "image": "us-central1-docker.pkg.dev/sentryio/symbolicator/image:nightly",
- "ports": {"3021/tcp": 3021},
- "volumes": {settings.SYMBOLICATOR_CONFIG_DIR: {"bind": "/etc/symbolicator"}},
- "command": ["run", "--config", "/etc/symbolicator/config.yml"],
- "only_if": options.get("symbolicator.enabled"),
- }
- ),
- "relay": lambda settings, options: (
- {
- "image": "us-central1-docker.pkg.dev/sentryio/relay/relay:nightly",
- "ports": {"7899/tcp": settings.SENTRY_RELAY_PORT},
- "volumes": {settings.RELAY_CONFIG_DIR: {"bind": "/etc/relay"}},
- "command": ["run", "--config", "/etc/relay"],
- "only_if": bool(os.environ.get("SENTRY_USE_RELAY", settings.SENTRY_USE_RELAY)),
- "with_devserver": True,
- }
- ),
- "chartcuterie": lambda settings, options: (
- {
- "image": "us-central1-docker.pkg.dev/sentryio/chartcuterie/image:latest",
- "volumes": {settings.CHARTCUTERIE_CONFIG_DIR: {"bind": "/etc/chartcuterie"}},
- "environment": {
- "CHARTCUTERIE_CONFIG": "/etc/chartcuterie/config.js",
- "CHARTCUTERIE_CONFIG_POLLING": "true",
- },
- "ports": {"9090/tcp": 7901},
- # NEED_CHARTCUTERIE is set by CI so we don't have to pass --skip-only-if when compiling which services to run.
- "only_if": os.environ.get("NEED_CHARTCUTERIE", False)
- or options.get("chart-rendering.enabled"),
- }
- ),
- "vroom": lambda settings, options: (
- {
- "image": "us-central1-docker.pkg.dev/sentryio/vroom/vroom:latest",
- "volumes": {"profiles": {"bind": "/var/lib/sentry-profiles"}},
- "environment": {
- "SENTRY_KAFKA_BROKERS_PROFILING": "{containers[kafka][name]}:9093",
- "SENTRY_KAFKA_BROKERS_OCCURRENCES": "{containers[kafka][name]}:9093",
- "SENTRY_SNUBA_HOST": "http://{containers[snuba][name]}:1218",
- },
- "ports": {"8085/tcp": 8085},
- "only_if": settings.SENTRY_USE_PROFILING,
- }
- ),
- "objectstore": lambda settings, options: (
- {
- "image": "ghcr.io/getsentry/objectstore:latest",
- "ports": {"8888/tcp": 8888},
- "environment": {},
- "only_if": settings.SENTRY_USE_OBJECTSTORE,
- }
- ),
-}
-
# Max file size for serialized file uploads in API
SENTRY_MAX_SERIALIZED_FILE_SIZE = 5000000
diff --git a/src/sentry/runner/commands/devserver.py b/src/sentry/runner/commands/devserver.py
index 338bee6ffee0bd..180ee9f7e320a6 100644
--- a/src/sentry/runner/commands/devserver.py
+++ b/src/sentry/runner/commands/devserver.py
@@ -349,10 +349,8 @@ def devserver(
kafka_consumers.add("ingest-occurrences")
# Check if Kafka is available and create all topics if it is running
- use_old_devservices = os.environ.get("USE_OLD_DEVSERVICES") == "1"
- valid_kafka_container_names = ["kafka-kafka-1", "sentry_kafka"]
- kafka_container_name = "sentry_kafka" if use_old_devservices else "kafka-kafka-1"
- kafka_is_running = any(name in containers for name in valid_kafka_container_names)
+ kafka_container_name = "kafka-kafka-1"
+ kafka_is_running = kafka_container_name in containers
if kafka_is_running:
from sentry_kafka_schemas import list_topics
@@ -366,15 +364,9 @@ def devserver(
# Set up Kafka consumers if they are configured
if kafka_consumers:
- kafka_container_warning_message = (
- f"""
- Devserver is configured to work with `sentry devservices`. Looks like the `{kafka_container_name}` container is not running.
- Please run `sentry devservices up kafka` to start it."""
- if use_old_devservices
- else f"""
- Devserver is configured to work with the revamped devservices. Looks like the `{kafka_container_name}` container is not running.
+ kafka_container_warning_message = f"""
+ Devserver is configured to work with devservices. Looks like the `{kafka_container_name}` container is not running.
Please run `devservices up` to start it."""
- )
if not kafka_is_running:
raise click.ClickException(
f"""
diff --git a/src/sentry/runner/commands/devservices.py b/src/sentry/runner/commands/devservices.py
index 92aa9ed4b09597..58b21d638556fe 100644
--- a/src/sentry/runner/commands/devservices.py
+++ b/src/sentry/runner/commands/devservices.py
@@ -1,20 +1,11 @@
from __future__ import annotations
import contextlib
-import functools
-import http
import json # noqa
import os
-import shutil
-import signal
-import subprocess
import sys
-import time
-import urllib.error
-import urllib.request
-from collections.abc import Callable, Generator
-from concurrent.futures import ThreadPoolExecutor, as_completed
-from typing import TYPE_CHECKING, Any, ContextManager, Literal, NamedTuple, overload
+from collections.abc import Generator
+from typing import TYPE_CHECKING, ContextManager
import click
@@ -22,53 +13,19 @@
import docker
CI = os.environ.get("CI") is not None
-USE_OLD_DEVSERVICES = os.environ.get("USE_OLD_DEVSERVICES") == "1"
# assigned as a constant so mypy's "unreachable" detection doesn't fail on linux
# https://github.com/python/mypy/issues/12286
DARWIN = sys.platform == "darwin"
-USE_COLIMA = bool(shutil.which("colima")) and os.environ.get("SENTRY_USE_COLIMA") != "0"
-USE_ORBSTACK = (
- os.path.exists("/Applications/OrbStack.app") and os.environ.get("SENTRY_USE_ORBSTACK") != "0"
-)
-
-if USE_ORBSTACK:
- USE_COLIMA = False
-
-if USE_COLIMA:
- USE_ORBSTACK = False
-
-USE_DOCKER_DESKTOP = not USE_COLIMA and not USE_ORBSTACK
-
if DARWIN:
- if USE_COLIMA:
- RAW_SOCKET_PATH = os.path.expanduser("~/.colima/default/docker.sock")
- elif USE_ORBSTACK:
- RAW_SOCKET_PATH = os.path.expanduser("~/.orbstack/run/docker.sock")
- elif USE_DOCKER_DESKTOP:
- # /var/run/docker.sock is now gated behind a docker desktop advanced setting
- RAW_SOCKET_PATH = os.path.expanduser("~/.docker/run/docker.sock")
+ RAW_SOCKET_PATH = os.path.expanduser("~/.colima/default/docker.sock")
else:
RAW_SOCKET_PATH = "/var/run/docker.sock"
-# Simplified from pre-commit @ fb0ccf3546a9cb34ec3692e403270feb6d6033a2
-@functools.cache
-def _gitroot() -> str:
- from os.path import abspath
- from subprocess import CalledProcessError, run
-
- try:
- proc = run(("git", "rev-parse", "--show-cdup"), check=True, capture_output=True)
- root = abspath(proc.stdout.decode().strip())
- except CalledProcessError:
- raise SystemExit(
- "git failed. Is it installed, and are you in a Git repository directory?",
- )
- return root
-
-
+# NOTE: we can delete the docker python client dependency if we port all usage of this
+# to docker cli calls
@contextlib.contextmanager
def get_docker_client() -> Generator[docker.DockerClient]:
import docker
@@ -81,790 +38,17 @@ def _client() -> ContextManager[docker.DockerClient]:
client = ctx.enter_context(_client())
except docker.errors.DockerException:
if DARWIN:
- if USE_COLIMA:
- click.echo("Attempting to start colima...")
- gitroot = _gitroot()
- subprocess.check_call(
- (
- # explicitly use repo-local devenv, not the global one
- f"{gitroot}/.venv/bin/devenv",
- "colima",
- "start",
- )
- )
- elif USE_DOCKER_DESKTOP:
- click.echo("Attempting to start docker...")
- subprocess.check_call(
- ("open", "-a", "/Applications/Docker.app", "--args", "--unattended")
- )
- elif USE_ORBSTACK:
- click.echo("Attempting to start orbstack...")
- subprocess.check_call(
- ("open", "-a", "/Applications/OrbStack.app", "--args", "--unattended")
- )
+ raise click.ClickException(
+ "Make sure colima is running. Run `devenv colima start`."
+ )
else:
raise click.ClickException("Make sure docker is running.")
- max_wait = 90
- timeout = time.monotonic() + max_wait
-
- click.echo(f"Waiting for docker to be ready.... (timeout in {max_wait}s)")
- while time.monotonic() < timeout:
- time.sleep(1)
- try:
- client = ctx.enter_context(_client())
- except docker.errors.DockerException:
- continue
- else:
- break
- else:
- raise click.ClickException("Failed to start docker.")
-
yield client
-@overload
-def get_or_create(
- client: docker.DockerClient, thing: Literal["network"], name: str
-) -> docker.models.networks.Network: ...
-
-
-@overload
-def get_or_create(
- client: docker.DockerClient, thing: Literal["volume"], name: str
-) -> docker.models.volumes.Volume: ...
-
-
-def get_or_create(
- client: docker.DockerClient, thing: Literal["network", "volume"], name: str
-) -> docker.models.networks.Network | docker.models.volumes.Volume:
- from docker.errors import NotFound
-
- try:
- return getattr(client, thing + "s").get(name)
- except NotFound:
- click.secho(f"> Creating '{name}' {thing}", err=True, fg="yellow")
- return getattr(client, thing + "s").create(name)
-
-
-def retryable_pull(
- client: docker.DockerClient, image: str, max_attempts: int = 5, platform: str | None = None
-) -> None:
- from docker.errors import APIError
-
- current_attempt = 0
-
- # `client.images.pull` intermittently fails in CI, and the docker API/docker-py does not give us the relevant error message (i.e. it's not the same error as running `docker pull` from shell)
- # As a workaround, let's retry when we hit the ImageNotFound exception.
- #
- # See https://github.com/docker/docker-py/issues/2101 for more information
- while True:
- try:
- if platform:
- client.images.pull(image, platform=platform)
- else:
- client.images.pull(image)
- except APIError:
- if current_attempt + 1 >= max_attempts:
- raise
- current_attempt = current_attempt + 1
- continue
- else:
- break
-
-
-def ensure_interface(ports: dict[str, int | tuple[str, int]]) -> dict[str, tuple[str, int]]:
- # If there is no interface specified, make sure the
- # default interface is 127.0.0.1
- rv = {}
- for k, v in ports.items():
- if not isinstance(v, tuple):
- v = ("127.0.0.1", v)
- rv[k] = v
- return rv
-
-
-def ensure_docker_cli_context(context: str) -> None:
- # this is faster than running docker context use ...
- config_file = os.path.expanduser("~/.docker/config.json")
- config = {}
-
- if os.path.exists(config_file):
- with open(config_file, "rb") as f:
- config = json.loads(f.read())
-
- config["currentContext"] = context
-
- os.makedirs(os.path.dirname(config_file), exist_ok=True)
- with open(config_file, "w") as f:
- f.write(json.dumps(config))
-
-
-@click.group()
-def devservices() -> None:
- """
- Manage dependent development services required for Sentry.
-
- Do not use in production!
- """
- # Disable backend validation so no devservices commands depend on like,
- # redis to be already running.
- os.environ["SENTRY_SKIP_BACKEND_VALIDATION"] = "1"
-
- if CI:
- click.echo("Assuming docker (CI).")
- return
-
- if not USE_OLD_DEVSERVICES:
- return
-
- if DARWIN:
- if USE_DOCKER_DESKTOP:
- click.echo("Using docker desktop.")
- ensure_docker_cli_context("desktop-linux")
- if USE_COLIMA:
- click.echo("Using colima.")
- ensure_docker_cli_context("colima")
- if USE_ORBSTACK:
- click.echo("Using orbstack.")
- ensure_docker_cli_context("orbstack")
-
-
-@devservices.command()
-@click.option("--project", default="sentry")
-@click.argument("service", nargs=1)
-def attach(project: str, service: str) -> None:
- """
- Run a single devservice in the foreground.
-
- Accepts a single argument, the name of the service to spawn. The service
- will run with output printed to your terminal, and the ability to kill it
- with ^C. This is used in devserver.
-
- Note: This does not update images, you will have to use `devservices up`
- for that.
- """
- from sentry.runner import configure
-
- configure()
-
- containers = _prepare_containers(project, silent=True)
- if service not in containers:
- raise click.ClickException(f"Service `{service}` is not known or not enabled.")
-
- with get_docker_client() as docker_client:
- container = _start_service(
- docker_client,
- service,
- containers,
- project,
- always_start=True,
- )
-
- if container is None:
- raise click.ClickException(f"No containers found for service `{service}`.")
-
- def exit_handler(*_: Any) -> None:
- try:
- click.echo(f"Stopping {service}")
- container.stop()
- click.echo(f"Removing {service}")
- container.remove()
- except KeyboardInterrupt:
- pass
-
- signal.signal(signal.SIGINT, exit_handler)
- signal.signal(signal.SIGTERM, exit_handler)
-
- for line in container.logs(stream=True, since=int(time.time() - 20)):
- click.echo(line, nl=False)
-
-
-@devservices.command()
-@click.argument("services", nargs=-1)
-@click.option("--project", default="sentry")
-@click.option("--exclude", multiple=True, help="Service to ignore and not run. Repeatable option.")
-@click.option(
- "--skip-only-if", is_flag=True, default=False, help="Skip 'only_if' checks for services"
-)
-@click.option(
- "--recreate", is_flag=True, default=False, help="Recreate containers that are already running."
-)
-def up(
- services: list[str],
- project: str,
- exclude: list[str],
- skip_only_if: bool,
- recreate: bool,
-) -> None:
- """
- Run/update all devservices in the background.
-
- The default is everything, however you may pass positional arguments to specify
- an explicit list of services to bring up.
-
- You may also exclude services, for example: --exclude redis --exclude postgres.
- """
- from sentry.runner import configure
-
- if not USE_OLD_DEVSERVICES:
- click.secho(
- "WARNING: `sentry devservices up` is deprecated. Please use `devservices up` instead. For more info about the revamped devservices, see https://github.com/getsentry/devservices.",
- fg="yellow",
- )
- return
-
- configure()
-
- containers = _prepare_containers(
- project, skip_only_if=(skip_only_if or len(services) > 0), silent=True
- )
- selected_services = set()
-
- if services:
- for service in services:
- if service not in containers:
- click.secho(
- f"Service `{service}` is not known or not enabled.\n",
- err=True,
- fg="red",
- )
- click.secho(
- "Services that are available:\n" + "\n".join(containers.keys()) + "\n", err=True
- )
- raise click.Abort()
- selected_services.add(service)
- else:
- selected_services = set(containers.keys())
-
- for service in exclude:
- if service not in containers:
- click.secho(f"Service `{service}` is not known or not enabled.\n", err=True, fg="red")
- click.secho(
- "Services that are available:\n" + "\n".join(containers.keys()) + "\n", err=True
- )
- raise click.Abort()
- selected_services.remove(service)
-
- with get_docker_client() as docker_client:
- get_or_create(docker_client, "network", project)
-
- with ThreadPoolExecutor(max_workers=len(selected_services)) as executor:
- futures = []
- for name in selected_services:
- futures.append(
- executor.submit(
- _start_service,
- docker_client,
- name,
- containers,
- project,
- False,
- recreate,
- )
- )
- for future in as_completed(futures):
- try:
- future.result()
- except Exception as e:
- click.secho(f"> Failed to start service: {e}", err=True, fg="red")
- raise
-
- # Check health of services. Seperate from _start_services
- # in case there are dependencies needed for the health
- # check (for example: kafka's healthcheck requires zookeeper)
- with ThreadPoolExecutor(max_workers=len(selected_services)) as executor:
- health_futures = []
- for name in selected_services:
- health_futures.append(
- executor.submit(
- check_health,
- name,
- containers[name],
- )
- )
- for health_future in as_completed(health_futures):
- try:
- health_future.result()
- except Exception as e:
- click.secho(f"> Failed to check health: {e}", err=True, fg="red")
- raise
-
-
-def _prepare_containers(
- project: str, skip_only_if: bool = False, silent: bool = False
-) -> dict[str, Any]:
- from django.conf import settings
-
- from sentry import options as sentry_options
-
- containers = {}
-
- for name, option_builder in settings.SENTRY_DEVSERVICES.items():
- options = option_builder(settings, sentry_options)
- only_if = options.pop("only_if", True)
-
- if not skip_only_if and not only_if:
- if not silent:
- click.secho(f"! Skipping {name} due to only_if condition", err=True, fg="cyan")
- continue
-
- options["network"] = project
- options["detach"] = True
- options["name"] = project + "_" + name
- options.setdefault("ports", {})
- options.setdefault("environment", {})
- # set policy to unless-stopped to avoid automatically restarting containers on boot
- # this is important given you can start multiple sets of containers that can conflict
- # with each other
- options.setdefault("restart_policy", {"Name": "unless-stopped"})
- options["ports"] = ensure_interface(options["ports"])
- options["extra_hosts"] = {"host.docker.internal": "host-gateway"}
- containers[name] = options
-
- # keys are service names
- # a service has 1 container exactly, the container name being value["name"]
- return containers
-
-
-@overload
-def _start_service(
- client: docker.DockerClient,
- name: str,
- containers: dict[str, Any],
- project: str,
- always_start: Literal[False] = ...,
- recreate: bool = False,
-) -> docker.models.containers.Container: ...
-
-
-@overload
-def _start_service(
- client: docker.DockerClient,
- name: str,
- containers: dict[str, Any],
- project: str,
- always_start: bool = False,
- recreate: bool = False,
-) -> docker.models.containers.Container | None: ...
-
-
-def _start_service(
- client: docker.DockerClient,
- name: str,
- containers: dict[str, Any],
- project: str,
- always_start: bool = False,
- recreate: bool = False,
-) -> docker.models.containers.Container | None:
- from docker.errors import NotFound
-
- options = containers[name]
-
- # If a service is associated with the devserver, then do not run the created container.
- # This was mainly added since it was not desirable for nginx to occupy port 8000 on the
- # first "devservices up".
- # Nowadays that nginx is gone again, it's still nice to be able to shut
- # down services within devserver.
- # See https://github.com/getsentry/sentry/pull/18362#issuecomment-616785458
- with_devserver = options.pop("with_devserver", False)
-
- # Two things call _start_service.
- # devservices up, and devservices attach.
- # Containers that should be started on-demand with devserver
- # should ONLY be started via the latter, which sets `always_start`.
- if with_devserver and not always_start:
- click.secho(
- f"> Not starting container '{options['name']}' because it should be started on-demand with devserver.",
- fg="yellow",
- )
- # XXX: if always_start=False, do not expect to have a container returned 100% of the time.
- return None
-
- container = None
- try:
- container = client.containers.get(options["name"])
- except NotFound:
- pass
-
- if container is not None:
- if not recreate and container.status == "running":
- click.secho(f"> Container '{options['name']}' is already running", fg="yellow")
- return container
-
- click.secho(f"> Stopping container '{container.name}'", fg="yellow")
- container.stop()
- click.secho(f"> Removing container '{container.name}'", fg="yellow")
- container.remove()
-
- for key, value in list(options["environment"].items()):
- options["environment"][key] = value.format(containers=containers)
-
- click.secho(f"> Pulling image '{options['image']}'", fg="green")
- retryable_pull(client, options["image"], platform=options.get("platform"))
-
- for mount in list(options.get("volumes", {}).keys()):
- if "/" not in mount:
- get_or_create(client, "volume", project + "_" + mount)
- options["volumes"][project + "_" + mount] = options["volumes"].pop(mount)
-
- listening = ""
- if options["ports"]:
- listening = "(listening: %s)" % ", ".join(map(str, options["ports"].values()))
-
- click.secho(f"> Creating container '{options['name']}'", fg="yellow")
- container = client.containers.create(**options)
- click.secho(f"> Starting container '{container.name}' {listening}", fg="yellow")
- container.start()
- return container
-
-
-@devservices.command()
-@click.option("--project", default="sentry")
-@click.argument("service", nargs=-1)
-def down(project: str, service: list[str]) -> None:
- """
- Shut down services without deleting their underlying data.
- Useful if you want to temporarily relieve resources on your computer.
-
- The default is everything, however you may pass positional arguments to specify
- an explicit list of services to bring down.
- """
-
- def _down(container: docker.models.containers.Container) -> None:
- click.secho(f"> Stopping '{container.name}' container", fg="red")
- container.stop()
- click.secho(f"> Removing '{container.name}' container", fg="red")
- container.remove()
-
- containers = []
- prefix = f"{project}_"
-
- with get_docker_client() as docker_client:
- for container in docker_client.containers.list(all=True):
- if not container.name.startswith(prefix):
- continue
- if service and not container.name[len(prefix) :] in service:
- continue
- containers.append(container)
-
- with ThreadPoolExecutor(max_workers=len(containers) or 1) as executor:
- futures = []
- for container in containers:
- futures.append(executor.submit(_down, container))
- for future in as_completed(futures):
- try:
- future.result()
- except Exception as e:
- click.secho(f"> Failed to stop service: {e}", err=True, fg="red")
- raise
-
-
-@devservices.command()
-@click.option("--project", default="sentry")
-@click.argument("services", nargs=-1)
-def rm(project: str, services: list[str]) -> None:
- """
- Shut down and delete all services and associated data.
- Useful if you'd like to start with a fresh slate.
-
- The default is everything, however you may pass positional arguments to specify
- an explicit list of services to remove.
- """
- from docker.errors import NotFound
-
- from sentry.runner import configure
-
- configure()
-
- containers = _prepare_containers(project, skip_only_if=len(services) > 0, silent=True)
-
- if services:
- selected_containers = {}
- for service in services:
- # XXX: This code is also fairly duplicated in here at this point, so dedupe in the future.
- if service not in containers:
- click.secho(
- f"Service `{service}` is not known or not enabled.\n",
- err=True,
- fg="red",
- )
- click.secho(
- "Services that are available:\n" + "\n".join(containers.keys()) + "\n", err=True
- )
- raise click.Abort()
- selected_containers[service] = containers[service]
- containers = selected_containers
-
- click.confirm(
- """
-This will delete these services and all of their data:
-
-%s
-
-Are you sure you want to continue?"""
- % "\n".join(containers.keys()),
- abort=True,
- )
-
- with get_docker_client() as docker_client:
- volume_to_service = {}
- for service_name, container_options in containers.items():
- try:
- container = docker_client.containers.get(container_options["name"])
- except NotFound:
- click.secho(
- "> WARNING: non-existent container '%s'" % container_options["name"],
- err=True,
- fg="yellow",
- )
- continue
-
- click.secho("> Stopping '%s' container" % container_options["name"], err=True, fg="red")
- container.stop()
- click.secho("> Removing '%s' container" % container_options["name"], err=True, fg="red")
- container.remove()
- for volume in container_options.get("volumes") or ():
- volume_to_service[volume] = service_name
-
- prefix = project + "_"
-
- for volume in docker_client.volumes.list():
- if volume.name.startswith(prefix):
- local_name = volume.name[len(prefix) :]
- if not services or volume_to_service.get(local_name) in services:
- click.secho("> Removing '%s' volume" % volume.name, err=True, fg="red")
- volume.remove()
-
- if not services:
- try:
- network = docker_client.networks.get(project)
- except NotFound:
- pass
- else:
- click.secho("> Removing '%s' network" % network.name, err=True, fg="red")
- network.remove()
-
-
-def check_health(service_name: str, options: dict[str, Any]) -> None:
- healthcheck = service_healthchecks.get(service_name, None)
- if healthcheck is None:
- return
-
- click.secho(f"> Checking container health '{service_name}'", fg="yellow")
-
- def hc() -> None:
- healthcheck.check(options)
-
- try:
- run_with_retries(
- hc,
- healthcheck.retries,
- healthcheck.timeout,
- f"Health check for '{service_name}' failed",
- )
- click.secho(f" > '{service_name}' is healthy", fg="green")
- except subprocess.CalledProcessError:
- click.secho(f" > '{service_name}' is not healthy", fg="red")
- raise
-
-
-def run_with_retries(
- cmd: Callable[[], object], retries: int = 3, timeout: int = 5, message: str = "Command failed"
-) -> None:
- for retry in range(1, retries + 1):
- try:
- cmd()
- except (
- subprocess.CalledProcessError,
- urllib.error.HTTPError,
- http.client.RemoteDisconnected,
- ):
- if retry == retries:
- raise
- else:
- click.secho(
- f" > {message}, retrying in {timeout}s (attempt {retry+1} of {retries})...",
- fg="yellow",
- )
- time.sleep(timeout)
- else:
- return
-
-
-def check_postgres(options: dict[str, Any]) -> None:
- subprocess.run(
- (
- "docker",
- "exec",
- options["name"],
- "pg_isready",
- "-U",
- "postgres",
- ),
- check=True,
- capture_output=True,
- text=True,
- )
-
-
-def check_rabbitmq(options: dict[str, Any]) -> None:
- subprocess.run(
- (
- "docker",
- "exec",
- options["name"],
- "rabbitmq-diagnostics",
- "-q",
- "ping",
- ),
- check=True,
- capture_output=True,
- text=True,
- )
-
-
-def check_redis(options: dict[str, Any]) -> None:
- subprocess.run(
- (
- "docker",
- "exec",
- options["name"],
- "redis-cli",
- "ping",
- ),
- check=True,
- capture_output=True,
- text=True,
- )
-
-
-def check_vroom(options: dict[str, Any]) -> None:
- (port,) = options["ports"].values()
-
- # Vroom is a slim debian based image and does not have curl, wget or
- # python3. Check health with a simple request on the host machine.
- urllib.request.urlopen(f"http://{port[0]}:{port[1]}/health", timeout=1)
-
-
-def check_clickhouse(options: dict[str, Any]) -> None:
- port = options["ports"]["8123/tcp"]
- subprocess.run(
- (
- "docker",
- "exec",
- options["name"],
- # Using wget instead of curl as that is what is available
- # in the clickhouse image
- "wget",
- f"http://{port[0]}:{port[1]}/ping",
- ),
- check=True,
- capture_output=True,
- text=True,
- )
-
-
-def check_kafka(options: dict[str, Any]) -> None:
- (port,) = options["ports"].values()
- subprocess.run(
- (
- "docker",
- "exec",
- options["name"],
- "kafka-topics",
- "--bootstrap-server",
- # Port is a tuple of (127.0.0.1, )
- f"{port[0]}:{port[1]}",
- "--list",
- ),
- check=True,
- capture_output=True,
- text=True,
- )
-
-
-def check_symbolicator(options: dict[str, Any]) -> None:
- (port,) = options["ports"].values()
- subprocess.run(
- (
- "docker",
- "exec",
- options["name"],
- "curl",
- f"http://{port[0]}:{port[1]}/healthcheck",
- ),
- check=True,
- capture_output=True,
- text=True,
- )
-
-
-def python_call_url_prog(url: str) -> str:
- return f"""
-import urllib.request
-try:
- req = urllib.request.urlopen({url!r}, timeout=1)
-except Exception as e:
- raise SystemExit(f'service is not ready: {{e}}')
-else:
- print('service is ready!')
-"""
-
-
-def check_chartcuterie(options: dict[str, Any]) -> None:
- # Chartcuterie binds the internal port to a different port
- internal_port = 9090
- port = options["ports"][f"{internal_port}/tcp"]
- url = f"http://{port[0]}:{internal_port}/api/chartcuterie/healthcheck/live"
- subprocess.run(
- (
- "docker",
- "exec",
- options["name"],
- "python3",
- "-uc",
- python_call_url_prog(url),
- ),
- check=True,
- capture_output=True,
- text=True,
- )
-
-
-def check_snuba(options: dict[str, Any]) -> None:
- from django.conf import settings
-
- url = f"{settings.SENTRY_SNUBA}/health_envoy"
- subprocess.run(
- (
- "docker",
- "exec",
- options["name"],
- "python3",
- "-uc",
- python_call_url_prog(url),
- ),
- check=True,
- capture_output=True,
- text=True,
- )
-
-
-class ServiceHealthcheck(NamedTuple):
- check: Callable[[dict[str, Any]], None]
- retries: int = 3
- timeout: int = 5
-
-
-service_healthchecks: dict[str, ServiceHealthcheck] = {
- "postgres": ServiceHealthcheck(check=check_postgres),
- "rabbitmq": ServiceHealthcheck(check=check_rabbitmq),
- "redis": ServiceHealthcheck(check=check_redis),
- "clickhouse": ServiceHealthcheck(check=check_clickhouse),
- "kafka": ServiceHealthcheck(check=check_kafka),
- "vroom": ServiceHealthcheck(check=check_vroom),
- "symbolicator": ServiceHealthcheck(check=check_symbolicator),
- "chartcuterie": ServiceHealthcheck(check=check_chartcuterie),
- "snuba": ServiceHealthcheck(check=check_snuba, retries=12, timeout=10),
-}
+# compatibility stub
+@click.command()
+@click.argument("args", nargs=-1)
+def devservices(args: tuple[str, ...]) -> None:
+ return
diff --git a/src/sentry/testutils/pytest/relay.py b/src/sentry/testutils/pytest/relay.py
index de488d5009e15c..f1551226ca6024 100644
--- a/src/sentry/testutils/pytest/relay.py
+++ b/src/sentry/testutils/pytest/relay.py
@@ -69,7 +69,7 @@ def relay_server_setup(live_server, tmpdir_factory):
relay_port = ephemeral_port_reserve.reserve(ip="127.0.0.1", port=33331)
redis_db = TEST_REDIS_DB
- use_old_devservices = environ.get("USE_OLD_DEVSERVICES", "0") == "1"
+
from sentry.relay import projectconfig_cache
from sentry.relay.projectconfig_cache.redis import RedisProjectConfigCache
@@ -81,8 +81,8 @@ def relay_server_setup(live_server, tmpdir_factory):
template_vars = {
"SENTRY_HOST": f"http://host.docker.internal:{port}/",
"RELAY_PORT": relay_port,
- "KAFKA_HOST": "sentry_kafka" if use_old_devservices else "kafka",
- "REDIS_HOST": "sentry_redis" if use_old_devservices else "redis",
+ "KAFKA_HOST": "kafka",
+ "REDIS_HOST": "redis",
"REDIS_DB": redis_db,
}
@@ -107,7 +107,7 @@ def relay_server_setup(live_server, tmpdir_factory):
options = {
"image": RELAY_TEST_IMAGE,
"ports": {"%s/tcp" % relay_port: relay_port},
- "network": "sentry" if use_old_devservices else "devservices",
+ "network": "devservices",
"detach": True,
"name": container_name,
"volumes": {config_path: {"bind": "/etc/relay"}},
diff --git a/src/sentry/testutils/skips.py b/src/sentry/testutils/skips.py
index 61f2ae758c215e..58c8a98857f995 100644
--- a/src/sentry/testutils/skips.py
+++ b/src/sentry/testutils/skips.py
@@ -1,10 +1,8 @@
from __future__ import annotations
import socket
-from urllib.parse import urlparse
import pytest
-from django.conf import settings
def _service_available(host: str, port: int) -> bool:
@@ -23,38 +21,30 @@ def _requires_service_message(name: str) -> str:
@pytest.fixture(scope="session")
def _requires_snuba() -> None:
- parsed = urlparse(settings.SENTRY_SNUBA)
- assert parsed.hostname is not None
- assert parsed.port is not None
- if not _service_available(parsed.hostname, parsed.port):
+ # TODO: ability to ask devservices what port a service is on
+ if not _service_available("127.0.0.1", 1218):
pytest.fail(_requires_service_message("snuba"))
@pytest.fixture(scope="session")
def _requires_kafka() -> None:
- kafka_conf = settings.SENTRY_DEVSERVICES["kafka"](settings, {})
- (port,) = kafka_conf["ports"].values()
-
- if not _service_available("127.0.0.1", port):
+ # TODO: ability to ask devservices what port a service is on
+ if not _service_available("127.0.0.1", 9092):
pytest.fail(_requires_service_message("kafka"))
@pytest.fixture(scope="session")
def _requires_symbolicator() -> None:
- symbolicator_conf = settings.SENTRY_DEVSERVICES["symbolicator"](settings, {})
- (port,) = symbolicator_conf["ports"].values()
-
- if not _service_available("127.0.0.1", port):
+ # TODO: ability to ask devservices what port a service is on
+ if not _service_available("127.0.0.1", 3021):
service_message = "requires 'symbolicator' server running\n\t💡 Hint: run `devservices up --mode=symbolicator`"
pytest.fail(service_message)
@pytest.fixture(scope="session")
def _requires_objectstore() -> None:
- objectstore_conf = settings.SENTRY_DEVSERVICES["objectstore"](settings, {})
- (port,) = objectstore_conf["ports"].values()
-
- if not _service_available("127.0.0.1", port):
+ # TODO: ability to ask devservices what port a service is on
+ if not _service_available("127.0.0.1", 8888):
service_message = "requires 'objectstore' server running\n\t💡 Hint: run `devservices up --mode=objectstore`"
pytest.skip(service_message)