byteplus-python-sdk-v2 3.0.61__py2.py3-none-any.whl → 3.0.63__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. {byteplus_python_sdk_v2-3.0.61.dist-info → byteplus_python_sdk_v2-3.0.63.dist-info}/METADATA +1 -1
  2. {byteplus_python_sdk_v2-3.0.61.dist-info → byteplus_python_sdk_v2-3.0.63.dist-info}/RECORD +111 -64
  3. {byteplus_python_sdk_v2-3.0.61.dist-info → byteplus_python_sdk_v2-3.0.63.dist-info}/WHEEL +1 -1
  4. byteplussdkcore/api_client.py +36 -8
  5. byteplussdkcore/auth/provider_binding.py +42 -0
  6. byteplussdkcore/auth/providers/sts_oidc_provider.py +23 -3
  7. byteplussdkcore/auth/providers/sts_provider.py +32 -3
  8. byteplussdkcore/auth/providers/sts_saml_provider.py +23 -3
  9. byteplussdkcore/auth/sts_http_config.py +133 -0
  10. byteplussdkcore/configuration.py +1 -1
  11. byteplussdkcore/feature/rds/connect_utils.py +6 -8
  12. byteplussdkcore/interceptor/interceptors/request.py +5 -0
  13. byteplussdkcore/rest.py +27 -0
  14. byteplussdkcore/retryer/retry_condition.py +29 -1
  15. byteplussdkecopartner/__init__.py +10 -0
  16. byteplussdkecopartner/api/eco_partner_api.py +291 -0
  17. byteplussdkecopartner/models/__init__.py +10 -0
  18. byteplussdkecopartner/models/download_bill_request.py +129 -0
  19. byteplussdkredis/models/configure_node_for_create_enterprise_db_instance_input.py → byteplussdkecopartner/models/download_bill_response.py +23 -23
  20. byteplussdkecopartner/models/file_for_download_bill_output.py +175 -0
  21. byteplussdkecopartner/models/initiate_bill_generation_request.py +190 -0
  22. byteplussdkecopartner/models/initiate_bill_generation_response.py +253 -0
  23. byteplussdkecopartner/models/item_for_list_billing_items_output.py +461 -0
  24. byteplussdkecopartner/models/list_billing_items_request.py +240 -0
  25. byteplussdkecopartner/models/list_billing_items_response.py +253 -0
  26. byteplussdkecopartner/models/task_for_download_bill_output.py +409 -0
  27. byteplussdkecopartner/models/total_for_list_billing_items_output.py +305 -0
  28. byteplussdkredis/__init__.py +6 -4
  29. byteplussdkredis/api/redis_api.py +97 -97
  30. byteplussdkredis/models/__init__.py +6 -4
  31. byteplussdkredis/models/describe_planned_event_impact_detail_request.py +124 -0
  32. byteplussdkredis/models/describe_planned_event_impact_detail_response.py +123 -0
  33. byteplussdkredis/models/impact_for_describe_planned_event_impact_detail_output.py +149 -0
  34. byteplussdkredis/models/impact_item_for_describe_planned_event_impact_detail_output.py +201 -0
  35. byteplussdkredis/models/impact_summary_for_describe_planned_events_output.py +201 -0
  36. byteplussdkredis/models/involved_node_for_describe_planned_event_impact_detail_output.py +201 -0
  37. byteplussdkredis/models/planned_event_for_describe_planned_events_output.py +79 -1
  38. byteplussdkresourcecenter/__init__.py +16 -0
  39. byteplussdkresourcecenter/api/resourcecenter_api.py +485 -0
  40. byteplussdkresourcecenter/models/__init__.py +16 -0
  41. byteplussdkresourcecenter/models/create_query_request.py +11 -3
  42. byteplussdkresourcecenter/models/execute_multi_account_sql_query_request.py +211 -0
  43. byteplussdkresourcecenter/models/execute_multi_account_sql_query_response.py +149 -0
  44. byteplussdkresourcecenter/models/execute_sql_query_request.py +9 -0
  45. byteplussdkresourcecenter/models/execute_sql_query_response.py +29 -3
  46. byteplussdkresourcecenter/models/get_multi_account_resource_center_status_response.py +15 -15
  47. byteplussdkresourcecenter/models/get_multi_account_resource_description_request.py +204 -0
  48. byteplussdkresourcecenter/models/get_multi_account_resource_description_response.py +461 -0
  49. byteplussdkresourcecenter/models/get_resource_description_request.py +177 -0
  50. byteplussdkresourcecenter/models/get_resource_description_response.py +461 -0
  51. byteplussdkresourcecenter/models/list_multi_account_resource_relationships_request.py +262 -0
  52. byteplussdkresourcecenter/models/list_multi_account_resource_relationships_response.py +149 -0
  53. byteplussdkresourcecenter/models/list_resource_relationships_request.py +235 -0
  54. byteplussdkresourcecenter/models/list_resource_relationships_response.py +149 -0
  55. byteplussdkresourcecenter/models/related_type_name_for_list_resource_types_output.py +149 -0
  56. byteplussdkresourcecenter/models/resource_relationship_for_list_multi_account_resource_relationships_output.py +227 -0
  57. byteplussdkresourcecenter/models/resource_relationship_for_list_resource_relationships_output.py +227 -0
  58. byteplussdkresourcecenter/models/resource_type_for_list_resource_types_output.py +55 -3
  59. byteplussdkresourcecenter/models/scope_for_execute_multi_account_sql_query_input.py +175 -0
  60. byteplussdkresourcecenter/models/search_multi_account_resources_request.py +20 -0
  61. byteplussdkresourcecenter/models/search_resources_request.py +6 -0
  62. byteplussdkredis/models/create_enterprise_db_instance_response.py → byteplussdkresourcecenter/models/tag_for_get_multi_account_resource_description_output.py +35 -35
  63. byteplussdkredis/models/tag_for_create_enterprise_db_instance_input.py → byteplussdkresourcecenter/models/tag_for_get_resource_description_output.py +14 -14
  64. byteplussdkresourcecenter/models/update_query_request.py +9 -0
  65. byteplussdkvpc/__init__.py +17 -0
  66. byteplussdkvpc/api/vpc_api.py +582 -0
  67. byteplussdkvpc/models/__init__.py +17 -0
  68. byteplussdkvpc/models/authorize_security_group_egress_batch_request.py +150 -0
  69. byteplussdkvpc/models/authorize_security_group_egress_batch_response.py +149 -0
  70. byteplussdkvpc/models/authorize_security_group_ingress_batch_request.py +150 -0
  71. byteplussdkvpc/models/authorize_security_group_ingress_batch_response.py +149 -0
  72. byteplussdkvpc/models/create_flow_log_request.py +27 -1
  73. byteplussdkvpc/models/create_flow_log_response.py +29 -3
  74. byteplussdkvpc/models/create_ipam_pool_request.py +2 -5
  75. byteplussdkvpc/models/create_ipam_request.py +0 -3
  76. byteplussdkvpc/models/create_ipam_resource_discovery_request.py +9 -0
  77. byteplussdkvpc/models/create_ipam_scope_request.py +2 -5
  78. byteplussdkvpc/models/create_network_interface_request.py +81 -3
  79. byteplussdkvpc/models/describe_ipam_pools_request.py +6 -0
  80. byteplussdkvpc/models/describe_ipam_resource_cidrs_request.py +27 -1
  81. byteplussdkvpc/models/describe_ipam_resource_discoveries_request.py +6 -0
  82. byteplussdkvpc/models/describe_ipam_scopes_request.py +6 -0
  83. byteplussdkvpc/models/describe_ipams_request.py +2 -2
  84. byteplussdkvpc/models/describe_network_interface_attributes_response.py +79 -1
  85. byteplussdkvpc/models/ipam_resource_cidr_for_describe_ipam_resource_cidrs_output.py +53 -1
  86. byteplussdkvpc/models/modify_flow_log_attribute_request.py +27 -1
  87. byteplussdkvpc/models/modify_flow_log_attribute_response.py +29 -3
  88. byteplussdkvpc/models/modify_ipam_pool_request.py +2 -5
  89. byteplussdkvpc/models/modify_ipam_request.py +2 -5
  90. byteplussdkvpc/models/modify_ipam_resource_discovery_request.py +61 -6
  91. byteplussdkvpc/models/modify_ipam_resource_discovery_response.py +27 -1
  92. byteplussdkvpc/models/modify_ipam_scope_request.py +2 -5
  93. byteplussdkvpc/models/modify_network_interface_attributes_request.py +81 -3
  94. byteplussdkvpc/models/modify_security_group_egress_batch_request.py +150 -0
  95. byteplussdkvpc/models/modify_security_group_egress_batch_response.py +149 -0
  96. byteplussdkvpc/models/modify_security_group_ingress_batch_request.py +150 -0
  97. byteplussdkvpc/models/modify_security_group_ingress_batch_response.py +149 -0
  98. byteplussdkvpc/models/network_interface_set_for_describe_network_interfaces_output.py +79 -1
  99. byteplussdkvpc/models/overlap_detail_for_describe_ipam_resource_cidrs_output.py +175 -0
  100. byteplussdkvpc/models/permission_for_authorize_security_group_egress_batch_input.py +412 -0
  101. byteplussdkvpc/models/permission_for_authorize_security_group_ingress_batch_input.py +412 -0
  102. byteplussdkvpc/models/permission_for_describe_security_group_attributes_output.py +27 -1
  103. byteplussdkvpc/models/permission_for_modify_security_group_egress_batch_input.py +439 -0
  104. byteplussdkvpc/models/permission_for_modify_security_group_ingress_batch_input.py +439 -0
  105. byteplussdkvpc/models/revoke_security_group_egress_batch_request.py +150 -0
  106. byteplussdkvpc/models/revoke_security_group_egress_batch_response.py +149 -0
  107. byteplussdkvpc/models/revoke_security_group_ingress_batch_request.py +150 -0
  108. byteplussdkvpc/models/revoke_security_group_ingress_batch_response.py +149 -0
  109. byteplussdkredis/models/create_enterprise_db_instance_request.py +0 -625
  110. {byteplus_python_sdk_v2-3.0.61.dist-info → byteplus_python_sdk_v2-3.0.63.dist-info}/licenses/LICENSE.txt +0 -0
  111. {byteplus_python_sdk_v2-3.0.61.dist-info → byteplus_python_sdk_v2-3.0.63.dist-info}/licenses/NOTICE.md +0 -0
  112. {byteplus_python_sdk_v2-3.0.61.dist-info → byteplus_python_sdk_v2-3.0.63.dist-info}/top_level.txt +0 -0
