import time from urllib.parse import urljoin import requests from tenacity import retry, stop_after_attempt, wait_fixed, before_sleep_log from consts.consts import ENV_DEV, ENV_STAGING, ENV_PROD from errors.errors import BadRequestException from svc.measuring import EDA_DATAAPI_HISTOGRAM from utils.logging import logging logger = logging.getLogger(__name__) # Cloud provider constant for AliCloud CLOUD_PROVIDER_ALICLOUD = "alicloud" def get_global_inner_domain(env: str): if env == ENV_DEV: return "https://inner-central.dev.tidbcloud.com" elif env == ENV_STAGING: return "https://inner-central.staging.tidbcloud.com" elif env == ENV_PROD: return "https://inner-central.prod.tidbcloud.com" else: raise BadRequestException(f"invalid env: {env}") def get_o11y_region_inner_domain(env: str, region: str): if env == ENV_DEV or env == ENV_STAGING: region = "us-west-2" return "https://" + region + ".inner-region.o11y." + env + ".tidbcloud.com" def get_alicloud_region_inner_domain(env: str, region: str): """ Get AliCloud regional inner domain. Format: https://regionalsvc01.{region}.{env}.alicloud.tidbcloud.com Examples: - https://regionalsvc01.ap-southeast-1.prod.alicloud.tidbcloud.com - https://regionalsvc01.us-west-2.dev.alicloud.tidbcloud.com """ return f"https://regionalsvc01.{region}.{env}.alicloud.tidbcloud.com" def get_o11y_region_inner_domain_with_provider(env: str, region: str, provider: str): """ Get regional inner domain based on provider. For AliCloud, uses the new AliCloud domain format. For others (AWS), uses the existing o11y domain format. """ provider = (provider or "").strip().lower() if provider == CLOUD_PROVIDER_ALICLOUD: return get_alicloud_region_inner_domain(env, region) return get_o11y_region_inner_domain(env, region) def get_provider_scoped_dataservice_path(provider: str, url: str): """ Get provider-scoped inner dataservice path. For AliCloud, adds /dataservice prefix to the path. For others, returns the original path. Examples: - AliCloud: /inner/dataservice/exec/sql -> /dataservice/inner/dataservice/exec/sql - AWS: /inner/dataservice/exec/sql -> /inner/dataservice/exec/sql """ provider = (provider or "").strip().lower() if provider == CLOUD_PROVIDER_ALICLOUD: return "/dataservice" + url return url class CrossRegionClient: def __init__(self, env: str, basic_auth_encoded: str, trace_id: str = "") -> None: self.env = env self.trace_id = trace_id self.basic_auth_encoded = basic_auth_encoded def request_global(self, method, url, **kwargs): s = requests.Session() base_url = get_global_inner_domain(self.env) full_url = urljoin(base_url, url) headers = kwargs.get("headers", {}) headers["Authorization"] = f"Basic {self.basic_auth_encoded}" headers["B3"] = self.trace_id kwargs["headers"] = headers start = time.time() resp = s.request(method, full_url, **kwargs) logging.info("request global, url, method, args, resp code, body: %s, %s, %s, %s, %s", full_url, method, kwargs, resp.status_code, resp.text) EDA_DATAAPI_HISTOGRAM.labels(region="global", url=url, status=resp.status_code).observe(time.time() - start) return resp @retry(reraise=True, wait=wait_fixed(3), stop=stop_after_attempt(5), before_sleep=before_sleep_log(logger, logging.INFO)) def request_o11y(self, region, method, url, **kwargs): s = requests.Session() base_url = get_o11y_region_inner_domain(self.env, region) full_url = urljoin(base_url, url) headers = kwargs.get("headers", {}) headers["Authorization"] = f"Basic {self.basic_auth_encoded}" kwargs["headers"] = headers headers["B3"] = self.trace_id start = time.time() resp = s.request(method, full_url, **kwargs) logging.info("request o11y, url, region, method, args, resp code, body: %s, %s, %s, %s, %s, %s", full_url, region, method, kwargs, resp.status_code, resp.text) EDA_DATAAPI_HISTOGRAM.labels(region=region, url=url, status=resp.status_code).observe(time.time() - start) return resp @retry(reraise=True, wait=wait_fixed(3), stop=stop_after_attempt(5), before_sleep=before_sleep_log(logger, logging.INFO)) def request_o11y_with_provider(self, region, provider, method, url, **kwargs): """ Request to o11y regional endpoint with provider support. For AliCloud provider: - Uses AliCloud domain: https://regionalsvc01.{region}.{env}.alicloud.tidbcloud.com - Adds /dataservice prefix to the path Args: region: The region to send the request to provider: Cloud provider (e.g., 'alicloud', 'aws') method: HTTP method url: API path (e.g., '/inner/dataservice/exec/sql') **kwargs: Additional request arguments """ s = requests.Session() base_url = get_o11y_region_inner_domain_with_provider(self.env, region, provider) scoped_url = get_provider_scoped_dataservice_path(provider, url) full_url = urljoin(base_url, scoped_url) headers = kwargs.get("headers", {}) headers["Authorization"] = f"Basic {self.basic_auth_encoded}" kwargs["headers"] = headers headers["B3"] = self.trace_id start = time.time() resp = s.request(method, full_url, **kwargs) logging.info( "request o11y with provider, url, region, provider, method, args, resp code, body: %s, %s, %s, %s, %s, %s, %s", full_url, region, provider, method, kwargs, resp.status_code, resp.text ) EDA_DATAAPI_HISTOGRAM.labels(region=region, url=url, status=resp.status_code).observe(time.time() - start) return resp