diff --git a/cinder/tests/unit/volume/drivers/dell_emc/sc/test_scapi.py b/cinder/tests/unit/volume/drivers/dell_emc/sc/test_scapi.py index c00a6f1389d..c7e1457f442 100644 --- a/cinder/tests/unit/volume/drivers/dell_emc/sc/test_scapi.py +++ b/cinder/tests/unit/volume/drivers/dell_emc/sc/test_scapi.py @@ -14,6 +14,7 @@ import ddt import eventlet +import json import mock import requests from requests import models @@ -1683,6 +1684,8 @@ class DellSCSanAPITestCase(test.TestCase): self.configuration.target_port = 3260 self._context = context.get_admin_context() self.apiversion = '2.0' + self.asynctimeout = 15 + self.synctimeout = 30 # Set up the SCApi self.scapi = storagecenter_api.SCApi( @@ -1691,6 +1694,8 @@ class DellSCSanAPITestCase(test.TestCase): self.configuration.san_login, self.configuration.san_password, self.configuration.dell_sc_verify_cert, + self.asynctimeout, + self.synctimeout, self.apiversion) # Set up the scapi configuration vars @@ -8635,6 +8640,8 @@ class DellSCSanAPIConnectionTestCase(test.TestCase): self.configuration.target_ip_address = '192.168.1.1' self.configuration.target_port = 3260 self._context = context.get_admin_context() + self.asynctimeout = 15 + self.synctimeout = 30 self.apiversion = '2.0' # Set up the SCApi @@ -8644,6 +8651,8 @@ class DellSCSanAPIConnectionTestCase(test.TestCase): self.configuration.san_login, self.configuration.san_password, self.configuration.dell_sc_verify_cert, + self.asynctimeout, + self.synctimeout, self.apiversion) # Set up the scapi configuration vars @@ -8772,10 +8781,12 @@ class DellHttpClientTestCase(test.TestCase): self.user = 'johnnyuser' self.password = 'password' self.verify = False + self.asynctimeout = 15 + self.synctimeout = 30 self.apiversion = '3.1' self.httpclient = storagecenter_api.HttpClient( - self.host, self.port, self.user, self.password, - self.verify, self.apiversion) + self.host, self.port, self.user, self.password, self.verify, + self.asynctimeout, self.synctimeout, self.apiversion) def test_get_async_url(self): url = self.httpclient._get_async_url(self.ASYNCTASK) @@ -8904,8 +8915,36 @@ class DellHttpClientTestCase(test.TestCase): expected_headers = self.httpclient.header.copy() mock_get.assert_called_once_with('https://localhost:3033/api/rest/url', headers=expected_headers, + timeout=30, verify=False) + @mock.patch.object(requests.Session, 'post', return_value=RESPONSE_200) + @mock.patch.object(storagecenter_api.HttpClient, '_rest_ret') + def test_post(self, mock_rest_ret, mock_post): + payload = {'payload': 'payload'} + self.httpclient.post('url', payload, True) + expected_headers = self.httpclient.header.copy() + expected_headers['async'] = 'True' + mock_post.assert_called_once_with( + 'https://localhost:3033/api/rest/url', + data=json.dumps(payload, ensure_ascii=False).encode('utf-8'), + headers=expected_headers, + timeout=15, + verify=False) + + @mock.patch.object(requests.Session, 'post', return_value=RESPONSE_200) + @mock.patch.object(storagecenter_api.HttpClient, '_rest_ret') + def test_post_sync(self, mock_rest_ret, mock_post): + payload = {'payload': 'payload'} + self.httpclient.post('url', payload, False) + expected_headers = self.httpclient.header.copy() + mock_post.assert_called_once_with( + 'https://localhost:3033/api/rest/url', + data=json.dumps(payload, ensure_ascii=False).encode('utf-8'), + headers=expected_headers, + timeout=30, + verify=False) + class DellStorageCenterApiHelperTestCase(test.TestCase): diff --git a/cinder/volume/drivers/dell_emc/sc/storagecenter_api.py b/cinder/volume/drivers/dell_emc/sc/storagecenter_api.py index 547757df2ca..5f16f882b25 100644 --- a/cinder/volume/drivers/dell_emc/sc/storagecenter_api.py +++ b/cinder/volume/drivers/dell_emc/sc/storagecenter_api.py @@ -79,7 +79,8 @@ class HttpClient(object): Helper for making the REST calls. """ - def __init__(self, host, port, user, password, verify, apiversion): + def __init__(self, host, port, user, password, + verify, asynctimeout, synctimeout, apiversion): """HttpClient handles the REST requests. :param host: IP address of the Dell Data Collector. @@ -88,6 +89,8 @@ class HttpClient(object): :param password: Password. :param verify: Boolean indicating whether certificate verification should be turned on or not. + :param asynctimeout: async REST call time out. + :param synctimeout: sync REST call time out. :param apiversion: Dell API version. """ self.baseUrl = 'https://%s:%s/' % (host, port) @@ -100,6 +103,8 @@ class HttpClient(object): self.header['Accept'] = 'application/json' self.header['x-dell-api-version'] = apiversion self.verify = verify + self.asynctimeout = asynctimeout + self.synctimeout = synctimeout # Verify is a configurable option. So if this is false do not # spam the c-vol log. @@ -230,7 +235,8 @@ class HttpClient(object): LOG.debug('get: %(url)s', {'url': url}) rest_response = self.session.get(self.__formatUrl(url), headers=self.header, - verify=self.verify) + verify=self.verify, + timeout=self.synctimeout) if (rest_response and rest_response.status_code == ( http_client.BAD_REQUEST)) and ( @@ -248,7 +254,9 @@ class HttpClient(object): data=json.dumps(payload, ensure_ascii=False).encode('utf-8'), headers=self._get_header(async_call), - verify=self.verify), async_call) + verify=self.verify, timeout=( + self.asynctimeout if async_call else self.synctimeout)), + async_call) @utils.retry(exceptions=(requests.ConnectionError,)) def put(self, url, payload, async_call=False): @@ -260,14 +268,18 @@ class HttpClient(object): data=json.dumps(payload, ensure_ascii=False).encode('utf-8'), headers=self._get_header(async_call), - verify=self.verify), async_call) + verify=self.verify, timeout=( + self.asynctimeout if async_call else self.synctimeout)), + async_call) @utils.retry(exceptions=(requests.ConnectionError,)) def delete(self, url, payload=None, async_call=False): LOG.debug('delete: %(url)s data: %(payload)s', {'url': url, 'payload': payload}) named = {'headers': self._get_header(async_call), - 'verify': self.verify} + 'verify': self.verify, + 'timeout': ( + self.asynctimeout if async_call else self.synctimeout)} if payload: named['data'] = json.dumps( payload, ensure_ascii=False).encode('utf-8') @@ -336,6 +348,8 @@ class SCApiHelper(object): self.san_login, self.san_password, self.config.dell_sc_verify_cert, + self.config.dell_api_async_rest_timeout, + self.config.dell_api_sync_rest_timeout, self.apiversion) # This instance is for a single backend. That backend has a # few items of information we should save rather than passing them @@ -368,7 +382,7 @@ class SCApiHelper(object): connection = None LOG.info('open_connection to %(ssn)s at %(ip)s', {'ssn': self.primaryssn, - 'ip': self.config.san_ip}) + 'ip': self.san_ip}) if self.primaryssn: try: """Open connection to REST API.""" @@ -420,12 +434,14 @@ class SCApi(object): 3.6.0 - Server type support. 3.7.0 - Support for Data Reduction, Group QOS and Volume QOS. 4.0.0 - Driver moved to dell_emc. + 4.1.0 - Timeouts added to rest calls. """ - APIDRIVERVERSION = '4.0.0' + APIDRIVERVERSION = '4.1.0' - def __init__(self, host, port, user, password, verify, apiversion): + def __init__(self, host, port, user, password, verify, + asynctimeout, synctimeout, apiversion): """This creates a connection to Dell SC or EM. :param host: IP address of the REST interface.. @@ -434,6 +450,8 @@ class SCApi(object): :param password: Password. :param verify: Boolean indicating whether certificate verification should be turned on or not. + :param asynctimeout: async REST call time out. + :param synctimeout: sync REST call time out. :param apiversion: Version used on login. """ self.notes = 'Created by Dell EMC Cinder Driver' @@ -454,8 +472,8 @@ class SCApi(object): # Nothing other than Replication should care if we are direct connect # or not. self.is_direct_connect = False - self.client = HttpClient(host, port, user, password, - verify, apiversion) + self.client = HttpClient(host, port, user, password, verify, + asynctimeout, synctimeout, apiversion) def __enter__(self): return self diff --git a/cinder/volume/drivers/dell_emc/sc/storagecenter_common.py b/cinder/volume/drivers/dell_emc/sc/storagecenter_common.py index 36e53feb0e1..91a1ace692f 100644 --- a/cinder/volume/drivers/dell_emc/sc/storagecenter_common.py +++ b/cinder/volume/drivers/dell_emc/sc/storagecenter_common.py @@ -58,6 +58,12 @@ common_opts = [ cfg.PortOpt('secondary_sc_api_port', default=3033, help='Secondary Dell API port'), + cfg.IntOpt('dell_api_async_rest_timeout', + default=15, + help='Dell SC API async call default timeout in seconds.'), + cfg.IntOpt('dell_api_sync_rest_timeout', + default=30, + help='Dell SC API sync call default timeout in seconds.'), cfg.MultiOpt('excluded_domain_ip', item_type=types.IPAddress(), default=None, diff --git a/cinder/volume/drivers/dell_emc/sc/storagecenter_fc.py b/cinder/volume/drivers/dell_emc/sc/storagecenter_fc.py index c1bca2bf9e2..8dbfe3df2e9 100644 --- a/cinder/volume/drivers/dell_emc/sc/storagecenter_fc.py +++ b/cinder/volume/drivers/dell_emc/sc/storagecenter_fc.py @@ -34,7 +34,7 @@ class SCFCDriver(storagecenter_common.SCCommonDriver, """Implements commands for Dell Storage Center FC management. To enable the driver add the following line to the cinder configuration: - volume_driver=cinder.volume.drivers.dell_emc.sc.dell_storagecenter_fc.\ + volume_driver=cinder.volume.drivers.dell_emc.sc.storagecenter_fc.\ SCFCDriver Version history: @@ -62,10 +62,11 @@ class SCFCDriver(storagecenter_common.SCCommonDriver, 3.6.0 - Server type support. 3.7.0 - Support for Data Reduction, Group QOS and Volume QOS. 4.0.0 - Driver moved to dell_emc. + 4.1.0 - Timeouts added to rest calls. """ - VERSION = '4.0.0' + VERSION = '4.1.0' CI_WIKI_NAME = "Dell_EMC_SC_Series_CI" diff --git a/cinder/volume/drivers/dell_emc/sc/storagecenter_iscsi.py b/cinder/volume/drivers/dell_emc/sc/storagecenter_iscsi.py index d6d9f0363e6..05eac61e014 100644 --- a/cinder/volume/drivers/dell_emc/sc/storagecenter_iscsi.py +++ b/cinder/volume/drivers/dell_emc/sc/storagecenter_iscsi.py @@ -34,7 +34,7 @@ class SCISCSIDriver(storagecenter_common.SCCommonDriver, To enable the driver add the following line to the cinder configuration: volume_driver=cinder.volume.drivers.dell_emc.sc.\ - dell_storagecenter_iscsi.SCISCSIDriver + storagecenter_iscsi.SCISCSIDriver Version history: @@ -62,10 +62,11 @@ class SCISCSIDriver(storagecenter_common.SCCommonDriver, 3.6.0 - Server type support. 3.7.0 - Support for Data Reduction, Group QOS and Volume QOS. 4.0.0 - Driver moved to dell_emc. + 4.1.0 - Timeouts added to rest calls. """ - VERSION = '4.0.0' + VERSION = '4.1.0' CI_WIKI_NAME = "Dell_EMC_SC_Series_CI" def __init__(self, *args, **kwargs): diff --git a/doc/source/configuration/block-storage/drivers/dell-storagecenter-driver.rst b/doc/source/configuration/block-storage/drivers/dell-storagecenter-driver.rst index 4f5073f7ddd..fa98a38542e 100644 --- a/doc/source/configuration/block-storage/drivers/dell-storagecenter-driver.rst +++ b/doc/source/configuration/block-storage/drivers/dell-storagecenter-driver.rst @@ -2,19 +2,19 @@ Dell EMC SC Series Fibre Channel and iSCSI drivers ================================================== -The Dell Storage Center volume driver interacts with configured Storage +The Dell EMC Storage Center volume driver interacts with configured Storage Center arrays. -The Dell Storage Center driver manages Storage Center arrays through -the Dell Storage Manager (DSM). DSM connection settings and Storage +The Dell EMC Storage Center driver manages Storage Center arrays through +the Dell EMC Storage Manager (DSM). DSM connection settings and Storage Center options are defined in the ``cinder.conf`` file. -Prerequisite: Dell Storage Manager 2015 R1 or later must be used. +Prerequisite: Dell EMC Storage Manager 2015 R1 or later must be used. Supported operations ~~~~~~~~~~~~~~~~~~~~ -The Dell Storage Center volume driver provides the following Cinder +The Dell EMC Storage Center volume driver provides the following Cinder volume operations: - Create, delete, attach (map), and detach (unmap) volumes. @@ -33,7 +33,7 @@ volume operations: Extra spec options ~~~~~~~~~~~~~~~~~~ -Volume type extra specs can be used to enable a variety of Dell Storage +Volume type extra specs can be used to enable a variety of Dell EMC Storage Center options. Selecting Storage Profiles, Replay Profiles, enabling replication, replication options including Live Volume and Active Replay replication. @@ -170,7 +170,7 @@ Use the following instructions to update the configuration file for iSCSI: # Name to give this storage back-end volume_backend_name = delliscsi # The iSCSI driver to load - volume_driver = cinder.volume.drivers.dell.dell_storagecenter_iscsi.DellStorageCenterISCSIDriver + volume_driver = cinder.volume.drivers.dell_emc.sc.storagecenter_iscsi.SCISCSIDriver # IP address of DSM san_ip = 172.23.8.101 # DSM user name @@ -204,7 +204,8 @@ channel: # Name to give this storage back-end volume_backend_name = dellfc # The FC driver to load - volume_driver = cinder.volume.drivers.dell.dell_storagecenter_fc.DellStorageCenterFCDriver + volume_driver = cinder.volume.drivers.dell_emc.sc.storagecenter_fc.SCFCDriver + # IP address of the DSM san_ip = 172.23.8.101 # DSM user name @@ -298,10 +299,10 @@ Simply specify default as the backend_id. $ cinder failover-host cinder@delliscsi --backend_id default -Non trivial heavy lifting is done by this command. It attempts to recover best -it can but if things have diverged to far it can only do so much. It is also a -one time only command so do not reboot or restart the service in the middle of -it. +Non trivial heavy lifting is done by this command. It attempts to recover as +best it can but if things have diverged too far it can only do so much. It is +also a one time only command so do not reboot or restart the service in the +middle of it. Failover and failback are significant operations under OpenStack Cinder. Be sure to consult with support before attempting. @@ -310,11 +311,11 @@ Server type configuration ~~~~~~~~~~~~~~~~~~~~~~~~~ This option allows one to set a default Server OS type to use when creating -a server definition on the Dell Storage Center. +a server definition on the Dell EMC Storage Center. -When attaching a volume to a node the Dell Storage Center driver creates a +When attaching a volume to a node the Dell EMC Storage Center driver creates a server definition on the storage array. This defition includes a Server OS -type. The type used by the Dell Storage Center cinder driver is +type. The type used by the Dell EMC Storage Center cinder driver is "Red Hat Linux 6.x". This is a modern operating system definition that supports all the features of an OpenStack node. @@ -352,10 +353,31 @@ Add the following to the back-end specification to exclude the domains at excluded_domain_ip=172.20.25.15 excluded_domain_ip=172.20.26.15 +Setting Dell EMC SC REST API timeouts +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The user can specify timeouts for Dell EMC SC REST API calls. + +To set the timeout for ASYNC REST API calls in seconds. + +.. code-block:: ini + + [dell] + dell_api_async_rest_timeout=15 + +To set the timeout for SYNC REST API calls in seconds. + +.. code-block:: ini + + [dell] + dell_api_sync_rest_timeout=30 + +Generally these should not be set without guidance from Dell EMC support. + Driver options ~~~~~~~~~~~~~~ The following table contains the configuration options specific to the -Dell Storage Center volume driver. +Dell EMC Storage Center volume driver. .. include:: ../../tables/cinder-dellsc.inc diff --git a/releasenotes/notes/dell-emc-sc-api-timeouts-ce8d166e1847ea94.yaml b/releasenotes/notes/dell-emc-sc-api-timeouts-ce8d166e1847ea94.yaml new file mode 100644 index 00000000000..abb0be6eb7b --- /dev/null +++ b/releasenotes/notes/dell-emc-sc-api-timeouts-ce8d166e1847ea94.yaml @@ -0,0 +1,11 @@ +--- +features: + - Added dell_api_async_rest_timeout option to the + Dell EMC SC driver. This is the timeout used for + asynchronous REST calls to the Dell EMC SC REST + API. Default is 15 seconds. + - Added dell_api_sync_rest_timeout option to the + Dell EMC SC driver. This is the timeout used for + synchronous REST calls to the Dell EMC SC REST + API. Default is 30 seconds. +