@@ -2,8 +2,10 @@
2
2
 
3
3
  from __future__ import absolute_import
4
4
 
5
+ import copy
5
6
  import datetime
6
7
  import logging
8
+ import threading
7
9
  import time
8
10
  from multiprocessing.pool import ThreadPool
9
11
  from time import sleep
@@ -59,6 +61,8 @@ class ApiClient(object):
59
61
  if configuration is None:
60
62
  configuration = Configuration()
61
63
  self.configuration = configuration
64
+ self._credential_binding_lock = threading.Lock()
65
+ self.rebind_credential_provider()
62
66
  # Use the pool property to lazily initialize the ThreadPool.
63
67
  self._pool = None
64
68
  self._base_auto_retry = configuration.auto_retry
@@ -69,7 +73,7 @@ class ApiClient(object):
69
73
  self.default_headers[header_name] = header_value
70
74
  self.cookie = cookie
71
75
  # Set default User-Agent.
72
- self.user_agent = 'byteplus-python-sdk-v2/3.0.61'
76
+ self.user_agent = 'byteplus-python-sdk-v2/3.0.63'
73
77
  self.client_side_validation = configuration.client_side_validation
74
78
 
75
79
  self.interceptor_chain = InterceptorChain()
@@ -106,6 +110,24 @@ class ApiClient(object):
106
110
  def set_default_header(self, header_name, header_value):
