123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110 |
- #!/usr/bin/python3
- import json # noqa
- import re
- from collections.abc import Mapping
- from dataclasses import dataclass
- from typing import Any
- import click
- """Convenience script for setting up silos in a dev environment.
- Prints devserver commands with the necessary environment variables.
- """
- @dataclass(frozen=True)
- class RegionConfig:
- number: int
- port: int
- api_token: str
- @property
- def name(self) -> str:
- return f"devregion{self.number}"
- @property
- def bind(self) -> str:
- return f"localhost:{self.port}"
- def get_env_repr(self) -> Mapping[str, Any]:
- return {
- "name": self.name,
- "id": self.number,
- "address": f"http://{self.bind}/",
- "category": "MULTI_TENANT",
- "api_token": self.api_token,
- }
- def format_env_vars(env_vars: Mapping[str, str]) -> str:
- def format_env_var(name: str, value: str) -> str:
- value = re.sub("([\"$'\\\\])", "\\\\\\1", value) # https://xkcd.com/1638/
- return f'{name}="{value}"'
- return " ".join(format_env_var(name, value) for (name, value) in env_vars.items())
- @click.command()
- @click.option(
- "--api-token",
- type=str,
- required=True,
- help=(
- """An API token to authorize RPC requests between servers.
- At the time this script is being written, the authentication system for RPCs
- hasn't been developed. An API token is needed to ensure that an incoming
- request hits a REST endpoint, but it doesn't need to have any particular
- permission scope.
- Because dev instances of the control and region silo will presumably share a
- single database, this script assumes that the same API token will work for both.
- """
- ),
- )
- @click.option("--region-count", type=int, default=2, help="Number of region silos")
- @click.option(
- "--control-port",
- type=int,
- default=8000,
- help=(
- """Port on which to bind the control silo.
- Region silos will be bound on ascending numbers after this one in steps of 10.
- """
- ),
- )
- def main(api_token: str, region_count: int, control_port: int) -> None:
- sender_credentials = {
- "is_allowed": True,
- "control_silo_api_token": api_token,
- "control_silo_address": f"http://localhost:{control_port}/",
- }
- regions = [
- RegionConfig(n, control_port + 10 * n, api_token) for n in range(1, region_count + 1)
- ]
- region_config = json.dumps([r.get_env_repr() for r in regions])
- common_env_vars = {}
- common_env_vars["SENTRY_REGION_CONFIG"] = region_config
- common_env_vars["SENTRY_DEV_HYBRID_CLOUD_RPC_SENDER"] = json.dumps(sender_credentials)
- control_env_vars = common_env_vars.copy()
- control_env_vars["SENTRY_SILO_MODE"] = "CONTROL"
- control_env_vars["SENTRY_DEVSERVER_BIND"] = f"localhost:{control_port}"
- print(f"# Control silo\n{format_env_vars(control_env_vars)} sentry devserver") # noqa
- for region in regions:
- region_env_vars = common_env_vars.copy()
- region_env_vars["SENTRY_SILO_MODE"] = "REGION"
- region_env_vars["SENTRY_REGION"] = region.name
- region_env_vars["SENTRY_DEVSERVER_BIND"] = region.bind
- print(f"\n# {region.name}\n{format_env_vars(region_env_vars)} sentry devserver") # noqa
- main()
|