Fix the logical port created twice
Logical port creation is a POST request. Sometimes it will trigger
ConnectionResetError which is a IOError. request_with_retry_on_ssl_error
will retry it.
If request has parameter retry_confirm, exception will be raised so ncp
could query if port has been created to avoid creating port twice.
Change-Id: Ic97b39c7a3736f02a79ab891970c1ad67b123156
(cherry picked from commit ac224a85a8
)
This commit is contained in:
parent
ef2bb68076
commit
1a3cda9f40
@ -2613,7 +2613,7 @@ class TestPolicyEnforcementPoint(NsxPolicyLibTestCase):
|
||||
tenant=TEST_TENANT)
|
||||
api_post.assert_called_once_with(
|
||||
expected_def.get_resource_path() + '?action=reload',
|
||||
None, expected_results=None, headers=None)
|
||||
None, expected_results=None, headers=None, retry_confirm=False)
|
||||
|
||||
|
||||
class TestPolicyDeploymentMap(NsxPolicyLibTestCase):
|
||||
|
@ -22,6 +22,7 @@ from oslo_serialization import jsonutils
|
||||
import requests
|
||||
|
||||
from vmware_nsxlib._i18n import _
|
||||
from vmware_nsxlib.v3 import constants
|
||||
from vmware_nsxlib.v3 import exceptions
|
||||
from vmware_nsxlib.v3 import utils
|
||||
|
||||
@ -173,9 +174,10 @@ class RESTClient(object):
|
||||
expected_results=expected_results)
|
||||
|
||||
def create(self, resource='', body=None, headers=None,
|
||||
expected_results=None):
|
||||
expected_results=None, retry_confirm=False):
|
||||
return self.url_post(resource, body, headers=headers,
|
||||
expected_results=expected_results)
|
||||
expected_results=expected_results,
|
||||
retry_confirm=retry_confirm)
|
||||
|
||||
def patch(self, resource='', body=None, headers=None):
|
||||
return self.url_patch(resource, body, headers=headers)
|
||||
@ -205,9 +207,11 @@ class RESTClient(object):
|
||||
return self._rest_call(url, method='PUT', body=body, headers=headers,
|
||||
expected_results=expected_results)
|
||||
|
||||
def url_post(self, url, body, headers=None, expected_results=None):
|
||||
def url_post(self, url, body, headers=None, expected_results=None,
|
||||
retry_confirm=False):
|
||||
return self._rest_call(url, method='POST', body=body, headers=headers,
|
||||
expected_results=expected_results)
|
||||
expected_results=expected_results,
|
||||
retry_confirm=retry_confirm)
|
||||
|
||||
def url_patch(self, url, body, headers=None):
|
||||
return self._rest_call(url, method='PATCH', body=body, headers=headers)
|
||||
@ -268,6 +272,7 @@ class RESTClient(object):
|
||||
silent=False, expected_results=None, **kwargs):
|
||||
request_headers = headers.copy() if headers else {}
|
||||
request_headers.update(self._default_headers)
|
||||
retry_confirm = kwargs.pop(constants.API_RETRY_CONFIRM, False)
|
||||
|
||||
if utils.INJECT_HEADERS_CALLBACK:
|
||||
inject_headers = utils.INJECT_HEADERS_CALLBACK()
|
||||
@ -281,7 +286,8 @@ class RESTClient(object):
|
||||
result = do_request(
|
||||
request_url,
|
||||
data=body,
|
||||
headers=request_headers)
|
||||
headers=request_headers,
|
||||
retry_confirm=retry_confirm)
|
||||
te = time.time()
|
||||
if silent:
|
||||
self._conn.set_silent(False)
|
||||
|
@ -104,15 +104,23 @@ class TimeoutSession(requests.Session):
|
||||
# wrapper timeouts at the session level
|
||||
# see: https://goo.gl/xNk7aM
|
||||
def request(self, *args, **kwargs):
|
||||
retry_confirm = kwargs.pop(constants.API_RETRY_CONFIRM, False)
|
||||
|
||||
def request_with_retry_on_ssl_error(*args, **kwargs):
|
||||
try:
|
||||
return super(TimeoutSession, self).request(*args, **kwargs)
|
||||
except (IOError, OpenSSL.SSL.Error):
|
||||
except (IOError, OpenSSL.SSL.Error) as err:
|
||||
# This can happen when connection tries to access certificate
|
||||
# file it was opened with (renegotiation?)
|
||||
# Proper way to solve this would be to pass in-memory cert
|
||||
# to ssl C code.
|
||||
# Retrying here works around the problem
|
||||
|
||||
# IOError covered too much Exception, if resources created
|
||||
# successfully on nsxt side but ConnectResetError happened,
|
||||
# Retrying here will create resource twice
|
||||
if isinstance(err, IOError) and retry_confirm:
|
||||
raise exceptions.RetryConfirm(msg=err)
|
||||
return super(TimeoutSession, self).request(*args, **kwargs)
|
||||
|
||||
def get_cert_provider():
|
||||
|
@ -127,3 +127,6 @@ API_DEFAULT_MAX_RATE = 100
|
||||
# API Call Log Related const
|
||||
API_CALL_LOG_PER_CLUSTER = 'API_LOG_PER_CLUSTER'
|
||||
API_CALL_LOG_PER_ENDPOINT = 'API_LOG_PER_ENDPOINT'
|
||||
|
||||
# API Retry confirm parameter
|
||||
API_RETRY_CONFIRM = 'retry_confirm'
|
||||
|
@ -238,6 +238,10 @@ class CannotConnectToServer(ManagerError):
|
||||
message = _("Cannot connect to server")
|
||||
|
||||
|
||||
class RetryConfirm(NsxLibException):
|
||||
message = _("Retry will be handled by upper layer: %(msg)s")
|
||||
|
||||
|
||||
class ResourceInUse(ManagerError):
|
||||
message = _("The object cannot be deleted as either it has children or it "
|
||||
"is being referenced by other objects")
|
||||
|
@ -164,7 +164,7 @@ class LogicalPort(utils.NsxLibApiBase):
|
||||
switch_profile_ids=None, vif_type=None, app_id=None,
|
||||
allocate_addresses=nsx_constants.ALLOCATE_ADDRESS_NONE,
|
||||
description=None, tn_uuid=None,
|
||||
extra_configs=None):
|
||||
extra_configs=None, retry_confirm=False):
|
||||
tags = tags or []
|
||||
body = {'logical_switch_id': lswitch_id}
|
||||
# NOTE(arosen): If parent_vif_id is specified we need to use
|
||||
@ -181,7 +181,8 @@ class LogicalPort(utils.NsxLibApiBase):
|
||||
attachment=attachment,
|
||||
description=description,
|
||||
extra_configs=extra_configs))
|
||||
return self.client.create(self.get_path(), body=body)
|
||||
return self.client.create(self.get_path(), body=body,
|
||||
retry_confirm=retry_confirm)
|
||||
|
||||
def delete(self, lport_id):
|
||||
self._delete_with_retry('%s?detach=true' % lport_id)
|
||||
|
Loading…
Reference in New Issue
Block a user