107
111
  self.default_headers[header_name] = header_value
108
112
 
113
+ def rebind_credential_provider(self):
114
+ """Snapshot the current provider/proxy configuration with a fresh STS cache.
115
+
116
+ Call after changing configuration or provider settings. Existing requests
117
+ retain their binding; concurrent mutation of the source is unsupported.
118
+ Custom providers retain their identity and no-argument retrieval API.
119
+ """
120
+ from byteplussdkcore.auth.provider_binding import bind_credential_provider
121
+ with self._credential_binding_lock:
122
+ self._credential_provider = bind_credential_provider(
123
+ self.configuration.credential_provider, self.configuration)
124
+
125
+ def _create_request(self, *args, **kwargs):
126
+ provider = self._credential_provider
127
+ request = Request(self.configuration, *args, **kwargs)
128
+ request.credential_provider = provider
129
+ return request
130
+
109
131
  def __call_api(
110
132
  self, resource_path, method, path_params=None,
111
133
  query_params=None, header_params=None, body=None, post_params=None,
@@ -119,8 +141,7 @@ class ApiClient(object):
119
141
  if self.cookie:
120
142
  header_params['Cookie'] = self.cookie
121
143
 
122
- request = Request(
123
- self.configuration,
144
+ request = self._create_request(
124
145
  resource_path, method, path_params,
125
146
  query_params, header_params, body, post_params,
126
147
  files, response_type, auth_settings,
@@ -414,7 +435,8 @@ class ApiClient(object):
414
435
  host=None, scheme='https', region='cn-beijing',
415
436
  timeout=30, service='sts',
416
437
  max_retries=3, retry_interval=1,
417
- provider_name="ApiClient"):
438
+ provider_name="ApiClient",
439
+ proxy_url=None, ca_file=None, insecure_skip_verify=False):
418
440
  """Invoke an STS federation endpoint (AssumeRoleWithOIDC / AssumeRoleWithSAML / etc.)
419
441
  through the SDK's main REST stack while explicitly disabling signing.
420
442
 
@@ -444,10 +466,8 @@ class ApiClient(object):
444
466
  Returns the unwrapped `Result` dict from the STS response. Business
445
467
  errors bubble up as `rest.ApiException` (matching master behavior).
446
468
  """
447
- # Configuration() via the TypeWithDefault metaclass returns a shallow
448
- # copy of the user's default configuration, so TLS/proxy/timeout
449
- # settings propagate to the STS call.
450
- fresh = Configuration()
469
+ # Preserve the initiating provider's bind-time transport snapshot.
470
+ fresh = copy.copy(self.configuration)
451
471
  # Break recursion on three fronts:
452
472
  # 1. credential_provider=None so SignRequestInterceptor won't call
453
473
  # back into the provider via get_credentials().
@@ -472,6 +492,7 @@ class ApiClient(object):
472
492
  # Caller semantics: max_retries = TOTAL attempts (legacy from
473
493
  # _do_http_request's for-loop). Configuration semantics:
474
494
  # num_max_retries = retries AFTER the initial attempt. Convert.
495
+ fresh.auto_retry = True
475
496
  fresh.num_max_retries = max(max_retries - 1, 0)
476
497
  # retry_interval is seconds; Configuration uses ms.
477
498
  # Collapse the exponential-backoff range to a fixed delay.
@@ -480,6 +501,13 @@ class ApiClient(object):
480
501
  fresh.min_retry_delay_ms = delay_ms
481
502
  fresh.max_retry_delay_ms = delay_ms
482
503
 
504
+ # Proxy / TLS customization for reaching the STS endpoint. Only applied
505
+ # when the caller opted in (any of the three set); otherwise the fresh
506
+ # Configuration keeps its inherited proxy/TLS settings (including
507
+ # HTTP_PROXY / HTTPS_PROXY env-var fallback in RESTClientObject).
508
+ from byteplussdkcore.auth.sts_http_config import StsHttpConfig
509
+ StsHttpConfig(proxy_url, ca_file, insecure_skip_verify).apply_to_configuration(fresh)
510
+
483
511
  # NOTE: NEW ApiClient(fresh), not self -- avoids re-entering caller's provider chain.
484
512
  client = ApiClient(fresh)
485
513
  # BuildRequestInterceptor parses resource_path by index:
@@ -0,0 +1,42 @@
1
+ """Client-local bindings for the concrete built-in STS providers."""
2
+ import copy
3
+ import threading
4
+
5
+ from six.moves.urllib.parse import urlparse
6
+
7
+
8
+ def new_sts_configuration(provider):
9
+ from byteplussdkcore.configuration import Configuration
10
+
11
+ snapshot = getattr(provider, '_sts_base_configuration', None)
12
+ configuration = copy.copy(snapshot) if snapshot is not None else Configuration()
13
+ configuration.credential_provider = None
14
+ return configuration
15
+
16
+
17
+ def bind_credential_provider(provider, configuration):
18
+ from .providers.sts_provider import StsCredentialProvider
19
+ from .providers.sts_oidc_provider import StsOidcCredentialProvider
20
+ from .providers.sts_saml_provider import StsSamlCredentialProvider
21
+
22
+ # Unknown subclasses can own resources or custom copy behavior.
23
+ if type(provider) not in (
24
+ StsCredentialProvider, StsOidcCredentialProvider, StsSamlCredentialProvider):
25
+ return provider
26
+
27
+ with provider._lock:
28
+ bound = copy.copy(provider)
29
+ bound.policy = copy.deepcopy(provider.policy)
30
+ bound.credentials = None
31
+ bound.expired_time = None
32
+ bound._lock = threading.Lock()
33
+ bound._sts_base_configuration = new_sts_configuration(provider)
34
+ # Endpoint resolution accepts a scheme embedded in host.
35
+ scheme = urlparse(bound.host).scheme if bound.host and '://' in bound.host else bound.scheme
36
+ bound.scheme = scheme
37
+ fallback = configuration.proxy
38
+ if not fallback and scheme in ('http', 'https'):
39
+ fallback = getattr(configuration, scheme + '_proxy')
40
+ # Do not turn environment proxy settings into explicit overrides.
41
+ bound._proxy_fallback = fallback or None
42
+ return bound
@@ -27,7 +27,8 @@ class StsOidcCredentialProvider(Provider):
27
27
  host='sts.ap-southeast-1.byteplusapi.com', region='ap-southeast-1', timeout=30,
28
28
  expired_buffer_seconds=60, policy=None,
29
29
  role_trn=None, oidc_token_file=None, session_name=None,
30
- max_retries=3, retry_interval=1):
30
+ max_retries=3, retry_interval=1,
31
+ proxy_url=None, ca_file=None, insecure_skip_verify=False):
31
32
 
