diff --git a/vmware_nsxlib/tests/unit/v3/test_cluster.py b/vmware_nsxlib/tests/unit/v3/test_cluster.py index a5049e41..22b27b1a 100644 --- a/vmware_nsxlib/tests/unit/v3/test_cluster.py +++ b/vmware_nsxlib/tests/unit/v3/test_cluster.py @@ -199,7 +199,8 @@ class RequestsHTTPProviderTestCase(unittest.TestCase): provider.validate_connection(mock_cluster, mock_ep, mock_conn) mock_get.assert_not_called() - def _validate_con_mocks(self, nsx_version): + def _validate_con_mocks(self, nsx_version, + keepalive_section='transport-zones'): nsxlib_config = nsxlib_testcase.get_default_nsxlib_config() nsxlib = v3.NsxLib(nsxlib_config) nsxlib.nsx_version = nsx_version @@ -209,7 +210,7 @@ class RequestsHTTPProviderTestCase(unittest.TestCase): mock_ep.provider.url = 'https://1.2.3.4' conf = mock.Mock() conf.url_base = 'abc' - conf.keepalive_section = 'transport-zones' + conf.keepalive_section = keepalive_section conf.validate_connection_method = nsxlib.validate_connection_method mock_cluster = mock.Mock() mock_cluster.nsxlib_config = conf diff --git a/vmware_nsxlib/v3/client.py b/vmware_nsxlib/v3/client.py index 15f23d9e..22c3024e 100644 --- a/vmware_nsxlib/v3/client.py +++ b/vmware_nsxlib/v3/client.py @@ -284,6 +284,12 @@ class NSX3Client(JSONRESTClient): NSX_V1_API_PREFIX = 'api/v1/' NSX_POLICY_V1_API_PREFIX = 'policy/api/v1/' + # NOTE: For user-facing client, NsxClusteredAPI instance + # will be passed as connection parameter below, thus all + # requests on this client will pass via cluster code to + # determine endpoint + # For validation client, TimeoutSession with specific + # endpoint parameters will be passed as connection. def __init__(self, connection, url_prefix=None, default_headers=None, nsx_api_managers=None, diff --git a/vmware_nsxlib/v3/cluster.py b/vmware_nsxlib/v3/cluster.py index 65077a60..4b143258 100644 --- a/vmware_nsxlib/v3/cluster.py +++ b/vmware_nsxlib/v3/cluster.py @@ -185,8 +185,8 @@ class NSXRequestsHTTPProvider(AbstractHTTPProvider): return "%s-%s" % (requests.__title__, requests.__version__) def validate_connection(self, cluster_api, endpoint, conn): - # We don't need to retry with different endpoint during validation, - # thus limit max_attempts to 1 + # Retry during validation can cause retry storm, thus limit + # max_attempts to 1 # on connection level, validation will be retried according to # nsxlib 'retries' and 'http_timeout' parameters. client = nsx_client.NSX3Client( @@ -195,12 +195,9 @@ class NSXRequestsHTTPProvider(AbstractHTTPProvider): default_headers=conn.default_headers, max_attempts=1) - validation_done = False - # Check the manager state directly if cluster_api.nsxlib_config.validate_connection_method: cluster_api.nsxlib_config.validate_connection_method( client, endpoint.provider.url) - validation_done = True # If keeplive section returns a list, it is assumed to be non-empty keepalive_section = cluster_api.nsxlib_config.keepalive_section @@ -210,7 +207,6 @@ class NSXRequestsHTTPProvider(AbstractHTTPProvider): result = client.get(keepalive_section, silent=True, with_retries=False) - validation_done = True if not result or result.get('result_count', 1) <= 0: msg = _("No %(section)s found " "for '%(url)s'") % {'section': keepalive_section, @@ -219,8 +215,6 @@ class NSXRequestsHTTPProvider(AbstractHTTPProvider): raise exceptions.ResourceNotFound( manager=endpoint.provider.url, operation=msg) - return validation_done - def new_connection(self, cluster_api, provider): config = cluster_api.nsxlib_config session = TimeoutSession(config.http_timeout, @@ -586,14 +580,10 @@ class ClusteredAPI(object): try: with endpoint.pool.item() as conn: # with some configurations, validation will be skipped - result = self._http_provider.validate_connection(self, - endpoint, - conn) - if result or endpoint.state == EndpointState.INITIALIZED: - # If no endpoint validation is configured, we assume - # endpoint is UP on startup, but we shouldn't move it - # to UP from DOWN state - endpoint.set_state(EndpointState.UP) + self._http_provider.validate_connection(self, + endpoint, + conn) + endpoint.set_state(EndpointState.UP) except exceptions.ClientCertificateNotTrusted: LOG.warning("Failed to validate API cluster endpoint " "'%(ep)s' due to untrusted client certificate", diff --git a/vmware_nsxlib/v3/policy/__init__.py b/vmware_nsxlib/v3/policy/__init__.py index df275a89..85db4ff0 100644 --- a/vmware_nsxlib/v3/policy/__init__.py +++ b/vmware_nsxlib/v3/policy/__init__.py @@ -138,8 +138,19 @@ class NsxPolicyLib(lib.NsxLibBase): @property def validate_connection_method(self): - # TODO(asarfaty): Find an equivalent api to check policy status - pass + """Return a method that will validate the NSX policy status""" + + def check_policy_status(client, url): + # Try to get the status silently and with no retries + infra = client.get('infra', + silent=True, with_retries=False) + if not infra or not infra.get('id'): + msg = _("Policy health check failed") + LOG.warning(msg) + raise exceptions.ResourceNotFound( + manager=url, operation=msg) + + return check_policy_status def get_version(self): """Get the NSX Policy manager version