diff --git a/vmware_nsxlib/tests/unit/v3/nsxlib_testcase.py b/vmware_nsxlib/tests/unit/v3/nsxlib_testcase.py index 76f4a828..171500ca 100644 --- a/vmware_nsxlib/tests/unit/v3/nsxlib_testcase.py +++ b/vmware_nsxlib/tests/unit/v3/nsxlib_testcase.py @@ -20,6 +20,7 @@ import mock from oslo_serialization import jsonutils from oslo_utils import uuidutils from requests import exceptions as requests_exceptions +from requests import models from vmware_nsxlib import v3 from vmware_nsxlib.v3 import client as nsx_client @@ -47,6 +48,8 @@ PLUGIN_VER = "plugin ver" DNS_NAMESERVERS = ['1.1.1.1'] DNS_DOMAIN = 'openstacklocal' +JSESSIONID = 'my_sess_id' + def _mock_nsxlib(): def _return_id_key(*args, **kwargs): @@ -316,8 +319,28 @@ class NsxClientTestCase(NsxLibTestCase): assert conn is not None def mock_nsx_clustered_api(self, session_response=None, **kwargs): - return NsxClientTestCase.MockNSXClusteredAPI( - session_response=session_response, **kwargs) + orig_request = nsx_cluster.TimeoutSession.request + + def mocked_request(*args, **kwargs): + if args[2].endswith('api/session/create'): + response = models.Response() + response.status_code = 200 + response.headers = { + 'Set-Cookie': 'JSESSIONID=%s;junk' % JSESSIONID} + return response + return orig_request(*args, **kwargs) + + with mock.patch.object(nsx_cluster.TimeoutSession, 'request', + new=mocked_request): + cluster = NsxClientTestCase.MockNSXClusteredAPI( + session_response=session_response, **kwargs) + return cluster + + @staticmethod + def default_headers(): + return {'Content-Type': 'application/json', + 'Accept': 'application/json', + 'Cookie': 'JSESSIONID=%s;' % JSESSIONID} def mocked_resource(self, resource_class, mock_validate=True, session_response=None): @@ -368,12 +391,14 @@ class NsxClientTestCase(NsxLibTestCase): return nsx_cluster.NSXClusteredAPI(nsxlib_config) def assert_json_call(self, method, client, url, - headers=nsx_client.JSONRESTClient._DEFAULT_HEADERS, + headers=None, timeout=(NSX_HTTP_TIMEOUT, NSX_HTTP_READ_TIMEOUT), data=None): cluster = client._conn if data: data = jsonutils.dumps(data, sort_keys=True) + if not headers: + headers = self.default_headers() cluster.assert_called_once( method, **{'url': url, 'verify': NSX_CERT, 'body': data, diff --git a/vmware_nsxlib/tests/unit/v3/test_client.py b/vmware_nsxlib/tests/unit/v3/test_client.py index 9c35c0f7..84227805 100644 --- a/vmware_nsxlib/tests/unit/v3/test_client.py +++ b/vmware_nsxlib/tests/unit/v3/test_client.py @@ -30,7 +30,14 @@ LOG = log.getLogger(__name__) CLIENT_PKG = 'vmware_nsxlib.v3.client' DFT_ACCEPT_HEADERS = { - 'Accept': '*/*' + 'Accept': '*/*', + 'Cookie': 'JSESSIONID=%s;' % nsxlib_testcase.JSESSIONID +} + +JSON_DFT_ACCEPT_HEADERS = { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Cookie': 'JSESSIONID=%s;' % nsxlib_testcase.JSESSIONID } @@ -65,7 +72,7 @@ def assert_call(verb, client_or_resource, def assert_json_call(verb, client_or_resource, url, verify=nsxlib_testcase.NSX_CERT, data=None, - headers=client.JSONRESTClient._DEFAULT_HEADERS, + headers=JSON_DFT_ACCEPT_HEADERS, single_call=True): return assert_call(verb, client_or_resource, url, verify=verify, data=data, diff --git a/vmware_nsxlib/tests/unit/v3/test_cluster.py b/vmware_nsxlib/tests/unit/v3/test_cluster.py index 342180a4..b60c0be0 100644 --- a/vmware_nsxlib/tests/unit/v3/test_cluster.py +++ b/vmware_nsxlib/tests/unit/v3/test_cluster.py @@ -18,6 +18,7 @@ import unittest import mock from oslo_serialization import jsonutils from requests import exceptions as requests_exceptions +from requests import models import six.moves.urllib.parse as urlparse from vmware_nsxlib.tests.unit.v3 import mocks @@ -36,6 +37,13 @@ def _validate_conn_down(*args, **kwargs): raise requests_exceptions.ConnectionError() +def get_sess_create_resp(): + sess_create_response = models.Response() + sess_create_response.status_code = 200 + sess_create_response.headers = {'Set-Cookie': 'JSESSIONID=abc;'} + return sess_create_response + + class RequestsHTTPProviderTestCase(unittest.TestCase): def test_new_connection(self): @@ -50,15 +58,18 @@ class RequestsHTTPProviderTestCase(unittest.TestCase): mock_api.nsxlib_config.conn_idle_timeout = 39 mock_api.nsxlib_config.client_cert_provider = None provider = cluster.NSXRequestsHTTPProvider() - session = provider.new_connection( - mock_api, cluster.Provider('9.8.7.6', 'https://9.8.7.6', - 'nsxuser', 'nsxpassword', None)) + with mock.patch.object(cluster.TimeoutSession, 'request', + return_value=get_sess_create_resp()): + session = provider.new_connection( + mock_api, cluster.Provider('9.8.7.6', 'https://9.8.7.6', + 'nsxuser', 'nsxpassword', None)) - self.assertEqual(('nsxuser', 'nsxpassword'), session.auth) - self.assertFalse(session.verify) - self.assertIsNone(session.cert) - self.assertEqual(100, session.adapters['https://'].max_retries.total) - self.assertEqual(99, session.timeout) + self.assertEqual(('nsxuser', 'nsxpassword'), session.auth) + self.assertFalse(session.verify) + self.assertIsNone(session.cert) + self.assertEqual(100, + session.adapters['https://'].max_retries.total) + self.assertEqual(99, session.timeout) def test_new_connection_with_client_auth(self): mock_api = mock.Mock() @@ -72,14 +83,16 @@ class RequestsHTTPProviderTestCase(unittest.TestCase): '/etc/cert.pem') mock_api.nsxlib_config.client_cert_provider = cert_provider_inst provider = cluster.NSXRequestsHTTPProvider() - session = provider.new_connection( - mock_api, cluster.Provider('9.8.7.6', 'https://9.8.7.6', - None, None, None)) + with mock.patch.object(cluster.TimeoutSession, 'request', + return_value=get_sess_create_resp()): + session = provider.new_connection( + mock_api, cluster.Provider('9.8.7.6', 'https://9.8.7.6', + None, None, None)) - self.assertIsNone(session.auth) - self.assertFalse(session.verify) - self.assertEqual(cert_provider_inst, session.cert_provider) - self.assertEqual(99, session.timeout) + self.assertIsNone(session.auth) + self.assertFalse(session.verify) + self.assertEqual(cert_provider_inst, session.cert_provider) + self.assertEqual(99, session.timeout) def test_validate_connection(self): self.skipTest("Revist") @@ -231,6 +244,8 @@ class ClusteredAPITestCase(nsxlib_testcase.NsxClientTestCase): self.assertEqual(_get_schedule(4), [eps[0], eps[2], eps[0], eps[2]]) def test_reinitialize_cluster(self): - api = self.mock_nsx_clustered_api() - # just make sure this api is defined, and does not crash - api._reinit_cluster() + with mock.patch.object(cluster.TimeoutSession, 'request', + return_value=get_sess_create_resp()): + api = self.mock_nsx_clustered_api() + # just make sure this api is defined, and does not crash + api._reinit_cluster() diff --git a/vmware_nsxlib/tests/unit/v3/test_resources.py b/vmware_nsxlib/tests/unit/v3/test_resources.py index 42dd0244..f991b71e 100644 --- a/vmware_nsxlib/tests/unit/v3/test_resources.py +++ b/vmware_nsxlib/tests/unit/v3/test_resources.py @@ -53,7 +53,8 @@ class TestSwitchingProfileTestCase(nsxlib_testcase.NsxClientTestCase): 'resource_type': profile_types.PORT_MIRRORING, 'display_name': 'pm-profile', 'description': 'port mirror prof' - }, sort_keys=True)) + }, sort_keys=True), + headers=self.default_headers()) def test_switching_profile_update(self): @@ -79,7 +80,8 @@ class TestSwitchingProfileTestCase(nsxlib_testcase.NsxClientTestCase): data=jsonutils.dumps({ 'resource_type': profile_types.PORT_MIRRORING, 'tags': tags - }, sort_keys=True)) + }, sort_keys=True), + headers=self.default_headers()) def test_spoofgaurd_profile_create(self): @@ -109,7 +111,8 @@ class TestSwitchingProfileTestCase(nsxlib_testcase.NsxClientTestCase): 'description': 'spoofguard-for-plugin', 'white_list_providers': ['LPORT_BINDINGS'], 'tags': tags - }, sort_keys=True)) + }, sort_keys=True), + headers=self.default_headers()) def test_create_dhcp_profile(self): @@ -154,7 +157,8 @@ class TestSwitchingProfileTestCase(nsxlib_testcase.NsxClientTestCase): 'tx_multicast': 0 }, 'block_non_ip_traffic': True - }, sort_keys=True)) + }, sort_keys=True), + headers=self.default_headers()) def test_create_mac_learning_profile(self): @@ -187,7 +191,8 @@ class TestSwitchingProfileTestCase(nsxlib_testcase.NsxClientTestCase): 'description': 'mac-learning-for-plugin', 'tags': tags, 'mac_change_allowed': True, - }, sort_keys=True)) + }, sort_keys=True), + headers=self.default_headers()) def test_find_by_display_name(self): resp_resources = { @@ -230,7 +235,8 @@ class TestSwitchingProfileTestCase(nsxlib_testcase.NsxClientTestCase): 'get', mocked_resource, 'https://1.2.3.4/api/v1/switching-profiles/' '?include_system_owned=True', - data=None) + data=None, + headers=self.default_headers()) class LogicalPortTestCase(nsxlib_testcase.NsxClientTestCase): @@ -300,7 +306,8 @@ class LogicalPortTestCase(nsxlib_testcase.NsxClientTestCase): test_client.assert_json_call( 'post', mocked_resource, 'https://1.2.3.4/api/v1/logical-ports', - data=jsonutils.dumps(resp_body, sort_keys=True)) + data=jsonutils.dumps(resp_body, sort_keys=True), + headers=self.default_headers()) def test_create_logical_port_with_attachtype_cif(self): """Test creating a port returns the correct response and 200 status @@ -353,7 +360,8 @@ class LogicalPortTestCase(nsxlib_testcase.NsxClientTestCase): test_client.assert_json_call( 'post', mocked_resource, 'https://1.2.3.4/api/v1/logical-ports', - data=jsonutils.dumps(resp_body, sort_keys=True)) + data=jsonutils.dumps(resp_body, sort_keys=True), + headers=self.default_headers()) def test_create_logical_port_admin_down(self): """Test creating port with admin_state down.""" @@ -379,7 +387,8 @@ class LogicalPortTestCase(nsxlib_testcase.NsxClientTestCase): mocked_resource.delete(uuid) test_client.assert_json_call( 'delete', mocked_resource, - 'https://1.2.3.4/api/v1/logical-ports/%s?detach=true' % uuid) + 'https://1.2.3.4/api/v1/logical-ports/%s?detach=true' % uuid, + headers=self.default_headers()) def test_get_logical_port_by_attachment(self): """Test deleting port.""" @@ -390,7 +399,8 @@ class LogicalPortTestCase(nsxlib_testcase.NsxClientTestCase): test_client.assert_json_call( 'get', mocked_resource, "https://1.2.3.4/api/v1/logical-ports/?attachment_type=%s" - "&attachment_id=%s" % (attachment_type, attachment_id)) + "&attachment_id=%s" % (attachment_type, attachment_id), + headers=self.default_headers()) def test_clear_port_bindings(self): fake_port = copy.copy(test_constants.FAKE_PORT) @@ -408,7 +418,8 @@ class LogicalPortTestCase(nsxlib_testcase.NsxClientTestCase): test_client.assert_json_call( 'put', mocked_resource, 'https://1.2.3.4/api/v1/logical-ports/%s' % fake_port['id'], - data=jsonutils.dumps(fake_port, sort_keys=True)) + data=jsonutils.dumps(fake_port, sort_keys=True), + headers=self.default_headers()) def test_create_logical_port_fail(self): """Test the failure of port creation.""" @@ -464,7 +475,8 @@ class LogicalRouterTestCase(nsxlib_testcase.NsxClientTestCase): test_client.assert_json_call( 'post', router, 'https://1.2.3.4/api/v1/logical-routers', - data=jsonutils.dumps(data, sort_keys=True)) + data=jsonutils.dumps(data, sort_keys=True), + headers=self.default_headers()) def test_delete_logical_router(self): """Test deleting router""" @@ -473,7 +485,8 @@ class LogicalRouterTestCase(nsxlib_testcase.NsxClientTestCase): router.delete(uuid) test_client.assert_json_call( 'delete', router, - 'https://1.2.3.4/api/v1/logical-routers/%s' % uuid) + 'https://1.2.3.4/api/v1/logical-routers/%s' % uuid, + headers=self.default_headers()) def test_force_delete_logical_router(self): """Test force deleting router""" @@ -482,7 +495,8 @@ class LogicalRouterTestCase(nsxlib_testcase.NsxClientTestCase): router.delete(uuid, True) test_client.assert_json_call( 'delete', router, - 'https://1.2.3.4/api/v1/logical-routers/%s?force=True' % uuid) + 'https://1.2.3.4/api/v1/logical-routers/%s?force=True' % uuid, + headers=self.default_headers()) def test_list_logical_router(self): router = self._mocked_lrouter() @@ -536,7 +550,8 @@ class LogicalRouterTestCase(nsxlib_testcase.NsxClientTestCase): 'post', router, ('https://1.2.3.4/api/v1/logical-routers/%s/nat/rules' % test_constants.FAKE_ROUTER_UUID), - data=jsonutils.dumps(data, sort_keys=True)) + data=jsonutils.dumps(data, sort_keys=True), + headers=self.default_headers()) def test_nat_rule_create_v1(self): # Ignoring 'bypass_firewall' with version 1.1 @@ -552,7 +567,8 @@ class LogicalRouterTestCase(nsxlib_testcase.NsxClientTestCase): test_client.assert_json_call( 'get', router, ('https://1.2.3.4/api/v1/logical-routers/%s/nat/rules' % - test_constants.FAKE_ROUTER_UUID)) + test_constants.FAKE_ROUTER_UUID), + headers=self.default_headers()) def test_nat_rule_update(self): router = self._mocked_lrouter() @@ -566,7 +582,8 @@ class LogicalRouterTestCase(nsxlib_testcase.NsxClientTestCase): 'put', router, ('https://1.2.3.4/api/v1/logical-routers/%s/nat/rules/%s' % (test_constants.FAKE_ROUTER_UUID, rule_id)), - data=jsonutils.dumps(data, sort_keys=True)) + data=jsonutils.dumps(data, sort_keys=True), + headers=self.default_headers()) def test_delete_nat_rule_by_gw(self): router = self._mocked_lrouter() @@ -585,7 +602,8 @@ class LogicalRouterTestCase(nsxlib_testcase.NsxClientTestCase): test_client.assert_json_call( 'delete', router, ('https://1.2.3.4/api/v1/logical-routers/%s/nat/rules/%s' % - (test_constants.FAKE_ROUTER_UUID, rule_id))) + (test_constants.FAKE_ROUTER_UUID, rule_id)), + headers=self.default_headers()) def test_delete_nat_rule_by_gw_and_source(self): router = self._mocked_lrouter() @@ -607,7 +625,8 @@ class LogicalRouterTestCase(nsxlib_testcase.NsxClientTestCase): test_client.assert_json_call( 'delete', router, ('https://1.2.3.4/api/v1/logical-routers/%s/nat/rules/%s' % - (test_constants.FAKE_ROUTER_UUID, rule_id))) + (test_constants.FAKE_ROUTER_UUID, rule_id)), + headers=self.default_headers()) class LogicalRouterPortTestCase(nsxlib_testcase.NsxClientTestCase): @@ -647,7 +666,8 @@ class LogicalRouterPortTestCase(nsxlib_testcase.NsxClientTestCase): test_client.assert_json_call( 'post', lrport, 'https://1.2.3.4/api/v1/logical-router-ports', - data=jsonutils.dumps(data, sort_keys=True)) + data=jsonutils.dumps(data, sort_keys=True), + headers=self.default_headers()) def test_logical_router_port_max_attempts(self): """Test a router port api has the configured retries.""" @@ -664,7 +684,8 @@ class LogicalRouterPortTestCase(nsxlib_testcase.NsxClientTestCase): lrport.delete(uuid) test_client.assert_json_call( 'delete', lrport, - 'https://1.2.3.4/api/v1/logical-router-ports/%s' % uuid) + 'https://1.2.3.4/api/v1/logical-router-ports/%s' % uuid, + headers=self.default_headers()) def test_update_logical_router_port(self): fake_router_port = test_constants.FAKE_ROUTER_PORT.copy() @@ -690,7 +711,8 @@ class LogicalRouterPortTestCase(nsxlib_testcase.NsxClientTestCase): test_client.assert_json_call( 'put', lrport, 'https://1.2.3.4/api/v1/logical-router-ports/%s' % uuid, - data=jsonutils.dumps(data, sort_keys=True)) + data=jsonutils.dumps(data, sort_keys=True), + headers=self.default_headers()) def test_get_logical_router_port_by_router_id(self): """Test getting a router port by router id.""" @@ -707,7 +729,8 @@ class LogicalRouterPortTestCase(nsxlib_testcase.NsxClientTestCase): test_client.assert_json_call( 'get', lrport, 'https://1.2.3.4/api/v1/logical-router-ports/?' - 'logical_router_id=%s' % router_id) + 'logical_router_id=%s' % router_id, + headers=self.default_headers()) def test_get_logical_router_port_by_switch_id(self): """Test getting a router port by switch id.""" @@ -726,7 +749,8 @@ class LogicalRouterPortTestCase(nsxlib_testcase.NsxClientTestCase): test_client.assert_json_call( 'get', lrport, 'https://1.2.3.4/api/v1/logical-router-ports/?' - 'logical_switch_id=%s' % switch_id) + 'logical_switch_id=%s' % switch_id, + headers=self.default_headers()) class IpPoolTestCase(nsxlib_testcase.NsxClientTestCase): @@ -769,7 +793,8 @@ class IpPoolTestCase(nsxlib_testcase.NsxClientTestCase): test_client.assert_json_call( 'post', pool, 'https://1.2.3.4/api/v1/pools/ip-pools', - data=jsonutils.dumps(data, sort_keys=True)) + data=jsonutils.dumps(data, sort_keys=True), + headers=self.default_headers()) def test_create_ip_pool_minimal_args(self): pool = self._mocked_pool() @@ -789,7 +814,8 @@ class IpPoolTestCase(nsxlib_testcase.NsxClientTestCase): test_client.assert_json_call( 'post', pool, 'https://1.2.3.4/api/v1/pools/ip-pools', - data=jsonutils.dumps(data, sort_keys=True)) + data=jsonutils.dumps(data, sort_keys=True), + headers=self.default_headers()) def test_create_ip_pool_no_ranges_with_gateway(self): pool = self._mocked_pool() @@ -810,7 +836,8 @@ class IpPoolTestCase(nsxlib_testcase.NsxClientTestCase): test_client.assert_json_call( 'post', pool, 'https://1.2.3.4/api/v1/pools/ip-pools', - data=jsonutils.dumps(data, sort_keys=True)) + data=jsonutils.dumps(data, sort_keys=True), + headers=self.default_headers()) def test_create_ip_pool_no_ranges_no_gateway(self): pool = self._mocked_pool() @@ -828,7 +855,8 @@ class IpPoolTestCase(nsxlib_testcase.NsxClientTestCase): test_client.assert_json_call( 'post', pool, 'https://1.2.3.4/api/v1/pools/ip-pools', - data=jsonutils.dumps(data, sort_keys=True)) + data=jsonutils.dumps(data, sort_keys=True), + headers=self.default_headers()) def test_create_ip_pool_no_cidr(self): pool = self._mocked_pool() @@ -860,7 +888,8 @@ class IpPoolTestCase(nsxlib_testcase.NsxClientTestCase): test_client.assert_json_call( 'put', pool, 'https://1.2.3.4/api/v1/pools/ip-pools/%s' % uuid, - data=jsonutils.dumps(fake_ip_pool, sort_keys=True)) + data=jsonutils.dumps(fake_ip_pool, sort_keys=True), + headers=self.default_headers()) def test_update_ip_pool_gateway(self): fake_ip_pool = test_constants.FAKE_IP_POOL.copy() @@ -876,7 +905,8 @@ class IpPoolTestCase(nsxlib_testcase.NsxClientTestCase): test_client.assert_json_call( 'put', pool, 'https://1.2.3.4/api/v1/pools/ip-pools/%s' % uuid, - data=jsonutils.dumps(fake_ip_pool, sort_keys=True)) + data=jsonutils.dumps(fake_ip_pool, sort_keys=True), + headers=self.default_headers()) def test_update_ip_pool_delete_gateway(self): fake_ip_pool = test_constants.FAKE_IP_POOL.copy() @@ -891,7 +921,8 @@ class IpPoolTestCase(nsxlib_testcase.NsxClientTestCase): test_client.assert_json_call( 'put', pool, 'https://1.2.3.4/api/v1/pools/ip-pools/%s' % uuid, - data=jsonutils.dumps(fake_ip_pool, sort_keys=True)) + data=jsonutils.dumps(fake_ip_pool, sort_keys=True), + headers=self.default_headers()) def test_get_ip_pool(self): """Test getting a router port by router id""" @@ -907,7 +938,8 @@ class IpPoolTestCase(nsxlib_testcase.NsxClientTestCase): self.assertEqual(fake_ip_pool, result) test_client.assert_json_call( 'get', pool, - 'https://1.2.3.4/api/v1/pools/ip-pools/%s' % uuid) + 'https://1.2.3.4/api/v1/pools/ip-pools/%s' % uuid, + headers=self.default_headers()) def test_delete_ip_pool(self): """Test deleting router port""" @@ -917,7 +949,8 @@ class IpPoolTestCase(nsxlib_testcase.NsxClientTestCase): pool.delete(uuid) test_client.assert_json_call( 'delete', pool, - 'https://1.2.3.4/api/v1/pools/ip-pools/%s' % uuid) + 'https://1.2.3.4/api/v1/pools/ip-pools/%s' % uuid, + headers=self.default_headers()) def test_allocate_ip_from_pool(self): pool = self._mocked_pool() @@ -930,7 +963,8 @@ class IpPoolTestCase(nsxlib_testcase.NsxClientTestCase): test_client.assert_json_call( 'post', pool, 'https://1.2.3.4/api/v1/pools/ip-pools/%s?action=ALLOCATE' % uuid, - data=jsonutils.dumps(data, sort_keys=True)) + data=jsonutils.dumps(data, sort_keys=True), + headers=self.default_headers()) def test_release_ip_to_pool(self): pool = self._mocked_pool() @@ -943,7 +977,8 @@ class IpPoolTestCase(nsxlib_testcase.NsxClientTestCase): test_client.assert_json_call( 'post', pool, 'https://1.2.3.4/api/v1/pools/ip-pools/%s?action=RELEASE' % uuid, - data=jsonutils.dumps(data, sort_keys=True)) + data=jsonutils.dumps(data, sort_keys=True), + headers=self.default_headers()) def test_get_ip_pool_allocations(self): """Test getting a router port by router id""" @@ -959,7 +994,8 @@ class IpPoolTestCase(nsxlib_testcase.NsxClientTestCase): self.assertEqual(fake_ip_pool, result) test_client.assert_json_call( 'get', pool, - 'https://1.2.3.4/api/v1/pools/ip-pools/%s/allocations' % uuid) + 'https://1.2.3.4/api/v1/pools/ip-pools/%s/allocations' % uuid, + headers=self.default_headers()) class TestNsxSearch(nsxlib_testcase.NsxClientTestCase): diff --git a/vmware_nsxlib/v3/cluster.py b/vmware_nsxlib/v3/cluster.py index 6de60c69..595543d1 100644 --- a/vmware_nsxlib/v3/cluster.py +++ b/vmware_nsxlib/v3/cluster.py @@ -19,6 +19,7 @@ import copy import datetime import itertools import logging +import re import eventlet from eventlet import greenpool @@ -105,8 +106,8 @@ class TimeoutSession(requests.Session): def request(self, *args, **kwargs): if 'timeout' not in kwargs: kwargs['timeout'] = (self.timeout, self.read_timeout) - - if not self._cert_provider: + skip_cert = kwargs.pop('skip_cert', False) + if not self._cert_provider or skip_cert: return super(TimeoutSession, self).request(*args, **kwargs) if self.cert is not None: @@ -145,6 +146,12 @@ class NSXRequestsHTTPProvider(AbstractHTTPProvider): using requests.Session() as the underlying connection. """ + SESSION_CREATE_URL = '/api/session/create' + COOKIE_FIELD = 'Cookie' + SET_COOKIE_FIELD = 'Set-Cookie' + XSRF_TOKEN = 'X-XSRF-TOKEN' + JSESSIONID = 'JSESSIONID' + @property def provider_id(self): return "%s-%s" % (requests.__title__, requests.__version__) @@ -152,7 +159,8 @@ class NSXRequestsHTTPProvider(AbstractHTTPProvider): def validate_connection(self, cluster_api, endpoint, conn): client = nsx_client.NSX3Client( conn, url_prefix=endpoint.provider.url, - url_path_base=cluster_api.nsxlib_config.url_base) + url_path_base=cluster_api.nsxlib_config.url_base, + default_headers=conn.default_headers) keepalive_section = cluster_api.nsxlib_config.keepalive_section result = client.get(keepalive_section, silent=True) # If keeplive section returns a list, it is assumed to be non-empty @@ -189,11 +197,45 @@ class NSXRequestsHTTPProvider(AbstractHTTPProvider): session.mount('http://', adapter) session.mount('https://', adapter) + self.get_default_headers(session, provider) + return session def is_connection_exception(self, exception): return isinstance(exception, requests_exceptions.ConnectionError) + def get_default_headers(self, session, provider): + """Get the default headers that should be added to future requests""" + session.default_headers = {} + + # Perform the initial session create and get the relevant jsessionid & + # X-XSRF-TOKEN for future requests + req_data = 'j_username=%s&j_password=%s' % (provider.username, + provider.password) + req_headers = {'Accept': 'application/json', + 'Content-Type': 'application/x-www-form-urlencoded'} + # Cannot use the certificate at this stage, because it is used for + # the certificate generation + resp = session.request('post', provider.url + self.SESSION_CREATE_URL, + data=req_data, headers=req_headers, + skip_cert=True) + if resp.status_code != 200: + LOG.error("Session create failed for endpoint %s", provider.url) + # this will later cause the endpoint to be Down + else: + for header_name in resp.headers: + if self.SET_COOKIE_FIELD.lower() == header_name.lower(): + m = re.match('%s=.*?\;' % self.JSESSIONID, + resp.headers[header_name]) + if m: + session.default_headers[self.COOKIE_FIELD] = m.group() + if self.XSRF_TOKEN.lower() == header_name.lower(): + session.default_headers[self.XSRF_TOKEN] = resp.headers[ + header_name] + LOG.info("Session create succeeded for endpoint %(url)s with " + "headers %(hdr)s", + {'url': provider.url, 'hdr': session.default_headers}) + class ClusterHealth(object): """Indicator of overall cluster health. @@ -494,6 +536,11 @@ class ClusteredAPI(object): try: LOG.debug("API cluster proxy %s %s to %s", proxy_for.upper(), uri, url) + # Add the connection default headers + if conn.default_headers: + kwargs['headers'] = kwargs.get('headers', {}) + kwargs['headers'].update(conn.default_headers) + # call the actual connection method to do the # http request/response over the wire response = do_request(url, *args, **kwargs)