32
33
  self._legacy_mode = oidc_token is not None
33
34
 
@@ -78,6 +79,13 @@ class StsOidcCredentialProvider(Provider):
78
79
  self.region = region
79
80
  self.scheme = scheme
80
81
 
82
+ # Proxy / TLS customization for reaching the STS endpoint. All optional;
83
+ # empty by default so RESTClientObject keeps its normal behavior
84
+ # (including HTTP_PROXY / HTTPS_PROXY env-var fallback).
85
+ self.proxy_url = proxy_url or None
86
+ self.ca_file = ca_file or None
87
+ self.insecure_skip_verify = bool(insecure_skip_verify)
88
+
81
89
  if expired_buffer_seconds > 600:
82
90
  raise ValueError('expired_buffer_seconds must be less than or equal to 600')
83
91
  self.expired_buffer_seconds = expired_buffer_seconds
@@ -157,8 +165,17 @@ class StsOidcCredentialProvider(Provider):
157
165
 
158
166
  # Late imports to avoid circular deps (auth.providers is imported
159
167
  # indirectly by byteplussdkcore/__init__.py).
160
- from byteplussdkcore import ApiClient, Configuration
161
- resp_result = ApiClient(Configuration())._sts_call(
168
+ from byteplussdkcore import ApiClient
169
+ from byteplussdkcore.auth.provider_binding import new_sts_configuration
170
+ from byteplussdkcore.auth.sts_http_config import StsHttpConfig
171
+ configuration = new_sts_configuration(self)
172
+ configuration.scheme = self.scheme
173
+ # Apply overrides before ApiClient constructs its REST transport.
174
+ StsHttpConfig(
175
+ self.proxy_url or getattr(self, '_proxy_fallback', None),
176
+ self.ca_file, self.insecure_skip_verify
177
+ ).apply_to_configuration(configuration)
178
+ resp_result = ApiClient(configuration)._sts_call(
162
179
  action='AssumeRoleWithOIDC',
163
180
  version='2018-01-01',
164
181
  params=params,
@@ -169,6 +186,9 @@ class StsOidcCredentialProvider(Provider):
169
186
  max_retries=self.max_retries,
170
187
  retry_interval=self.retry_interval,
171
188
  provider_name=self.PROVIDER_NAME,
189
+ proxy_url=self.proxy_url or getattr(self, '_proxy_fallback', None),
190
+ ca_file=self.ca_file,
191
+ insecure_skip_verify=self.insecure_skip_verify,
172
192
  )
173
193
  if 'Credentials' not in resp_result:
174
194
  raise RuntimeError(
@@ -5,7 +5,7 @@ from datetime import datetime
5
5
 
6
6
  import dateutil.parser
7
7
 
8
- from byteplussdkcore import UniversalApi, UniversalInfo, ApiClient, Configuration
8
+ from byteplussdkcore import UniversalApi, UniversalInfo, ApiClient
9
9
  from .provider import Provider, CredentialValue
10
10
 
11
11
 
@@ -20,7 +20,8 @@ class AssumeRoleCredentials:
20
20
 
21
21
  class StsCredentialProvider(Provider):
22
22
  def __init__(self, ak, sk, role_name, account_id, duration_seconds=3600, scheme='https',
23
- host='sts.ap-southeast-1.byteplusapi.com', region='ap-southeast-1', timeout=30, expired_buffer_seconds=60, policy=None, max_retries=3, retry_interval=1):
23
+ host='sts.ap-southeast-1.byteplusapi.com', region='ap-southeast-1', timeout=30, expired_buffer_seconds=60, policy=None, max_retries=3, retry_interval=1,
24
+ proxy_url=None, ca_file=None, insecure_skip_verify=False):
24
25
  self.ak = ak
25
26
  self.sk = sk
26
27
  self.role_name = role_name
@@ -36,6 +37,13 @@ class StsCredentialProvider(Provider):
36
37
  self.scheme = scheme
37
38
  self.policy = policy
38
39
 
40
+ # Proxy / TLS customization for reaching the STS endpoint. All optional;
41
+ # empty by default so RESTClientObject keeps its normal behavior
42
+ # (including HTTP_PROXY / HTTPS_PROXY env-var fallback).
43
+ self.proxy_url = proxy_url or None
44
+ self.ca_file = ca_file or None
45
+ self.insecure_skip_verify = bool(insecure_skip_verify)
46
+
39
47
  self.expired_time = None
40
48
  if expired_buffer_seconds > 600:
41
49
  raise ValueError('expired_buffer_seconds must be less than or equal to 600')
@@ -69,18 +77,39 @@ class StsCredentialProvider(Provider):
69
77
  }
