|
| 1 | +# coding=utf-8 |
| 2 | +from __future__ import unicode_literals, print_function |
| 3 | +import re |
| 4 | +from volcenginesdkcore.endpoint.endpoint_provider import EndpointProvider, ResolvedEndpoint |
| 5 | + |
| 6 | + |
| 7 | +# ----------------------------- |
| 8 | +# Errors (模仿 volcengineerr.New) |
| 9 | +# ----------------------------- |
| 10 | +class StandProviderError(Exception): |
| 11 | + def __init__(self, code, message): |
| 12 | + Exception.__init__(self, "%s: %s" % (code, message)) |
| 13 | + self.code = code |
| 14 | + self.message = message |
| 15 | + |
| 16 | + |
| 17 | +# ----------------------------- |
| 18 | +# 常量 |
| 19 | +# ----------------------------- |
| 20 | +DEFAULT_FORMAT = "{Service}{Region}.{SiteStack}.com" |
| 21 | + |
| 22 | +# 站点栈 |
| 23 | +SITE_STACK_VOLC_IPV4 = "volcengineapi" |
| 24 | +SITE_STACK_VOLC_DUAL_STACK = "volcengine-api" |
| 25 | + |
| 26 | + |
| 27 | +# ----------------------------- |
| 28 | +# 数据模型(兼容 2.7/3.x 的朴素类) |
| 29 | +# ----------------------------- |
| 30 | +class StandardEndpointResolverVariable(object): |
| 31 | + def __init__(self): |
| 32 | + self.service = "" |
| 33 | + self.region = "" |
| 34 | + self.site_stack = "" |
| 35 | + self.extension = {} |
| 36 | + |
| 37 | + def to_dict(self): |
| 38 | + return { |
| 39 | + "Service": self.service, |
| 40 | + "Region": self.region, |
| 41 | + "SiteStack": self.site_stack, |
| 42 | + "Extension": self.extension, |
| 43 | + } |
| 44 | + |
| 45 | + |
| 46 | +class ServiceInfo(object): |
| 47 | + def __init__(self, service, is_global): |
| 48 | + self.service = service |
| 49 | + self.IsGlobal = is_global |
| 50 | + |
| 51 | +ServiceInfos = { |
| 52 | + "vpc": ServiceInfo("vpc", False), |
| 53 | + "ecs": ServiceInfo("ecs", False), |
| 54 | + "billing": ServiceInfo("billing", True), |
| 55 | + "ark": ServiceInfo("ark", False), |
| 56 | + "iam": ServiceInfo("iam", True), |
| 57 | + "mcs": ServiceInfo("mcs", False), |
| 58 | + "rocketmq": ServiceInfo("rocketmq", False), |
| 59 | + "bytehouse": ServiceInfo("bytehouse", False), |
| 60 | + "dns": ServiceInfo("dns", True), |
| 61 | + "autoscaling": ServiceInfo("autoscaling", False), |
| 62 | + "spark": ServiceInfo("spark", False), |
| 63 | + "cloud_detect": ServiceInfo("cloud_detect", False), |
| 64 | + "filenas": ServiceInfo("filenas", False), |
| 65 | + "escloud": ServiceInfo("escloud", False), |
| 66 | + "flink": ServiceInfo("flink", False), |
| 67 | + "cp": ServiceInfo("cp", False), |
| 68 | + "vefaas": ServiceInfo("vefaas", False), |
| 69 | + "ml_platform": ServiceInfo("ml_platform", False), |
| 70 | + "edx": ServiceInfo("edx", True), |
| 71 | + "dcdn": ServiceInfo("dcdn", True), |
| 72 | + "cdn": ServiceInfo("cdn", True), |
| 73 | + "kafka": ServiceInfo("kafka", False), |
| 74 | + "certificate_service": ServiceInfo("certificate_service", True), |
| 75 | + "waf": ServiceInfo("waf", True), |
| 76 | + "rds_mssql": ServiceInfo("rds_mssql", False), |
| 77 | + "cloudtrail": ServiceInfo("cloudtrail", False), |
| 78 | + "vei_api": ServiceInfo("vei_api", True), |
| 79 | + "cen": ServiceInfo("cen", True), |
| 80 | + "rabbitmq": ServiceInfo("rabbitmq", False), |
| 81 | + "vmp": ServiceInfo("vmp", False), |
| 82 | + "volc_observe": ServiceInfo("volc_observe", False), |
| 83 | + "dataleap": ServiceInfo("dataleap", False), |
| 84 | + "fw_center": ServiceInfo("fw_center", True), |
| 85 | + "redis": ServiceInfo("redis", False), |
| 86 | + "mcdn": ServiceInfo("mcdn", True), |
| 87 | + "cloudidentity": ServiceInfo("cloudidentity", False), |
| 88 | + "vedbm": ServiceInfo("vedbm", False), |
| 89 | + "cv": ServiceInfo("cv", True), |
| 90 | + "translate": ServiceInfo("translate", True), |
| 91 | + "cloud_trail": ServiceInfo("cloud_trail", False), |
| 92 | + "bio": ServiceInfo("bio", False), |
| 93 | + "nta": ServiceInfo("nta", True), |
| 94 | + "elasticmapreduce": ServiceInfo("elasticmapreduce", False), |
| 95 | + "vepfs": ServiceInfo("vepfs", False), |
| 96 | + "seccenter": ServiceInfo("seccenter", True), |
| 97 | + "advdefence": ServiceInfo("advdefence", True), |
| 98 | + "tis": ServiceInfo("tis", True), |
| 99 | + "organization": ServiceInfo("organization", True), |
| 100 | + "vke": ServiceInfo("vke", False), |
| 101 | + "Redis": ServiceInfo("Redis", False), |
| 102 | + "privatelink": ServiceInfo("privatelink", False), |
| 103 | + "RocketMQ": ServiceInfo("RocketMQ", False), |
| 104 | + "Kafka": ServiceInfo("Kafka", False), |
| 105 | + "rds_mysql": ServiceInfo("rds_mysql", False), |
| 106 | + "rds_postgresql": ServiceInfo("rds_postgresql", False), |
| 107 | + "storage_ebs": ServiceInfo("storage_ebs", False), |
| 108 | + "clb": ServiceInfo("clb", False), |
| 109 | + "alb": ServiceInfo("alb", False), |
| 110 | + "FileNAS": ServiceInfo("FileNAS", False), |
| 111 | + "configcenter": ServiceInfo("configcenter", False), |
| 112 | + "cr": ServiceInfo("cr", False), |
| 113 | + "sts": ServiceInfo("sts", False), |
| 114 | + "mongodb": ServiceInfo("mongodb", False), |
| 115 | + "transitrouter": ServiceInfo("transitrouter", False), |
| 116 | + "Volc_Observe": ServiceInfo("Volc_Observe", False), |
| 117 | + "dms": ServiceInfo("dms", False), |
| 118 | + "auto_scaling": ServiceInfo("auto_scaling", False), |
| 119 | + "directconnect": ServiceInfo("directconnect", False), |
| 120 | + "kms": ServiceInfo("kms", False), |
| 121 | + "dbw": ServiceInfo("dbw", False), |
| 122 | + "dts": ServiceInfo("dts", False), |
| 123 | + "natgateway": ServiceInfo("natgateway", False), |
| 124 | + "tos": ServiceInfo("tos", False), |
| 125 | + "TLS": ServiceInfo("TLS", False), |
| 126 | + "vpn": ServiceInfo("vpn", False), |
| 127 | + "vod": ServiceInfo("vod", False), |
| 128 | + "quota": ServiceInfo("quota", True), |
| 129 | + "ecs_ops": ServiceInfo("ecs_ops", True), |
| 130 | + "as_ops": ServiceInfo("as_ops", True), |
| 131 | + "account_management": ServiceInfo("account_management", True), |
| 132 | + "account_management_byteplus": ServiceInfo("account_management_byteplus", True), |
| 133 | + "bandwidthquota": ServiceInfo("bandwidthquota", True), |
| 134 | + "psa_manager": ServiceInfo("psa_manager", True), |
| 135 | + "dc_controller": ServiceInfo("dc_controller", False), |
| 136 | + "eps_platform_trade": ServiceInfo("eps_platform_trade", False), |
| 137 | + "eps_platform_fund": ServiceInfo("eps_platform_fund", False), |
| 138 | + "commercialization": ServiceInfo("commercialization", True), |
| 139 | + "veecp_openapi": ServiceInfo("veecp_openapi", False), |
| 140 | + "orgnization": ServiceInfo("orgnization", True), |
| 141 | + "coze": ServiceInfo("coze", True), |
| 142 | + "sec_agent": ServiceInfo("sec_agent", True), |
| 143 | + "sec_intelligent_dev": ServiceInfo("sec_intelligent_dev", True), |
| 144 | + "vegame": ServiceInfo("vegame", False), |
| 145 | + "acep": ServiceInfo("acep", True), |
| 146 | + "private_zone": ServiceInfo("private_zone", True), |
| 147 | + "sqs": ServiceInfo("sqs", False), |
| 148 | + "resourcecenter": ServiceInfo("resourcecenter", True), |
| 149 | + "aiotvideo": ServiceInfo("aiotvideo", True), |
| 150 | + "apig": ServiceInfo("apig", False), |
| 151 | + "bmq": ServiceInfo("bmq", False), |
| 152 | + "bytehouse_ce": ServiceInfo("bytehouse_ce", False), |
| 153 | + "cloudmonitor": ServiceInfo("cloudmonitor", False), |
| 154 | + "emr": ServiceInfo("emr", False), |
| 155 | + "ga": ServiceInfo("ga", True), |
| 156 | + "graph": ServiceInfo("graph", False), |
| 157 | + "gtm": ServiceInfo("gtm", True), |
| 158 | + "hbase": ServiceInfo("hbase", False), |
| 159 | + "metakms": ServiceInfo("metakms", False), |
| 160 | + "na": ServiceInfo("na", True), |
| 161 | + "resource_share": ServiceInfo("resource_share", True), |
| 162 | + "speech_saas_prod": ServiceInfo("speech_saas_prod", True), |
| 163 | + "tag": ServiceInfo("tag", True), |
| 164 | + "vefaas_dev": ServiceInfo("vefaas_dev", False), |
| 165 | + "vms": ServiceInfo("vms", False), |
| 166 | + "eco_partner": ServiceInfo("eco_partner", True), |
| 167 | + "smc": ServiceInfo("smc", True), |
| 168 | +} |
| 169 | + |
| 170 | + |
| 171 | +# ----------------------------- |
| 172 | +# Region 校验 |
| 173 | +# ----------------------------- |
| 174 | +class RegionChecker(object): |
| 175 | + def __init__(self, white_regions, pattern): |
| 176 | + self.white_regions = white_regions or {} |
| 177 | + self.pattern = pattern |
| 178 | + |
| 179 | + def validate(self, region): |
| 180 | + if self.white_regions and region in self.white_regions: |
| 181 | + return True |
| 182 | + if self.pattern: |
| 183 | + return bool(self.pattern.match(region)) |
| 184 | + return False |
| 185 | + |
| 186 | + |
| 187 | +region_matcher = RegionChecker( |
| 188 | + { |
| 189 | + "ap-singapore-1": {}, |
| 190 | + "ap-southeast-1": {}, |
| 191 | + "ap-southeast-2": {}, |
| 192 | + "ap-southeast-3": {}, |
| 193 | + "byteplus-global": {}, |
| 194 | + "cn-beijing": {}, |
| 195 | + "cn-beijing-autodriving": {}, |
| 196 | + "cn-beijing-selfdrive": {}, |
| 197 | + "cn-beijing2": {}, |
| 198 | + "cn-beijing300": {}, |
| 199 | + "cn-changsha-sdv": {}, |
| 200 | + "cn-chengdu": {}, |
| 201 | + "cn-chengdu-sdv": {}, |
| 202 | + "cn-chongqing-sdv": {}, |
| 203 | + "cn-datong": {}, |
| 204 | + "cn-east-1-dedicated": {}, |
| 205 | + "cn-gaofang-bj": {}, |
| 206 | + "cn-gaofang-gz1": {}, |
| 207 | + "cn-gaofang-nt1": {}, |
| 208 | + "cn-gaofang-nt2": {}, |
| 209 | + "cn-gaofang-nt3": {}, |
| 210 | + "cn-gaofang-nt4": {}, |
| 211 | + "cn-gaofang-nt5": {}, |
| 212 | + "cn-guangzhou": {}, |
| 213 | + "cn-guilin-boe": {}, |
| 214 | + "cn-hangzhou": {}, |
| 215 | + "cn-hjxj": {}, |
| 216 | + "cn-hjzg": {}, |
| 217 | + "cn-hlbx": {}, |
| 218 | + "cn-hlxj": {}, |
| 219 | + "cn-hlzg": {}, |
| 220 | + "cn-hongkong": {}, |
| 221 | + "cn-hongkong-pop": {}, |
| 222 | + "cn-lfbx": {}, |
| 223 | + "cn-lfxj": {}, |
| 224 | + "cn-lfzg": {}, |
| 225 | + "cn-macau-pop-sdv": {}, |
| 226 | + "cn-mainland": {}, |
| 227 | + "cn-nanjing-bbit": {}, |
| 228 | + "cn-ningbo-sdv": {}, |
| 229 | + "cn-north-1": {}, |
| 230 | + "cn-north-1-dedicated": {}, |
| 231 | + "cn-north-boe": {}, |
| 232 | + "cn-shanghai": {}, |
| 233 | + "cn-shanghai-autodriving": {}, |
| 234 | + "cn-taiwan-boe": {}, |
| 235 | + "cn-wuhan": {}, |
| 236 | + "cn-wulanchabu": {}, |
| 237 | + "cn-xian-boe-sdv": {}, |
| 238 | + "overseas-1": {}, |
| 239 | + "rec-cn": {}, |
| 240 | + "rec-sg": {}, |
| 241 | + }, |
| 242 | + re.compile( |
| 243 | + r"^(?:[a-z]{2}-[a-z]+(?:-[a-z]+)?|(?:cn|ap|eu|na|sa|me|af)-[a-z]+-\d+(?:-(?:finance|exclusive|local|inner))?)$" |
| 244 | + ), |
| 245 | +) |
| 246 | + |
| 247 | + |
| 248 | +# ----------------------------- |
| 249 | +# 工具函数 |
| 250 | +# ----------------------------- |
| 251 | +def standardize_domain_service_code(service_code): |
| 252 | + """lower + '_' -> '-'""" |
| 253 | + return service_code.lower().replace("_", "-") |
| 254 | + |
| 255 | + |
| 256 | +# ----------------------------- |
| 257 | +# 解析器 |
| 258 | +# ----------------------------- |
| 259 | +class StandardEndpointResolver(EndpointProvider): |
| 260 | + def __init__(self, fmt=None, site_stack=None, extension=None, custom_services=None): |
| 261 | + self.fmt = fmt or DEFAULT_FORMAT |
| 262 | + self.variables = StandardEndpointResolverVariable() |
| 263 | + self.variables.site_stack = site_stack or SITE_STACK_VOLC_IPV4 |
| 264 | + self.variables.extension = extension or {} |
| 265 | + self.custom_services = custom_services or {} |
| 266 | + |
| 267 | + def endpoint_for(self, service, region, custom_bootstrap_region=None, use_dual_stack=None, **kwargs): |
| 268 | + # 1) Region 校验 |
| 269 | + if not region_matcher.validate(region): |
| 270 | + raise StandProviderError( |
| 271 | + "InvalidRegion", |
| 272 | + "invalid region %s for standard endpoint resolver, " |
| 273 | + "please upgrade the sdk endpoint resolver to the latest version" % region |
| 274 | + ) |
| 275 | + |
| 276 | + # 2) 默认模板 |
| 277 | + fmt = self.fmt or DEFAULT_FORMAT |
| 278 | + |
| 279 | + # 3) 变量准备 |
| 280 | + self.variables.service = standardize_domain_service_code(service) |
| 281 | + |
| 282 | + svc_info = ServiceInfos.get(service) |
| 283 | + if not svc_info: |
| 284 | + svc_info = self.custom_services.get(service) |
| 285 | + if not svc_info: |
| 286 | + raise StandProviderError( |
| 287 | + "ServiceNotFound", |
| 288 | + "service %s not found in ServiceInfos or customServices, " |
| 289 | + "please upgrade the sdk endpoint resolver to the latest version" % service |
| 290 | + ) |
| 291 | + |
| 292 | + # 非全局服务拼接 ".{region}",全局则为空 |
| 293 | + if not svc_info.IsGlobal: |
| 294 | + self.variables.region = "." + region |
| 295 | + else: |
| 296 | + self.variables.region = "" |
| 297 | + |
| 298 | + # 4) IP 版本 -> SiteStack |
| 299 | + if use_dual_stack: |
| 300 | + self.variables.site_stack = SITE_STACK_VOLC_DUAL_STACK |
| 301 | + else: |
| 302 | + self.variables.site_stack = SITE_STACK_VOLC_IPV4 |
| 303 | + |
| 304 | + # 5) 渲染 |
| 305 | + try: |
| 306 | + rendered = fmt.format(**self.variables.to_dict()) |
| 307 | + except KeyError as err: |
| 308 | + raise StandProviderError( |
| 309 | + "TemplateExecuteError", |
| 310 | + "failed to execute template for format %s, missing variable %s" % (fmt, err) |
| 311 | + ) |
| 312 | + except Exception as err: |
| 313 | + raise StandProviderError( |
| 314 | + "TemplateExecuteError", |
| 315 | + "failed to execute template for format %s, variable %r: %s" % (fmt, self.variables.to_dict(), err) |
| 316 | + ) |
| 317 | + |
| 318 | + return ResolvedEndpoint(rendered) |
| 319 | + |
| 320 | + |
| 321 | +# ----------------------------- |
| 322 | +if __name__ == "__main__": |
| 323 | + r = StandardEndpointResolver() |
| 324 | + try: |
| 325 | + ep = r.endpoint_for( |
| 326 | + service="vpc", |
| 327 | + region="ap-southeast-1", |
| 328 | + use_dual_stack=False, |
| 329 | + ) |
| 330 | + print(ep.host) # 例如:vpc.ap-southeast-1.volcengine-api.com |
| 331 | + except Exception as e: |
| 332 | + e.print() |
0 commit comments