Skip to content

Commit 4cad7ec

Browse files
committed
Merge branch 'fix/pysdk-poll-url-rewrite' into '5.5.12'
<fix>[testlib]: rewrite async poll URL to use client-configured hostname See merge request zstackio/zstack!9526
2 parents 73ca9d8 + 17a0ec8 commit 4cad7ec

1 file changed

Lines changed: 34 additions & 9 deletions

File tree

testlib/src/main/resources/zssdk.py

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
import hmac
1919
from hashlib import sha1
2020
import datetime
21-
import time
2221

2322
try:
2423
int_types = (int, long)
@@ -58,7 +57,7 @@ def _exception_safe(func):
5857
def wrap(*args, **kwargs):
5958
try:
6059
func(*args, **kwargs)
61-
except:
60+
except Exception:
6261
print(traceback.format_exc())
6362

6463
return wrap
@@ -80,6 +79,7 @@ def _http_error(status, body=None):
8079
def _error(code, desc, details):
8180
err = ErrorCode()
8281
err.code = code
82+
err.description = desc
8383
err.desc = desc
8484
err.details = details
8585
return {'error': err}
@@ -181,7 +181,7 @@ def _check_params(self):
181181
if value is not None and isinstance(value, str) and annotation.max_length and len(value) > annotation.max_length:
182182
raise SdkError('invalid length[%s] of the parameter[%s], the max allowed length is %s' % (len(value), param_name, annotation.max_length))
183183

184-
if value is not None and isinstance(value, str) and annotation.min_length and len(value) > annotation.min_length:
184+
if value is not None and isinstance(value, str) and annotation.min_length and len(value) < annotation.min_length:
185185
raise SdkError('invalid length[%s] of the parameter[%s], the minimal allowed length is %s' % (len(value), param_name, annotation.min_length))
186186

187187
if value is not None and isinstance(value, list) and annotation.non_empty is True and len(value) == 0:
@@ -235,11 +235,11 @@ def _url(self):
235235
elements.append('/v1')
236236

237237
path = self.PATH.replace('{', '${')
238-
unresolved = re.findall('${(.+?)}', path)
238+
unresolved = re.findall(r'\$\{(.+?)\}', path)
239239
params = self._params()
240240
if unresolved:
241241
for u in unresolved:
242-
if u in params:
242+
if u not in params:
243243
raise SdkError('missing a mandatory parameter[%s]' % u)
244244

245245
path = string.Template(path).substitute(params)
@@ -362,7 +362,21 @@ def _poll_result(self, rsp, cb):
362362
m = json.loads(rsp.data)
363363
location = m[LOCATION]
364364
if not location:
365-
raise SdkError("Internal Error] the api[%s] is an async API but the server doesn't return the polling location url")
365+
raise SdkError("[Internal Error] the api[%s] is an async API but the server doesn't return the polling location url" % self.PATH)
366+
367+
# Rewrite poll URL to use client-configured hostname:port,
368+
# in case server returns an internal IP unreachable from client
369+
try:
370+
from urllib.parse import urlparse, urlunparse
371+
except ImportError:
372+
from urlparse import urlparse, urlunparse
373+
parsed = urlparse(location)
374+
configured_host = __config__[CONFIG_HOSTNAME]
375+
configured_port = str(__config__[CONFIG_PORT])
376+
if ':' in configured_host and not configured_host.startswith('['):
377+
configured_host = '[%s]' % configured_host
378+
location = urlunparse(parsed._replace(
379+
netloc='%s:%s' % (configured_host, configured_port)))
366380

367381
if cb:
368382
# async polling
@@ -480,11 +494,13 @@ def _uuid():
480494
def _json_http(
481495
uri,
482496
body=None,
483-
headers={},
497+
headers=None,
484498
method='POST',
485499
timeout=120.0
486500
):
487501
pool = urllib3.PoolManager(timeout=timeout, retries=urllib3.util.retry.Retry(15))
502+
if headers is None:
503+
headers = {}
488504
headers.update({'Content-Type': 'application/json', 'Connection': 'close'})
489505

490506
if body is not None and not isinstance(body, str):
@@ -497,6 +513,15 @@ def _json_http(
497513
else:
498514
rsp = pool.request(method, uri, headers=headers)
499515

500-
print('[Response to %s %s]: status: %s, body: %s' % (method, uri, rsp.status, rsp.data))
501-
return rsp
516+
data = rsp.data
517+
if isinstance(data, bytes):
518+
data = data.decode('utf-8')
519+
print('[Response to %s %s]: status: %s, body: %s' % (method, uri, rsp.status, data))
520+
521+
class _Rsp(object):
522+
pass
523+
r = _Rsp()
524+
r.status = rsp.status
525+
r.data = data
526+
return r
502527

0 commit comments

Comments
 (0)