70
78
  if self.policy is not None:
71
79
  params['Policy'] = self.policy
72
- configuration = type.__call__(Configuration)
80
+ # Bound clients retain the default STS transport settings from binding.
81
+ # Direct provider use still inherits the current default configuration.
82
+ from byteplussdkcore.auth.provider_binding import new_sts_configuration
83
+ configuration = new_sts_configuration(self)
84
+ # Break recursion: this AssumeRole call signs with the explicit ak/sk
85
+ # below, so it must NOT re-enter a credential provider (which could be
86
+ # this very provider via the inherited default configuration).
87
+ configuration.credential_provider = None
73
88
  configuration.ak = self.ak
74
89
  configuration.sk = self.sk
90
+ configuration.session_token = ""
75
91
  configuration.host = self.host
76
92
  configuration.region = self.region
77
93
  configuration.scheme = self.scheme
78
94
  configuration.read_timeout = self.timeout
79
95
 
96
+ # Provider max_retries controls total attempts independently of business retry.
97
+ configuration.auto_retry = True
80
98
  configuration.num_max_retries = max(self.max_retries - 1, 0)
81
99
  delay_ms = int(self.retry_interval * 1000)
82
100
  configuration.min_retry_delay_ms = delay_ms
83
101
  configuration.max_retry_delay_ms = delay_ms
102
+
103
+ # Proxy / TLS customization for reaching the STS endpoint. Only applied
104
+ # when the caller opted in; otherwise the configuration keeps its
105
+ # default proxy/TLS settings (including HTTP_PROXY / HTTPS_PROXY
106
+ # env-var fallback in RESTClientObject).
107
+ from byteplussdkcore.auth.sts_http_config import StsHttpConfig
108
+ StsHttpConfig(
109
+ self.proxy_url or getattr(self, '_proxy_fallback', None),
110
+ self.ca_file, self.insecure_skip_verify
111
+ ).apply_to_configuration(configuration)
112
+
84
113
  c = UniversalApi(ApiClient(configuration))
85
114
  info = UniversalInfo(method='GET', service='sts', version='2018-01-01', action='AssumeRole',
86
115
  content_type='text/plain')
@@ -24,7 +24,8 @@ class StsSamlCredentialProvider(Provider):
24
24
  def __init__(self, role_name=None, account_id=None, provider_name=None, saml_resp=None,
25
25
  duration_seconds=3600, scheme='https',
26
26
  host='sts.ap-southeast-1.byteplusapi.com', region='ap-southeast-1', timeout=30, expired_buffer_seconds=60,
27
- policy=None, role_trn=None, saml_provider_trn=None, max_retries=3, retry_interval=1):
27
+ policy=None, role_trn=None, saml_provider_trn=None, max_retries=3, retry_interval=1,
28
+ proxy_url=None, ca_file=None, insecure_skip_verify=False):
28
29
  self.role_name = role_name
29
30
  self.account_id = account_id
30
31
  self.provider_name = provider_name
@@ -58,6 +59,13 @@ class StsSamlCredentialProvider(Provider):
58
59
  self.scheme = scheme
59
60
  self.policy = policy
60
61
 
62
+ # Proxy / TLS customization for reaching the STS endpoint. All optional;
63
+ # empty by default so RESTClientObject keeps its normal behavior
64
+ # (including HTTP_PROXY / HTTPS_PROXY env-var fallback).
65
+ self.proxy_url = proxy_url or None
66
+ self.ca_file = ca_file or None
67
+ self.insecure_skip_verify = bool(insecure_skip_verify)
68
+
61
69
  self.expired_time = None
62
70
  if expired_buffer_seconds > 600:
63
71
  raise ValueError('expired_buffer_seconds must be less than or equal to 600')
@@ -117,8 +125,17 @@ class StsSamlCredentialProvider(Provider):
117
125
  }
118
126
  if self.policy is not None:
119
127
  params['Policy'] = self.policy
