From ec7f04ee97d9484845c41b8c775ec248da8cda4b Mon Sep 17 00:00:00 2001 From: Unana Okpoyo Date: Mon, 2 Oct 2017 11:33:55 +0100 Subject: [PATCH] VMAX driver - Deprecate backend xml configuration The use of xml files for vmax backend configuration is deprecated. Configuration parameters should be set in cinder.conf for security and uniformity. The xml file can still be used but will not be supported after the queens release. Change-Id: Ic7fc1827608190ec47db30b1265bebde616b616b Implements: blueprint backend-xml-deprecation --- .../volume/drivers/dell_emc/vmax/test_vmax.py | 51 ++++++++- cinder/volume/drivers/dell_emc/vmax/common.py | 101 ++++++++++++++---- cinder/volume/drivers/dell_emc/vmax/fc.py | 4 +- cinder/volume/drivers/dell_emc/vmax/iscsi.py | 5 +- cinder/volume/drivers/dell_emc/vmax/utils.py | 13 +++ ...eprecate-backend-xml-708a41919bcc55a8.yaml | 6 ++ 6 files changed, 150 insertions(+), 30 deletions(-) create mode 100644 releasenotes/notes/vmax-deprecate-backend-xml-708a41919bcc55a8.yaml diff --git a/cinder/tests/unit/volume/drivers/dell_emc/vmax/test_vmax.py b/cinder/tests/unit/volume/drivers/dell_emc/vmax/test_vmax.py index 9e2eede9051..bfc97ff5a60 100644 --- a/cinder/tests/unit/volume/drivers/dell_emc/vmax/test_vmax.py +++ b/cinder/tests/unit/volume/drivers/dell_emc/vmax/test_vmax.py @@ -74,7 +74,7 @@ class VMAXCommonData(object): failed_resource = 'OS-failed-resource' fake_host = 'HostX@Backend#Diamond+DSS+SRP_1+000197800123' new_host = 'HostX@Backend#Silver+OLTP+SRP_1+000197800123' - version = '3.0.0' + version = '3.1.0' volume_wwn = '600000345' remote_array = '000197800124' device_id = '00001' @@ -846,14 +846,34 @@ class FakeRequestsSession(object): class FakeConfiguration(object): def __init__(self, emc_file=None, volume_backend_name=None, - interval=0, retries=0, replication_device=None): + interval=0, retries=0, replication_device=None, **kwargs): self.cinder_dell_emc_config_file = emc_file self.interval = interval self.retries = retries self.volume_backend_name = volume_backend_name self.config_group = volume_backend_name + self.san_is_local = False if replication_device: self.replication_device = [replication_device] + for key, value in kwargs.items(): + if key == 'san_login': + self.san_login = value + elif key == 'san_password': + self.san_password = value + elif key == 'san_ip': + self.san_ip = value + elif key == 'san_rest_port': + self.san_rest_port = value + elif key == 'vmax_srp': + self.vmax_srp = value + elif key == 'vmax_service_level': + self.vmax_service_level = value + elif key == 'vmax_workload': + self.vmax_workload = value + elif key == 'vmax_port_groups': + self.vmax_port_groups = value + elif key == 'vmax_array': + self.vmax_array = value def safe_get(self, key): try: @@ -4499,6 +4519,29 @@ class VMAXCommonTest(test.TestCase): source_group, source_vols)) self.assertEqual(ref_model_update, model_update) + def test_get_attributes_from_cinder_config(self): + kwargs_expected = ( + {'RestServerIp': '1.1.1.1', + 'RestServerPort': 8443, + 'RestUserName': 'smc', + 'RestPassword': 'smc', + 'SSLCert': None, + 'SSLVerify': False, + 'SerialNumber': self.data.array, + 'srpName': 'SRP_1', + 'PortGroup': self.data.port_group_name_i}) + backup_conf = self.common.configuration + configuration = FakeConfiguration( + None, 'CommonTests', 1, 1, san_ip='1.1.1.1', san_login='smc', + vmax_array=self.data.array, vmax_srp='SRP_1', san_password='smc', + san_rest_port=8443, vmax_port_groups=[self.data.port_group_name_i]) + self.common.configuration = configuration + kwargs_returned = self.common.get_attributes_from_cinder_config() + self.assertEqual(kwargs_expected, kwargs_returned) + self.common.configuration = backup_conf + kwargs = self.common.get_attributes_from_cinder_config() + self.assertIsNone(kwargs) + class VMAXFCTest(test.TestCase): def setUp(self): @@ -5020,9 +5063,9 @@ class VMAXMaskingTest(test.TestCase): self._gather_info = common.VMAXCommon._gather_info common.VMAXCommon._gather_info = mock.Mock() driver = common.VMAXCommon( - 'iSCSI', common.VMAXCommon.VERSION, configuration=configuration) + 'iSCSI', self.data.version, configuration=configuration) driver_fc = common.VMAXCommon( - 'FC', common.VMAXCommon.VERSION, configuration=configuration) + 'FC', self.data.version, configuration=configuration) self.driver = driver self.driver_fc = driver_fc self.mask = self.driver.masking diff --git a/cinder/volume/drivers/dell_emc/vmax/common.py b/cinder/volume/drivers/dell_emc/vmax/common.py index a5f9878772e..eb63fd93452 100644 --- a/cinder/volume/drivers/dell_emc/vmax/common.py +++ b/cinder/volume/drivers/dell_emc/vmax/common.py @@ -16,6 +16,7 @@ import ast from copy import deepcopy import os.path +import random import sys from oslo_config import cfg @@ -55,6 +56,7 @@ REPLICATION_ERROR = fields.ReplicationStatus.ERROR vmax_opts = [ cfg.StrOpt('cinder_dell_emc_config_file', default=CINDER_EMC_CONFIG_FILE, + deprecated_for_removal=True, help='Use this file for cinder emc plugin ' 'config data.'), cfg.IntOpt('interval', @@ -68,7 +70,22 @@ vmax_opts = [ cfg.BoolOpt('initiator_check', default=False, help='Use this value to enable ' - 'the initiator_check.')] + 'the initiator_check.'), + cfg.PortOpt(utils.VMAX_SERVER_PORT, + default=8443, + help='REST server port number.'), + cfg.StrOpt(utils.VMAX_ARRAY, + help='Serial number of the array to connect to.'), + cfg.StrOpt(utils.VMAX_SRP, + help='Storage resource pool on array to use for provisioning.'), + cfg.StrOpt(utils.VMAX_SERVICE_LEVEL, + help='Service level to use for provisioning storage.'), + cfg.StrOpt(utils.VMAX_WORKLOAD, + help='Workload'), + cfg.ListOpt(utils.VMAX_PORT_GROUPS, + bounds=True, + help='List of port groups containing frontend ports ' + 'configured prior for server connection.')] CONF.register_opts(vmax_opts, group=configuration.SHARED_CONF_GROUP) @@ -81,18 +98,6 @@ class VMAXCommon(object): It supports VMAX 3 and VMAX All Flash arrays. """ - VERSION = "3.0.0" - - stats = {'driver_version': '3.0', - 'free_capacity_gb': 0, - 'reserved_percentage': 0, - 'storage_protocol': None, - 'total_capacity_gb': 0, - 'vendor_name': 'Dell EMC', - 'volume_backend_name': None, - 'replication_enabled': False, - 'replication_targets': None} - pool_info = {'backend_name': None, 'config_file': None, 'arrays_info': {}, @@ -123,8 +128,10 @@ class VMAXCommon(object): def _gather_info(self): """Gather the relevant information for update_volume_stats.""" self._get_attributes_from_config() - array_info = self.utils.parse_file_to_get_array_map( - self.pool_info['config_file']) + array_info = self.get_attributes_from_cinder_config() + if array_info is None: + array_info = self.utils.parse_file_to_get_array_map( + self.pool_info['config_file']) self.rest.set_rest_credentials(array_info) finalarrayinfolist = self._get_slo_workload_combinations( array_info) @@ -855,7 +862,8 @@ class VMAXCommon(object): array_reserve_percent) def _set_config_file_and_get_extra_specs(self, volume, - volume_type_id=None): + volume_type_id=None, + register_config_file=True): """Given the volume object get the associated volumetype. Given the volume object get the associated volumetype and the @@ -876,13 +884,15 @@ class VMAXCommon(object): qos_specs = res['qos_specs'] config_group = None + config_file = None # If there are no extra specs then the default case is assumed. if extra_specs: config_group = self.configuration.config_group if extra_specs.get('replication_enabled') == ' True': extra_specs[utils.IS_RE] = True - config_file = self._register_config_file_from_config_group( - config_group) + if register_config_file: + config_file = self._register_config_file_from_config_group( + config_group) return extra_specs, config_file, qos_specs def _find_device_on_array(self, volume, extra_specs): @@ -1061,11 +1071,17 @@ class VMAXCommon(object): :raises: VolumeBackendAPIException: """ try: - extra_specs, config_file, qos_specs = ( - self._set_config_file_and_get_extra_specs( - volume, volume_type_id)) - array_info = self.utils.parse_file_to_get_array_map( - config_file) + array_info = self.get_attributes_from_cinder_config() + if array_info: + extra_specs, config_file, qos_specs = ( + self._set_config_file_and_get_extra_specs( + volume, volume_type_id, register_config_file=False)) + else: + extra_specs, config_file, qos_specs = ( + self._set_config_file_and_get_extra_specs( + volume, volume_type_id)) + array_info = self.utils.parse_file_to_get_array_map( + self.pool_info['config_file']) if not array_info: exception_message = (_( "Unable to get corresponding record for srp.")) @@ -3568,3 +3584,42 @@ class VMAXCommon(object): vol_model_updates.append(update) return model_update, vol_model_updates + + def get_attributes_from_cinder_config(self): + LOG.debug("Using cinder.conf file") + kwargs = None + username = self.configuration.safe_get(utils.VMAX_USER_NAME) + password = self.configuration.safe_get(utils.VMAX_PASSWORD) + if username and password: + serial_number = self.configuration.safe_get(utils.VMAX_ARRAY) + if serial_number is None: + LOG.error("Array Serial Number must be set in cinder.conf") + srp_name = self.configuration.safe_get(utils.VMAX_SRP) + if srp_name is None: + LOG.error("SRP Name must be set in cinder.conf") + slo = self.configuration.safe_get(utils.VMAX_SERVICE_LEVEL) + workload = self.configuration.safe_get(utils.WORKLOAD) + port_groups = self.configuration.safe_get(utils.VMAX_PORT_GROUPS) + random_portgroup = None + if port_groups: + random_portgroup = random.choice(self.configuration.safe_get( + utils.VMAX_PORT_GROUPS)) + kwargs = ( + {'RestServerIp': self.configuration.safe_get( + utils.VMAX_SERVER_IP), + 'RestServerPort': self.configuration.safe_get( + utils.VMAX_SERVER_PORT), + 'RestUserName': username, + 'RestPassword': password, + 'SSLCert': self.configuration.safe_get('driver_client_cert'), + 'SerialNumber': serial_number, + 'srpName': srp_name, + 'PortGroup': random_portgroup}) + if self.configuration.safe_get('driver_ssl_cert_verify'): + kwargs.update({'SSLVerify': self.configuration.safe_get( + 'driver_ssl_cert_path')}) + else: + kwargs.update({'SSLVerify': False}) + if slo is not None: + kwargs.update({'ServiceLevel': slo, 'Workload': workload}) + return kwargs diff --git a/cinder/volume/drivers/dell_emc/vmax/fc.py b/cinder/volume/drivers/dell_emc/vmax/fc.py index 585ae71689d..9be38fd73ab 100644 --- a/cinder/volume/drivers/dell_emc/vmax/fc.py +++ b/cinder/volume/drivers/dell_emc/vmax/fc.py @@ -20,13 +20,14 @@ from oslo_log import log as logging from cinder import interface from cinder.volume import driver from cinder.volume.drivers.dell_emc.vmax import common +from cinder.volume.drivers.san import san from cinder.zonemanager import utils as fczm_utils LOG = logging.getLogger(__name__) @interface.volumedriver -class VMAXFCDriver(driver.FibreChannelDriver): +class VMAXFCDriver(san.SanDriver, driver.FibreChannelDriver): """FC Drivers for VMAX using REST. Version history: @@ -83,6 +84,7 @@ class VMAXFCDriver(driver.FibreChannelDriver): - Support for live migration - Support for Generic Volume Group 3.1.0 - Support for replication groups (Tiramisu) + - Deprecate backend xml configuration """ VERSION = "3.1.0" diff --git a/cinder/volume/drivers/dell_emc/vmax/iscsi.py b/cinder/volume/drivers/dell_emc/vmax/iscsi.py index bc5850d64a7..958b491e93f 100644 --- a/cinder/volume/drivers/dell_emc/vmax/iscsi.py +++ b/cinder/volume/drivers/dell_emc/vmax/iscsi.py @@ -22,14 +22,14 @@ import six from cinder import exception from cinder.i18n import _ from cinder import interface -from cinder.volume import driver from cinder.volume.drivers.dell_emc.vmax import common +from cinder.volume.drivers.san import san LOG = logging.getLogger(__name__) @interface.volumedriver -class VMAXISCSIDriver(driver.ISCSIDriver): +class VMAXISCSIDriver(san.SanISCSIDriver): """ISCSI Drivers for VMAX using Rest. Version history: @@ -88,6 +88,7 @@ class VMAXISCSIDriver(driver.ISCSIDriver): - Support for live migration - Support for Generic Volume Group 3.1.0 - Support for replication groups (Tiramisu) + - Deprecate backend xml configuration """ VERSION = "3.1.0" diff --git a/cinder/volume/drivers/dell_emc/vmax/utils.py b/cinder/volume/drivers/dell_emc/vmax/utils.py index 4b6c7b1aabb..953bab097f0 100644 --- a/cinder/volume/drivers/dell_emc/vmax/utils.py +++ b/cinder/volume/drivers/dell_emc/vmax/utils.py @@ -59,6 +59,17 @@ EXTRA_SPECS = 'extra_specs' IS_RE = 'replication_enabled' DISABLECOMPRESSION = 'storagetype:disablecompression' +# Cinder.conf vmax configuration +VMAX_SERVER_IP = 'san_ip' +VMAX_USER_NAME = 'san_login' +VMAX_PASSWORD = 'san_password' +VMAX_SERVER_PORT = 'san_rest_port' +VMAX_ARRAY = 'vmax_array' +VMAX_WORKLOAD = 'vmax_workload' +VMAX_SRP = 'vmax_srp' +VMAX_SERVICE_LEVEL = 'vmax_service_level' +VMAX_PORT_GROUPS = 'vmax_port_groups' + class VMAXUtils(object): """Utility class for Rest based VMAX volume drivers. @@ -325,6 +336,8 @@ class VMAXUtils(object): :param file_name: the configuration file :returns: list """ + LOG.warning("Use of xml file in backend configuration is deprecated " + "in Queens and will not be supported in future releases.") kwargs = {} my_file = open(file_name, 'r') data = my_file.read() diff --git a/releasenotes/notes/vmax-deprecate-backend-xml-708a41919bcc55a8.yaml b/releasenotes/notes/vmax-deprecate-backend-xml-708a41919bcc55a8.yaml new file mode 100644 index 00000000000..f2b73d78593 --- /dev/null +++ b/releasenotes/notes/vmax-deprecate-backend-xml-708a41919bcc55a8.yaml @@ -0,0 +1,6 @@ +--- +deprecations: + - | + The use of xml files for vmax backend configuration is now deprecated and + will be removed during the following release. Deployers are encouraged + to use the cinder.conf for configuring connections to the vmax.