120
- from byteplussdkcore import ApiClient, Configuration
121
- resp_result = ApiClient(Configuration())._sts_call(
128
+ from byteplussdkcore import ApiClient
129
+ from byteplussdkcore.auth.provider_binding import new_sts_configuration
130
+ from byteplussdkcore.auth.sts_http_config import StsHttpConfig
131
+ configuration = new_sts_configuration(self)
132
+ configuration.scheme = self.scheme
133
+ # Apply overrides before ApiClient constructs its REST transport.
134
+ StsHttpConfig(
135
+ self.proxy_url or getattr(self, '_proxy_fallback', None),
136
+ self.ca_file, self.insecure_skip_verify
137
+ ).apply_to_configuration(configuration)
138
+ resp_result = ApiClient(configuration)._sts_call(
122
139
  action='AssumeRoleWithSAML',
123
140
  version='2018-01-01',
124
141
  params=params,
@@ -129,6 +146,9 @@ class StsSamlCredentialProvider(Provider):
129
146
  max_retries=self.max_retries,
130
147
  retry_interval=self.retry_interval,
131
148
  provider_name=self.PROVIDER_NAME,
149
+ proxy_url=self.proxy_url or getattr(self, '_proxy_fallback', None),
150
+ ca_file=self.ca_file,
151
+ insecure_skip_verify=self.insecure_skip_verify,
132
152
  )
133
153
  if 'Credentials' not in resp_result:
134
154
  raise RuntimeError(
@@ -0,0 +1,133 @@
1
+ # coding: utf-8
2
+ """Proxy / TLS customization shared by the STS credential providers.
3
+
4
+ This mirrors the Go SDK's ``ProxyConfig`` (see ``byteplus/credentials/
5
+ http_client.go``). It bundles the three public knobs used when reaching the
6
+ STS endpoint and knows how to project them onto an SDK ``Configuration``:
7
+
8
+ proxy_url -> configuration.proxy
9
+ ca_file -> configuration.ssl_ca_cert
10
+ insecure_skip_verify -> configuration.verify_ssl (inverted)
11
+
12
+ Unlike the Go SDK -- which builds a dedicated ``*http.Transport`` -- the
13
+ Python SDK already routes every request (including STS federation calls)
14
+ through ``RESTClientObject``, which reads these ``Configuration`` fields
15
+ directly. So the only thing this helper needs to do is set the fields.
16
+
17
+ An explicit provider ``proxy_url`` wins over its client-local fallback.
18
+ When both are empty, the transport retains default configuration and
19
+ ``HTTP_PROXY`` / ``HTTPS_PROXY`` lookup; it does not implement ``NO_PROXY``.
20
+
21
+ TLS priority also matches Go's ``tls.Config``: ``insecure_skip_verify``
22
+ takes precedence over ``ca_file`` (when verification is skipped the custom
23
+ CA is irrelevant).
24
+ """
25
+
26
+ from __future__ import absolute_import
27
+
28
+ import base64
29
+
30
+ import six
31
+ from six.moves.urllib.parse import unquote, urlparse
32
+
33
+
34
+ class StsHttpConfig(object):
35
+ """Carries proxy / TLS options for a single STS request path.
36
+
37
+ :param proxy_url: Forward proxy address, ``scheme://[user:password@]host:port``.
38
+ Empty preserves default configuration and environment lookup.
39
+ :param ca_file: Path to a custom CA bundle (PEM) used to verify the STS
40
+ server certificate. Restores verification unless skipped.
41
+ Empty inherits ssl_ca_cert, otherwise REST uses certifi.
42
+ :param insecure_skip_verify: When True, skip TLS certificate/hostname
43
+ verification. For debugging only; never use in production.
44
+ """
45
+
46
+ def __init__(self, proxy_url=None, ca_file=None, insecure_skip_verify=False):
47
+ self.proxy_url = proxy_url or None
48
+ self.ca_file = ca_file or None
49
+ self.insecure_skip_verify = bool(insecure_skip_verify)
50
+
51
+ def is_empty(self):
52
+ """True when no proxy/TLS option is configured.
53
+
54
+ Callers use this to leave the underlying ``Configuration`` untouched,
55
+ so existing behavior (including BYTEPLUS env-var proxies) is
56
+ preserved when the user did not opt in. Mirrors Go's ``IsZero``.
57
+ """
58
+ return (not self.proxy_url) and (not self.ca_file) and (not self.insecure_skip_verify)
59
+
60
+ def apply_to_configuration(self, configuration):
61
+ """Project the configured options onto ``configuration`` in place.
62
+
63
+ No-op when :meth:`is_empty` is True.
64
+ """
65
+ if self.is_empty():
66
+ return configuration
67
+
68
+ if self.proxy_url:
69
+ # Highest-priority proxy source; RESTClientObject honors this over
70
+ # http_proxy / https_proxy / env vars.
71
+ configuration.proxy = self.proxy_url
72
+
73
+ # TLS: insecure_skip_verify wins over ca_file (same as Go's tls.Config,
74
+ # where RootCAs is ignored once InsecureSkipVerify is set).
75
+ if self.insecure_skip_verify:
76
+ configuration.verify_ssl = False
77
+ configuration.ssl_ca_cert = None
78
+ elif self.ca_file:
79
+ configuration.verify_ssl = True
80
+ configuration.ssl_ca_cert = self.ca_file
81
+
82
+ return configuration
83
+
84
+ def proxy_authorization_header(self):
85
+ """Return the ``Proxy-Authorization`` header value, or None.
86
+
87
+ Delegates to :func:`build_proxy_authorization_header` using this
88
+ config's ``proxy_url``.
89
+ """
90
+ return build_proxy_authorization_header(self.proxy_url)
91
+
92
+
93
+ def build_proxy_authorization_header(proxy_url):
94
+ """Build a ``Basic`` ``Proxy-Authorization`` value from an embedded userinfo.
95
+
96
+ urllib3 (v2) does NOT automatically forward the ``user:password@`` embedded
97
+ in a proxy URL as a ``Proxy-Authorization`` header, whereas Go's
98
+ ``http.ProxyURL`` / ``http.ProxyFromEnvironment`` do. To keep behavior
99
+ aligned with the Go SDK, callers extract this header explicitly and pass it
100
+ to ``ProxyManager(proxy_headers=...)``.
101
+
102
+ Returns None when ``proxy_url`` is empty or carries no userinfo. Raises
103
+ ``ValueError`` when ``proxy_url`` cannot be parsed.
104
+ """
105
+ if not proxy_url:
106
+ return None
107
+
108
+ try:
109
+ parsed = urlparse(proxy_url)
110
+ except (ValueError, AttributeError) as e:
111
+ raise ValueError("invalid proxy url {0!r}: {1}".format(proxy_url, e))
112
+
113
+ username = parsed.username
114
+ if username is None:
115
+ return None
116
+ password = parsed.password or ""
117
+
118
+ # Go's http.Transport derives proxy Basic auth from url.Userinfo, whose
119
+ # Username()/Password() return the PERCENT-DECODED values. urlparse keeps
120
+ # userinfo raw, so decode here to stay byte-for-byte identical with the Go
121
+ # SDK (e.g. a "p%40ss" password must be sent as "p@ss").
122
+ # Python 2 unquote accepts UTF-8 bytes; Python 3 accepts text.
123
+ if six.PY2:
124
+ username = username.encode("utf-8") if isinstance(username, six.text_type) else username
125
+ password = password.encode("utf-8") if isinstance(password, six.text_type) else password
126
+ username = unquote(username)
127
+ password = unquote(password)
128
+ if isinstance(username, six.text_type):
129
+ username = username.encode("utf-8")
130
+ if isinstance(password, six.text_type):
131
+ password = password.encode("utf-8")
132
+ # urllib3.make_headers uses Latin-1, which cannot encode UTF-8 userinfo.
133
+ return "Basic " + base64.b64encode(username + b":" + password).decode("ascii")
@@ -302,7 +302,7 @@ class Configuration(six.with_metaclass(TypeWithDefault, object)):
302
302
  "OS: {env}\n" \
303
303
  "Python Version: {pyversion}\n" \
304
304
  "Version of the API: 0.1.0\n" \
305
- "SDK Package Version: 3.0.61".\
305
+ "SDK Package Version: 3.0.63".\
306
306
  format(env=sys.platform, pyversion=sys.version)
307
307
 
308
308
  @property
@@ -6,9 +6,8 @@ This module provides utilities for generating authentication tokens for RDS MySQ
6
6
  """
7
7
 
8
8
  from byteplussdkcore.endpoint.providers.standard_provider import StandardEndpointResolver
9
- from byteplussdkcore.interceptor import InterceptorChain, InterceptorContext, SignRequestInterceptor, \
9
+ from byteplussdkcore.interceptor import InterceptorChain, InterceptorContext, \
10
10
  ResolveEndpointInterceptor
11
- from byteplussdkcore.interceptor import Request
12
11
 
13
12
  DEFAULT_SERVICE = 'rds_mysql'
14
13
  DEFAULT_API_VERSION = '2022-01-01'
@@ -58,11 +57,10 @@ def build_auth_token(api_client, db_user, instance_id, expires=None):
58
57
  }
59
58
 
60
59
  # Create Request with presign mode
61
- request = Request(configuration,
62
- resource_path='/{}/{}/{}/get/text_plain/'.format(DEFAULT_API, DEFAULT_API_VERSION,
63
- DEFAULT_SERVICE),
64
- method='GET',
65
- query_params=query)
60
+ request = api_client._create_request(
61
+ resource_path='/{}/{}/{}/get/text_plain/'.format(
62
+ DEFAULT_API, DEFAULT_API_VERSION, DEFAULT_SERVICE),
63
+ method='GET', query_params=query)
66
64
  request.endpoint_provider = StandardEndpointResolver()
67
65
  request.service = DEFAULT_SERVICE
68
66
  request.is_presign = True
@@ -82,7 +80,7 @@ def build_auth_token(api_client, db_user, instance_id, expires=None):
82
80
 
83
81
  # Step 3: Sign request (host is None, won't be included in signature)
84
82
  sign_chain = InterceptorChain()
85
- sign_chain.append_request_interceptor(SignRequestInterceptor())
83
+ sign_chain.append_request_interceptor(api_client.sign_request_interceptor)
86
84
  context = sign_chain.execute_request(context)
87
85
 
88
86
  return context.request.signed_query
@@ -57,6 +57,10 @@ class Request(object):
57
57
  self.session_token = configuration.session_token
58
58
  self.region = configuration.region
59
59
  self.scheme = configuration.scheme
60
+ # Business proxy snapshot; credential routing belongs to ApiClient's binding.
61
+ self.proxy = configuration.proxy
62
+ self.http_proxy = configuration.http_proxy
63
+ self.https_proxy = configuration.https_proxy
60
64
  self.endpoint_provider = configuration.endpoint_provider
61
65
  self.custom_bootstrap_region = configuration.custom_bootstrap_region
62
66
  self.use_dual_stack = configuration.use_dual_stack
@@ -64,6 +68,7 @@ class Request(object):
64
68
  # ApiClient injects its private base retryer before interception.
65
69
  self.auto_retry = configuration.auto_retry
66
70
  self.retryer = None
71
+ # ApiClient replaces this with its persistent binding before signing.
67
72
  self.credential_provider = configuration.credential_provider
68
73
  self.invocation_id = str(uuid.uuid4())
69
74
  self.retry_count = 0
byteplussdkcore/rest.py CHANGED
@@ -147,6 +147,11 @@ class RESTClientObject(object):
147
147
  )
148
148
 
149
149
  if proxy_url:
150
+ # urllib3 (v2) does not forward the ``user:password@`` embedded in
151
+ # the proxy URL as a Proxy-Authorization header, unlike Go's
152
+ # http.ProxyURL. Extract it explicitly so proxies requiring Basic
153
+ # auth work the same way across SDKs.
154
+ proxy_headers = self.__proxy_authorization_headers(proxy_url)
150
155
  self.pool_manager = urllib3.ProxyManager(
151
156
  num_pools=pools_size,
152
157
  maxsize=maxsize,
@@ -155,6 +160,7 @@ class RESTClientObject(object):
155
160
  cert_file=configuration.cert_file,
156
161
  key_file=configuration.key_file,
157
162
  proxy_url=proxy_url,
163
+ proxy_headers=proxy_headers,
158
164
  timeout=timeout,
159
165
  retries=Retry(total=False),
160
166
  **addition_pool_args
@@ -191,6 +197,27 @@ class RESTClientObject(object):
191
197
  proxy_url = os.getenv('https_proxy')
192
198
  return proxy_url
193
199
 
200
+ @staticmethod
201
+ def __proxy_authorization_headers(proxy_url):
202
+ """Build proxy_headers carrying Proxy-Authorization, or None.
203
+
204
+ Returns a dict ``{'Proxy-Authorization': 'Basic ...'}`` when the proxy
205
+ URL embeds a ``user:password@`` userinfo, otherwise None (so urllib3
206
+ keeps its default empty proxy headers). Never raises: a malformed proxy
207
+ URL simply yields no auth header and lets the connection attempt (and
208
+ its clearer downstream error) proceed.
209
+ """
210
+ try:
211
+ from byteplussdkcore.auth.sts_http_config import (
212
+ build_proxy_authorization_header,
213
+ )
214
+ value = build_proxy_authorization_header(proxy_url)
215
+ except Exception:
216
+ return None
217
+ if not value:
218
+ return None
219
+ return {"Proxy-Authorization": value}
220
+
194
221
  def request(self, method, url, query_params=None, headers=None,
195
222
  body=None, post_params=None, _preload_content=True,
196
223
  _request_timeout=None):
@@ -1,10 +1,13 @@
1
+ import errno
1
2
  import json
2
3
  import logging
3
4
  import socket
5
+ import ssl
4
6
  import traceback
5
7
  from abc import abstractmethod
6
8
 
7
9
  import urllib3
10
+ from six.moves.http_client import BadStatusLine
8
11
 
9
12
  from byteplussdkcore.observability.debugger import sdk_core_logger
10
13
  from byteplussdkcore.rest import ApiException, RESTResponse
@@ -73,7 +76,7 @@ class DefaultRetryCondition(RetryCondition):
73
76
  Returns:
74
77
  bool: True if the request should be retried, False otherwise.
75
78
  """
76
- if err is not None and isinstance(err, self.__retry_exceptions):
79
+ if err is not None and self._is_retryable_exception(err):
77
80
  sdk_core_logger.debug_retry("retry for retryable exception, err: %s", err)
78
81
  return True
79
82
 
@@ -105,6 +108,31 @@ class DefaultRetryCondition(RetryCondition):
105
108
  sdk_core_logger.debug_retry("no need to retry")
106
109
  return False
107
110
 
111
+ @classmethod
112
+ def _is_retryable_exception(cls, err):
113
+ # Retry the underlying connection failure, not every proxy failure.
114
+ # In particular, a CONNECT 407 or a TLS/configuration error must stop.
115
+ seen = set()
116
+ while isinstance(err, (urllib3.exceptions.ProxyError, urllib3.exceptions.MaxRetryError)):
117
+ if id(err) in seen:
118
+ return False
119
+ seen.add(id(err))
120
+ if isinstance(err, urllib3.exceptions.ProxyError):
121
+ err = err.original_error
122
+ else:
123
+ err = err.reason
124
+ if isinstance(err, (ssl.SSLError, urllib3.exceptions.SSLError)):
125
+ return False
126
+ if isinstance(err, cls.__retry_exceptions):
127
+ return True
128
+ # RemoteDisconnected on Python 3, empty BadStatusLine on Python 2.
129
+ if isinstance(err, BadStatusLine) and err.line in ("", "''"):
130
+ return True
131
+ return isinstance(err, socket.error) and err.errno in (
132
+ errno.ECONNRESET, errno.ECONNREFUSED, errno.ECONNABORTED,
133
+ errno.EPIPE, errno.ETIMEDOUT, errno.ENETUNREACH, errno.EHOSTUNREACH,
134
+ )
135
+
108
136
  @staticmethod
109
137
  def __json_loads(data):
110
138
  """
@@ -26,13 +26,23 @@ from byteplussdkecopartner.models.create_invitation_link_response import CreateI
26
26
  from byteplussdkecopartner.models.create_unique_invitation_link_request import CreateUniqueInvitationLinkRequest
27
27
  from byteplussdkecopartner.models.create_unique_invitation_link_response import CreateUniqueInvitationLinkResponse
28
28
  from byteplussdkecopartner.models.customer_for_get_customer_details_by_type_output import CustomerForGetCustomerDetailsByTypeOutput
29
+ from byteplussdkecopartner.models.download_bill_request import DownloadBillRequest
30
+ from byteplussdkecopartner.models.download_bill_response import DownloadBillResponse
31
+ from byteplussdkecopartner.models.file_for_download_bill_output import FileForDownloadBillOutput
29
32
  from byteplussdkecopartner.models.get_customer_details_by_type_request import GetCustomerDetailsByTypeRequest
30
33
  from byteplussdkecopartner.models.get_customer_details_by_type_response import GetCustomerDetailsByTypeResponse
31
34
  from byteplussdkecopartner.models.get_customer_details_by_uid_request import GetCustomerDetailsByUIDRequest
32
35
  from byteplussdkecopartner.models.get_customer_details_by_uid_response import GetCustomerDetailsByUIDResponse
33
36
  from byteplussdkecopartner.models.get_quota_information_request import GetQuotaInformationRequest
34
37
  from byteplussdkecopartner.models.get_quota_information_response import GetQuotaInformationResponse
38
+ from byteplussdkecopartner.models.initiate_bill_generation_request import InitiateBillGenerationRequest
39
+ from byteplussdkecopartner.models.initiate_bill_generation_response import InitiateBillGenerationResponse
40
+ from byteplussdkecopartner.models.item_for_list_billing_items_output import ItemForListBillingItemsOutput
41
+ from byteplussdkecopartner.models.list_billing_items_request import ListBillingItemsRequest
42
+ from byteplussdkecopartner.models.list_billing_items_response import ListBillingItemsResponse
35
43
  from byteplussdkecopartner.models.modify_quota_request import ModifyQuotaRequest
36
44
  from byteplussdkecopartner.models.modify_quota_response import ModifyQuotaResponse
37
45
  from byteplussdkecopartner.models.settle_quota_payment_request import SettleQuotaPaymentRequest
38
46
  from byteplussdkecopartner.models.settle_quota_payment_response import SettleQuotaPaymentResponse
47
+ from byteplussdkecopartner.models.task_for_download_bill_output import TaskForDownloadBillOutput
48
+ from byteplussdkecopartner.models.total_for_list_billing_items_output import TotalForListBillingItemsOutput