VMAX driver - remove deprecated XML option
'cinder_dell_emc_config_file' was deprecated in Queens. We are now removing all reference to it and all XML parsing. Now we rely solely on the config tags in cinder.conf. Closes-Bug: #1768273 Change-Id: If6f7c58f445dd813df7161cc6cd6dd84484e8a7e
This commit is contained in:
parent
6c3ab36479
commit
c0a5be259e
@ -16,9 +16,7 @@
|
|||||||
import ast
|
import ast
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
import datetime
|
import datetime
|
||||||
import tempfile
|
|
||||||
import time
|
import time
|
||||||
from xml.dom import minidom
|
|
||||||
|
|
||||||
import mock
|
import mock
|
||||||
import requests
|
import requests
|
||||||
@ -154,7 +152,7 @@ class VMAXCommonData(object):
|
|||||||
|
|
||||||
# cinder volume info
|
# cinder volume info
|
||||||
ctx = context.RequestContext('admin', 'fake', True)
|
ctx = context.RequestContext('admin', 'fake', True)
|
||||||
provider_location = {'array': six.text_type(array),
|
provider_location = {'array': array,
|
||||||
'device_id': device_id}
|
'device_id': device_id}
|
||||||
|
|
||||||
provider_location2 = {'array': six.text_type(array),
|
provider_location2 = {'array': six.text_type(array),
|
||||||
@ -283,8 +281,8 @@ class VMAXCommonData(object):
|
|||||||
extra_specs_rep_enabled['replication_enabled'] = True
|
extra_specs_rep_enabled['replication_enabled'] = True
|
||||||
rep_extra_specs = deepcopy(extra_specs_rep_enabled)
|
rep_extra_specs = deepcopy(extra_specs_rep_enabled)
|
||||||
rep_extra_specs['array'] = remote_array
|
rep_extra_specs['array'] = remote_array
|
||||||
rep_extra_specs['interval'] = 0
|
rep_extra_specs['interval'] = 1
|
||||||
rep_extra_specs['retries'] = 0
|
rep_extra_specs['retries'] = 1
|
||||||
rep_extra_specs['srp'] = srp2
|
rep_extra_specs['srp'] = srp2
|
||||||
rep_extra_specs['rep_mode'] = 'Synchronous'
|
rep_extra_specs['rep_mode'] = 'Synchronous'
|
||||||
rep_extra_specs2 = deepcopy(rep_extra_specs)
|
rep_extra_specs2 = deepcopy(rep_extra_specs)
|
||||||
@ -1183,89 +1181,15 @@ class FakeConfiguration(object):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class FakeXML(object):
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
""""""
|
|
||||||
self.tempdir = tempfile.mkdtemp()
|
|
||||||
self.data = VMAXCommonData()
|
|
||||||
|
|
||||||
def create_fake_config_file(self, config_group, portgroup,
|
|
||||||
ssl_verify=False):
|
|
||||||
|
|
||||||
doc = minidom.Document()
|
|
||||||
emc = doc.createElement("EMC")
|
|
||||||
doc.appendChild(emc)
|
|
||||||
doc = self.add_array_info(doc, emc, portgroup, ssl_verify)
|
|
||||||
filename = 'cinder_dell_emc_config_%s.xml' % config_group
|
|
||||||
config_file_path = self.tempdir + '/' + filename
|
|
||||||
|
|
||||||
f = open(config_file_path, 'w')
|
|
||||||
doc.writexml(f)
|
|
||||||
f.close()
|
|
||||||
return config_file_path
|
|
||||||
|
|
||||||
def add_array_info(self, doc, emc, portgroup_name, ssl_verify):
|
|
||||||
array = doc.createElement("Array")
|
|
||||||
arraytext = doc.createTextNode(self.data.array)
|
|
||||||
emc.appendChild(array)
|
|
||||||
array.appendChild(arraytext)
|
|
||||||
|
|
||||||
ecomserverip = doc.createElement("RestServerIp")
|
|
||||||
ecomserveriptext = doc.createTextNode("1.1.1.1")
|
|
||||||
emc.appendChild(ecomserverip)
|
|
||||||
ecomserverip.appendChild(ecomserveriptext)
|
|
||||||
|
|
||||||
ecomserverport = doc.createElement("RestServerPort")
|
|
||||||
ecomserverporttext = doc.createTextNode("8443")
|
|
||||||
emc.appendChild(ecomserverport)
|
|
||||||
ecomserverport.appendChild(ecomserverporttext)
|
|
||||||
|
|
||||||
ecomusername = doc.createElement("RestUserName")
|
|
||||||
ecomusernametext = doc.createTextNode("smc")
|
|
||||||
emc.appendChild(ecomusername)
|
|
||||||
ecomusername.appendChild(ecomusernametext)
|
|
||||||
|
|
||||||
ecompassword = doc.createElement("RestPassword")
|
|
||||||
ecompasswordtext = doc.createTextNode("smc")
|
|
||||||
emc.appendChild(ecompassword)
|
|
||||||
ecompassword.appendChild(ecompasswordtext)
|
|
||||||
|
|
||||||
portgroup = doc.createElement("PortGroup")
|
|
||||||
portgrouptext = doc.createTextNode(portgroup_name)
|
|
||||||
portgroup.appendChild(portgrouptext)
|
|
||||||
|
|
||||||
portgroups = doc.createElement("PortGroups")
|
|
||||||
portgroups.appendChild(portgroup)
|
|
||||||
emc.appendChild(portgroups)
|
|
||||||
|
|
||||||
srp = doc.createElement("SRP")
|
|
||||||
srptext = doc.createTextNode("SRP_1")
|
|
||||||
emc.appendChild(srp)
|
|
||||||
srp.appendChild(srptext)
|
|
||||||
|
|
||||||
if ssl_verify:
|
|
||||||
restcert = doc.createElement("SSLCert")
|
|
||||||
restcerttext = doc.createTextNode("/path/cert.crt")
|
|
||||||
emc.appendChild(restcert)
|
|
||||||
restcert.appendChild(restcerttext)
|
|
||||||
|
|
||||||
restverify = doc.createElement("SSLVerify")
|
|
||||||
restverifytext = doc.createTextNode("/path/cert.pem")
|
|
||||||
emc.appendChild(restverify)
|
|
||||||
restverify.appendChild(restverifytext)
|
|
||||||
return doc
|
|
||||||
|
|
||||||
|
|
||||||
class VMAXUtilsTest(test.TestCase):
|
class VMAXUtilsTest(test.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.data = VMAXCommonData()
|
self.data = VMAXCommonData()
|
||||||
volume_utils.get_max_over_subscription_ratio = mock.Mock()
|
volume_utils.get_max_over_subscription_ratio = mock.Mock()
|
||||||
super(VMAXUtilsTest, self).setUp()
|
super(VMAXUtilsTest, self).setUp()
|
||||||
config_group = 'UtilsTests'
|
configuration = FakeConfiguration(
|
||||||
fake_xml = FakeXML().create_fake_config_file(
|
None, 'UtilsTests', 1, 1, san_ip='1.1.1.1', san_login='smc',
|
||||||
config_group, self.data.port_group_name_i, True)
|
vmax_array=self.data.array, vmax_srp='SRP_1', san_password='smc',
|
||||||
configuration = FakeConfiguration(fake_xml, config_group)
|
san_api_port=8443, vmax_port_groups=[self.data.port_group_name_i])
|
||||||
rest.VMAXRest._establish_rest_session = mock.Mock(
|
rest.VMAXRest._establish_rest_session = mock.Mock(
|
||||||
return_value=FakeRequestsSession())
|
return_value=FakeRequestsSession())
|
||||||
driver = iscsi.VMAXISCSIDriver(configuration=configuration)
|
driver = iscsi.VMAXISCSIDriver(configuration=configuration)
|
||||||
@ -1298,48 +1222,6 @@ class VMAXUtilsTest(test.TestCase):
|
|||||||
{'name': 'no_type_id'})
|
{'name': 'no_type_id'})
|
||||||
self.assertEqual({}, extra_specs)
|
self.assertEqual({}, extra_specs)
|
||||||
|
|
||||||
def test_get_random_portgroup(self):
|
|
||||||
# 4 portgroups
|
|
||||||
data = ("<?xml version='1.0' encoding='UTF-8'?>\n<EMC>\n"
|
|
||||||
"<PortGroups>"
|
|
||||||
"<PortGroup>OS-PG1</PortGroup>\n"
|
|
||||||
"<PortGroup>OS-PG2</PortGroup>\n"
|
|
||||||
"<PortGroup>OS-PG3</PortGroup>\n"
|
|
||||||
"<PortGroup>OS-PG4</PortGroup>\n"
|
|
||||||
"</PortGroups>"
|
|
||||||
"</EMC>")
|
|
||||||
dom = minidom.parseString(data)
|
|
||||||
portgroup = self.utils._get_random_portgroup(dom)
|
|
||||||
self.assertIn('OS-PG', portgroup)
|
|
||||||
|
|
||||||
# Duplicate portgroups
|
|
||||||
data = ("<?xml version='1.0' encoding='UTF-8'?>\n<EMC>\n"
|
|
||||||
"<PortGroups>"
|
|
||||||
"<PortGroup>OS-PG1</PortGroup>\n"
|
|
||||||
"<PortGroup>OS-PG1</PortGroup>\n"
|
|
||||||
"<PortGroup>OS-PG1</PortGroup>\n"
|
|
||||||
"<PortGroup>OS-PG2</PortGroup>\n"
|
|
||||||
"</PortGroups>"
|
|
||||||
"</EMC>")
|
|
||||||
dom = minidom.parseString(data)
|
|
||||||
portgroup = self.utils._get_random_portgroup(dom)
|
|
||||||
self.assertIn('OS-PG', portgroup)
|
|
||||||
|
|
||||||
def test_get_random_portgroup_none(self):
|
|
||||||
# Missing PortGroup tag
|
|
||||||
data = ("<?xml version='1.0' encoding='UTF-8'?>\n<EMC>\n"
|
|
||||||
"</EMC>")
|
|
||||||
dom = minidom.parseString(data)
|
|
||||||
self.assertIsNone(self.utils._get_random_portgroup(dom))
|
|
||||||
|
|
||||||
# Missing portgroups
|
|
||||||
data = ("<?xml version='1.0' encoding='UTF-8'?>\n<EMC>\n"
|
|
||||||
"<PortGroups>"
|
|
||||||
"</PortGroups>"
|
|
||||||
"</EMC>")
|
|
||||||
dom = minidom.parseString(data)
|
|
||||||
self.assertIsNone(self.utils._get_random_portgroup(dom))
|
|
||||||
|
|
||||||
def test_get_host_short_name(self):
|
def test_get_host_short_name(self):
|
||||||
host_under_16_chars = 'host_13_chars'
|
host_under_16_chars = 'host_13_chars'
|
||||||
host1 = self.utils.get_host_short_name(
|
host1 = self.utils.get_host_short_name(
|
||||||
@ -1365,53 +1247,6 @@ class VMAXUtilsTest(test.TestCase):
|
|||||||
expect_vol_element_name = ('OS-' + volume_id)
|
expect_vol_element_name = ('OS-' + volume_id)
|
||||||
self.assertEqual(expect_vol_element_name, volume_element_name)
|
self.assertEqual(expect_vol_element_name, volume_element_name)
|
||||||
|
|
||||||
def test_parse_file_to_get_array_map(self):
|
|
||||||
kwargs = (
|
|
||||||
{'RestServerIp': '1.1.1.1',
|
|
||||||
'RestServerPort': '8443',
|
|
||||||
'RestUserName': 'smc',
|
|
||||||
'RestPassword': 'smc',
|
|
||||||
'SSLCert': '/path/cert.crt',
|
|
||||||
'SSLVerify': '/path/cert.pem',
|
|
||||||
'SerialNumber': self.data.array,
|
|
||||||
'srpName': 'SRP_1',
|
|
||||||
'PortGroup': self.data.port_group_name_i})
|
|
||||||
array_info = self.utils.parse_file_to_get_array_map(
|
|
||||||
self.common.configuration.cinder_dell_emc_config_file)
|
|
||||||
self.assertEqual(kwargs, array_info)
|
|
||||||
|
|
||||||
@mock.patch.object(utils.VMAXUtils,
|
|
||||||
'_get_connection_info')
|
|
||||||
@mock.patch.object(utils.VMAXUtils,
|
|
||||||
'_get_random_portgroup')
|
|
||||||
def test_parse_file_to_get_array_map_errors(self, mock_port, mock_conn):
|
|
||||||
tempdir = tempfile.mkdtemp()
|
|
||||||
doc = minidom.Document()
|
|
||||||
emc = doc.createElement("EMC")
|
|
||||||
doc.appendChild(emc)
|
|
||||||
filename = 'cinder_dell_emc_config_%s.xml' % 'fake_xml'
|
|
||||||
config_file_path = tempdir + '/' + filename
|
|
||||||
f = open(config_file_path, 'w')
|
|
||||||
doc.writexml(f)
|
|
||||||
f.close()
|
|
||||||
array_info = self.utils.parse_file_to_get_array_map(
|
|
||||||
config_file_path)
|
|
||||||
self.assertIsNone(array_info['SerialNumber'])
|
|
||||||
|
|
||||||
def test_parse_file_to_get_array_map_conn_errors(self):
|
|
||||||
tempdir = tempfile.mkdtemp()
|
|
||||||
doc = minidom.Document()
|
|
||||||
emc = doc.createElement("EMC")
|
|
||||||
doc.appendChild(emc)
|
|
||||||
filename = 'cinder_dell_emc_config_%s.xml' % 'fake_xml'
|
|
||||||
config_file_path = tempdir + '/' + filename
|
|
||||||
f = open(config_file_path, 'w')
|
|
||||||
doc.writexml(f)
|
|
||||||
f.close()
|
|
||||||
self.assertRaises(exception.VolumeBackendAPIException,
|
|
||||||
self.utils.parse_file_to_get_array_map,
|
|
||||||
config_file_path)
|
|
||||||
|
|
||||||
def test_truncate_string(self):
|
def test_truncate_string(self):
|
||||||
# string is less than max number
|
# string is less than max number
|
||||||
str_to_truncate = 'string'
|
str_to_truncate = 'string'
|
||||||
@ -1796,10 +1631,10 @@ class VMAXRestTest(test.TestCase):
|
|||||||
|
|
||||||
super(VMAXRestTest, self).setUp()
|
super(VMAXRestTest, self).setUp()
|
||||||
volume_utils.get_max_over_subscription_ratio = mock.Mock()
|
volume_utils.get_max_over_subscription_ratio = mock.Mock()
|
||||||
config_group = 'RestTests'
|
configuration = FakeConfiguration(
|
||||||
fake_xml = FakeXML().create_fake_config_file(
|
None, 'RestTests', 1, 1, san_ip='1.1.1.1', san_login='smc',
|
||||||
config_group, self.data.port_group_name_f)
|
vmax_array=self.data.array, vmax_srp='SRP_1', san_password='smc',
|
||||||
configuration = FakeConfiguration(fake_xml, config_group)
|
san_api_port=8443, vmax_port_groups=[self.data.port_group_name_i])
|
||||||
rest.VMAXRest._establish_rest_session = mock.Mock(
|
rest.VMAXRest._establish_rest_session = mock.Mock(
|
||||||
return_value=FakeRequestsSession())
|
return_value=FakeRequestsSession())
|
||||||
driver = fc.VMAXFCDriver(configuration=configuration)
|
driver = fc.VMAXFCDriver(configuration=configuration)
|
||||||
@ -3255,10 +3090,10 @@ class VMAXProvisionTest(test.TestCase):
|
|||||||
|
|
||||||
super(VMAXProvisionTest, self).setUp()
|
super(VMAXProvisionTest, self).setUp()
|
||||||
volume_utils.get_max_over_subscription_ratio = mock.Mock()
|
volume_utils.get_max_over_subscription_ratio = mock.Mock()
|
||||||
config_group = 'ProvisionTests'
|
configuration = FakeConfiguration(
|
||||||
self.fake_xml = FakeXML().create_fake_config_file(
|
None, 'ProvisionTests', 1, 1, san_ip='1.1.1.1', san_login='smc',
|
||||||
config_group, self.data.port_group_name_i)
|
vmax_array=self.data.array, vmax_srp='SRP_1', san_password='smc',
|
||||||
configuration = FakeConfiguration(self.fake_xml, config_group)
|
san_api_port=8443, vmax_port_groups=[self.data.port_group_name_i])
|
||||||
rest.VMAXRest._establish_rest_session = mock.Mock(
|
rest.VMAXRest._establish_rest_session = mock.Mock(
|
||||||
return_value=FakeRequestsSession())
|
return_value=FakeRequestsSession())
|
||||||
driver = iscsi.VMAXISCSIDriver(configuration=configuration)
|
driver = iscsi.VMAXISCSIDriver(configuration=configuration)
|
||||||
@ -3760,11 +3595,10 @@ class VMAXCommonTest(test.TestCase):
|
|||||||
super(VMAXCommonTest, self).setUp()
|
super(VMAXCommonTest, self).setUp()
|
||||||
self.mock_object(volume_utils, 'get_max_over_subscription_ratio',
|
self.mock_object(volume_utils, 'get_max_over_subscription_ratio',
|
||||||
return_value=1.0)
|
return_value=1.0)
|
||||||
config_group = 'CommonTests'
|
configuration = FakeConfiguration(
|
||||||
self.fake_xml = FakeXML().create_fake_config_file(
|
None, 'CommonTests', 1, 1, san_ip='1.1.1.1', san_login='smc',
|
||||||
config_group, self.data.port_group_name_f)
|
vmax_array=self.data.array, vmax_srp='SRP_1', san_password='smc',
|
||||||
configuration = FakeConfiguration(self.fake_xml, config_group,
|
san_api_port=8443, vmax_port_groups=[self.data.port_group_name_f])
|
||||||
1, 1)
|
|
||||||
rest.VMAXRest._establish_rest_session = mock.Mock(
|
rest.VMAXRest._establish_rest_session = mock.Mock(
|
||||||
return_value=FakeRequestsSession())
|
return_value=FakeRequestsSession())
|
||||||
driver = fc.VMAXFCDriver(configuration=configuration)
|
driver = fc.VMAXFCDriver(configuration=configuration)
|
||||||
@ -3782,16 +3616,15 @@ class VMAXCommonTest(test.TestCase):
|
|||||||
@mock.patch.object(common.VMAXCommon,
|
@mock.patch.object(common.VMAXCommon,
|
||||||
'_get_slo_workload_combinations',
|
'_get_slo_workload_combinations',
|
||||||
return_value=[])
|
return_value=[])
|
||||||
@mock.patch.object(utils.VMAXUtils,
|
@mock.patch.object(common.VMAXCommon,
|
||||||
'parse_file_to_get_array_map',
|
'get_attributes_from_cinder_config',
|
||||||
return_value=[])
|
return_value=[])
|
||||||
def test_gather_info_no_opts(self, mock_parse, mock_combo, mock_rest):
|
def test_gather_info_no_opts(self, mock_parse, mock_combo, mock_rest):
|
||||||
configuration = FakeConfiguration(None, 'config_group', None, None)
|
configuration = FakeConfiguration(None, 'config_group', None, None)
|
||||||
fc.VMAXFCDriver(configuration=configuration)
|
fc.VMAXFCDriver(configuration=configuration)
|
||||||
|
|
||||||
def test_get_slo_workload_combinations_success(self):
|
def test_get_slo_workload_combinations_success(self):
|
||||||
array_info = self.utils.parse_file_to_get_array_map(
|
array_info = self.common.get_attributes_from_cinder_config()
|
||||||
self.common.pool_info['config_file'])
|
|
||||||
finalarrayinfolist = self.common._get_slo_workload_combinations(
|
finalarrayinfolist = self.common._get_slo_workload_combinations(
|
||||||
array_info)
|
array_info)
|
||||||
self.assertTrue(len(finalarrayinfolist) > 1)
|
self.assertTrue(len(finalarrayinfolist) > 1)
|
||||||
@ -4123,23 +3956,6 @@ class VMAXCommonTest(test.TestCase):
|
|||||||
data = self.common.update_volume_stats()
|
data = self.common.update_volume_stats()
|
||||||
self.assertEqual('CommonTests', data['volume_backend_name'])
|
self.assertEqual('CommonTests', data['volume_backend_name'])
|
||||||
|
|
||||||
def test_set_config_file_and_get_extra_specs(self):
|
|
||||||
volume = self.data.test_volume
|
|
||||||
extra_specs, config_file, qos_specs = (
|
|
||||||
self.common._set_config_file_and_get_extra_specs(volume))
|
|
||||||
self.assertEqual(self.data.vol_type_extra_specs, extra_specs)
|
|
||||||
self.assertEqual(self.fake_xml, config_file)
|
|
||||||
|
|
||||||
def test_set_config_file_and_get_extra_specs_no_specs(self):
|
|
||||||
volume = self.data.test_volume
|
|
||||||
ref_config = '/etc/cinder/cinder_dell_emc_config.xml'
|
|
||||||
with mock.patch.object(self.utils, 'get_volumetype_extra_specs',
|
|
||||||
return_value=None):
|
|
||||||
extra_specs, config_file, qos_specs = (
|
|
||||||
self.common._set_config_file_and_get_extra_specs(volume))
|
|
||||||
self.assertIsNone(extra_specs)
|
|
||||||
self.assertEqual(ref_config, config_file)
|
|
||||||
|
|
||||||
def test_find_device_on_array_success(self):
|
def test_find_device_on_array_success(self):
|
||||||
volume = self.data.test_volume
|
volume = self.data.test_volume
|
||||||
extra_specs = self.data.extra_specs
|
extra_specs = self.data.extra_specs
|
||||||
@ -4240,18 +4056,6 @@ class VMAXCommonTest(test.TestCase):
|
|||||||
volume, None, extra_specs)
|
volume, None, extra_specs)
|
||||||
self.assertEqual(ref_masked, maskedvols)
|
self.assertEqual(ref_masked, maskedvols)
|
||||||
|
|
||||||
def test_register_config_file_from_config_group_exists(self):
|
|
||||||
config_group_name = 'CommonTests'
|
|
||||||
config_file = self.common._register_config_file_from_config_group(
|
|
||||||
config_group_name)
|
|
||||||
self.assertEqual(self.fake_xml, config_file)
|
|
||||||
|
|
||||||
def test_register_config_file_from_config_group_does_not_exist(self):
|
|
||||||
config_group_name = 'IncorrectName'
|
|
||||||
self.assertRaises(exception.VolumeBackendAPIException,
|
|
||||||
self.common._register_config_file_from_config_group,
|
|
||||||
config_group_name)
|
|
||||||
|
|
||||||
def test_initial_setup_success(self):
|
def test_initial_setup_success(self):
|
||||||
volume = self.data.test_volume
|
volume = self.data.test_volume
|
||||||
ref_extra_specs = deepcopy(self.data.extra_specs_intervals_set)
|
ref_extra_specs = deepcopy(self.data.extra_specs_intervals_set)
|
||||||
@ -4261,7 +4065,8 @@ class VMAXCommonTest(test.TestCase):
|
|||||||
|
|
||||||
def test_initial_setup_failed(self):
|
def test_initial_setup_failed(self):
|
||||||
volume = self.data.test_volume
|
volume = self.data.test_volume
|
||||||
with mock.patch.object(self.utils, 'parse_file_to_get_array_map',
|
with mock.patch.object(
|
||||||
|
self.common, 'get_attributes_from_cinder_config',
|
||||||
return_value=None):
|
return_value=None):
|
||||||
self.assertRaises(exception.VolumeBackendAPIException,
|
self.assertRaises(exception.VolumeBackendAPIException,
|
||||||
self.common._initial_setup, volume)
|
self.common._initial_setup, volume)
|
||||||
@ -4475,8 +4280,7 @@ class VMAXCommonTest(test.TestCase):
|
|||||||
volume_name, volume_size, extra_specs)
|
volume_name, volume_size, extra_specs)
|
||||||
|
|
||||||
def test_set_vmax_extra_specs(self):
|
def test_set_vmax_extra_specs(self):
|
||||||
srp_record = self.utils.parse_file_to_get_array_map(
|
srp_record = self.common.get_attributes_from_cinder_config()
|
||||||
self.fake_xml)
|
|
||||||
extra_specs = self.common._set_vmax_extra_specs(
|
extra_specs = self.common._set_vmax_extra_specs(
|
||||||
self.data.vol_type_extra_specs, srp_record)
|
self.data.vol_type_extra_specs, srp_record)
|
||||||
ref_extra_specs = deepcopy(self.data.extra_specs_intervals_set)
|
ref_extra_specs = deepcopy(self.data.extra_specs_intervals_set)
|
||||||
@ -4484,16 +4288,14 @@ class VMAXCommonTest(test.TestCase):
|
|||||||
self.assertEqual(ref_extra_specs, extra_specs)
|
self.assertEqual(ref_extra_specs, extra_specs)
|
||||||
|
|
||||||
def test_set_vmax_extra_specs_no_srp_name(self):
|
def test_set_vmax_extra_specs_no_srp_name(self):
|
||||||
srp_record = self.utils.parse_file_to_get_array_map(
|
srp_record = self.common.get_attributes_from_cinder_config()
|
||||||
self.fake_xml)
|
|
||||||
extra_specs = self.common._set_vmax_extra_specs({}, srp_record)
|
extra_specs = self.common._set_vmax_extra_specs({}, srp_record)
|
||||||
self.assertEqual('Optimized', extra_specs['slo'])
|
self.assertEqual('Optimized', extra_specs['slo'])
|
||||||
|
|
||||||
def test_set_vmax_extra_specs_compr_disabled(self):
|
def test_set_vmax_extra_specs_compr_disabled(self):
|
||||||
with mock.patch.object(self.rest, 'is_compression_capable',
|
with mock.patch.object(self.rest, 'is_compression_capable',
|
||||||
return_value=True):
|
return_value=True):
|
||||||
srp_record = self.utils.parse_file_to_get_array_map(
|
srp_record = self.common.get_attributes_from_cinder_config()
|
||||||
self.fake_xml)
|
|
||||||
extra_specs = self.common._set_vmax_extra_specs(
|
extra_specs = self.common._set_vmax_extra_specs(
|
||||||
self.data.vol_type_extra_specs_compr_disabled, srp_record)
|
self.data.vol_type_extra_specs_compr_disabled, srp_record)
|
||||||
ref_extra_specs = deepcopy(self.data.extra_specs_intervals_set)
|
ref_extra_specs = deepcopy(self.data.extra_specs_intervals_set)
|
||||||
@ -4502,8 +4304,7 @@ class VMAXCommonTest(test.TestCase):
|
|||||||
self.assertEqual(ref_extra_specs, extra_specs)
|
self.assertEqual(ref_extra_specs, extra_specs)
|
||||||
|
|
||||||
def test_set_vmax_extra_specs_compr_disabled_not_compr_capable(self):
|
def test_set_vmax_extra_specs_compr_disabled_not_compr_capable(self):
|
||||||
srp_record = self.utils.parse_file_to_get_array_map(
|
srp_record = self.common.get_attributes_from_cinder_config()
|
||||||
self.fake_xml)
|
|
||||||
extra_specs = self.common._set_vmax_extra_specs(
|
extra_specs = self.common._set_vmax_extra_specs(
|
||||||
self.data.vol_type_extra_specs_compr_disabled, srp_record)
|
self.data.vol_type_extra_specs_compr_disabled, srp_record)
|
||||||
ref_extra_specs = deepcopy(self.data.extra_specs_intervals_set)
|
ref_extra_specs = deepcopy(self.data.extra_specs_intervals_set)
|
||||||
@ -4511,16 +4312,20 @@ class VMAXCommonTest(test.TestCase):
|
|||||||
self.assertEqual(ref_extra_specs, extra_specs)
|
self.assertEqual(ref_extra_specs, extra_specs)
|
||||||
|
|
||||||
def test_set_vmax_extra_specs_portgroup_as_spec(self):
|
def test_set_vmax_extra_specs_portgroup_as_spec(self):
|
||||||
srp_record = self.utils.parse_file_to_get_array_map(
|
srp_record = self.common.get_attributes_from_cinder_config()
|
||||||
self.fake_xml)
|
|
||||||
extra_specs = self.common._set_vmax_extra_specs(
|
extra_specs = self.common._set_vmax_extra_specs(
|
||||||
{utils.PORTGROUPNAME: 'extra_spec_pg'}, srp_record)
|
{utils.PORTGROUPNAME: 'extra_spec_pg'}, srp_record)
|
||||||
self.assertEqual('extra_spec_pg', extra_specs[utils.PORTGROUPNAME])
|
self.assertEqual('extra_spec_pg', extra_specs[utils.PORTGROUPNAME])
|
||||||
|
|
||||||
def test_set_vmax_extra_specs_no_portgroup_set(self):
|
def test_set_vmax_extra_specs_no_portgroup_set(self):
|
||||||
fake_xml = FakeXML().create_fake_config_file(
|
srp_record = {'srpName': 'SRP_1',
|
||||||
'test_no_pg_set', '')
|
'RestServerIp': '1.1.1.1',
|
||||||
srp_record = self.utils.parse_file_to_get_array_map(fake_xml)
|
'RestPassword': 'smc',
|
||||||
|
'SSLCert': None,
|
||||||
|
'RestServerPort': 8443,
|
||||||
|
'SSLVerify': False,
|
||||||
|
'RestUserName': 'smc',
|
||||||
|
'SerialNumber': '000197800123'}
|
||||||
self.assertRaises(exception.VolumeBackendAPIException,
|
self.assertRaises(exception.VolumeBackendAPIException,
|
||||||
self.common._set_vmax_extra_specs,
|
self.common._set_vmax_extra_specs,
|
||||||
{}, srp_record)
|
{}, srp_record)
|
||||||
@ -5375,7 +5180,7 @@ class VMAXCommonTest(test.TestCase):
|
|||||||
self.assertEqual(ref_dev_id, src_dev_id1)
|
self.assertEqual(ref_dev_id, src_dev_id1)
|
||||||
self.assertEqual(ref_dev_id, src_dev_id2)
|
self.assertEqual(ref_dev_id, src_dev_id2)
|
||||||
|
|
||||||
def test_get_attributes_from_cinder_config_new(self):
|
def test_get_attributes_from_cinder_config_new_and_old(self):
|
||||||
kwargs_expected = (
|
kwargs_expected = (
|
||||||
{'RestServerIp': '1.1.1.1',
|
{'RestServerIp': '1.1.1.1',
|
||||||
'RestServerPort': 8443,
|
'RestServerPort': 8443,
|
||||||
@ -5386,7 +5191,7 @@ class VMAXCommonTest(test.TestCase):
|
|||||||
'SerialNumber': self.data.array,
|
'SerialNumber': self.data.array,
|
||||||
'srpName': 'SRP_1',
|
'srpName': 'SRP_1',
|
||||||
'PortGroup': self.data.port_group_name_i})
|
'PortGroup': self.data.port_group_name_i})
|
||||||
backup_conf = self.common.configuration
|
old_conf = FakeConfiguration(None, 'CommonTests', 1, 1)
|
||||||
configuration = FakeConfiguration(
|
configuration = FakeConfiguration(
|
||||||
None, 'CommonTests', 1, 1, san_ip='1.1.1.1', san_login='smc',
|
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',
|
vmax_array=self.data.array, vmax_srp='SRP_1', san_password='smc',
|
||||||
@ -5394,30 +5199,7 @@ class VMAXCommonTest(test.TestCase):
|
|||||||
self.common.configuration = configuration
|
self.common.configuration = configuration
|
||||||
kwargs_returned = self.common.get_attributes_from_cinder_config()
|
kwargs_returned = self.common.get_attributes_from_cinder_config()
|
||||||
self.assertEqual(kwargs_expected, kwargs_returned)
|
self.assertEqual(kwargs_expected, kwargs_returned)
|
||||||
self.common.configuration = backup_conf
|
self.common.configuration = old_conf
|
||||||
kwargs = self.common.get_attributes_from_cinder_config()
|
|
||||||
self.assertIsNone(kwargs)
|
|
||||||
|
|
||||||
def test_get_attributes_from_cinder_config_old(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()
|
kwargs = self.common.get_attributes_from_cinder_config()
|
||||||
self.assertIsNone(kwargs)
|
self.assertIsNone(kwargs)
|
||||||
|
|
||||||
@ -5703,11 +5485,11 @@ class VMAXFCTest(test.TestCase):
|
|||||||
self.data = VMAXCommonData()
|
self.data = VMAXCommonData()
|
||||||
|
|
||||||
super(VMAXFCTest, self).setUp()
|
super(VMAXFCTest, self).setUp()
|
||||||
config_group = 'FCTests'
|
|
||||||
volume_utils.get_max_over_subscription_ratio = mock.Mock()
|
volume_utils.get_max_over_subscription_ratio = mock.Mock()
|
||||||
self.fake_xml = FakeXML().create_fake_config_file(
|
self.configuration = FakeConfiguration(
|
||||||
config_group, self.data.port_group_name_f)
|
None, 'FCTests', 1, 1, san_ip='1.1.1.1', san_login='smc',
|
||||||
self.configuration = FakeConfiguration(self.fake_xml, config_group)
|
vmax_array=self.data.array, vmax_srp='SRP_1', san_password='smc',
|
||||||
|
san_api_port=8443, vmax_port_groups=[self.data.port_group_name_i])
|
||||||
rest.VMAXRest._establish_rest_session = mock.Mock(
|
rest.VMAXRest._establish_rest_session = mock.Mock(
|
||||||
return_value=FakeRequestsSession())
|
return_value=FakeRequestsSession())
|
||||||
driver = fc.VMAXFCDriver(configuration=self.configuration)
|
driver = fc.VMAXFCDriver(configuration=self.configuration)
|
||||||
@ -5961,11 +5743,10 @@ class VMAXISCSITest(test.TestCase):
|
|||||||
self.data = VMAXCommonData()
|
self.data = VMAXCommonData()
|
||||||
|
|
||||||
super(VMAXISCSITest, self).setUp()
|
super(VMAXISCSITest, self).setUp()
|
||||||
config_group = 'ISCSITests'
|
configuration = FakeConfiguration(
|
||||||
self.fake_xml = FakeXML().create_fake_config_file(
|
None, 'ISCSITests', 1, 1, san_ip='1.1.1.1', san_login='smc',
|
||||||
config_group, self.data.port_group_name_i)
|
vmax_array=self.data.array, vmax_srp='SRP_1', san_password='smc',
|
||||||
volume_utils.get_max_over_subscription_ratio = mock.Mock()
|
san_api_port=8443, vmax_port_groups=[self.data.port_group_name_i])
|
||||||
configuration = FakeConfiguration(self.fake_xml, config_group)
|
|
||||||
rest.VMAXRest._establish_rest_session = mock.Mock(
|
rest.VMAXRest._establish_rest_session = mock.Mock(
|
||||||
return_value=FakeRequestsSession())
|
return_value=FakeRequestsSession())
|
||||||
driver = iscsi.VMAXISCSIDriver(configuration=configuration)
|
driver = iscsi.VMAXISCSIDriver(configuration=configuration)
|
||||||
@ -7266,9 +7047,6 @@ class VMAXCommonReplicationTest(test.TestCase):
|
|||||||
self.data = VMAXCommonData()
|
self.data = VMAXCommonData()
|
||||||
|
|
||||||
super(VMAXCommonReplicationTest, self).setUp()
|
super(VMAXCommonReplicationTest, self).setUp()
|
||||||
config_group = 'CommonReplicationTests'
|
|
||||||
self.fake_xml = FakeXML().create_fake_config_file(
|
|
||||||
config_group, self.data.port_group_name_f)
|
|
||||||
self.replication_device = {
|
self.replication_device = {
|
||||||
'target_device_id': self.data.remote_array,
|
'target_device_id': self.data.remote_array,
|
||||||
'remote_port_group': self.data.port_group_name_f,
|
'remote_port_group': self.data.port_group_name_f,
|
||||||
@ -7276,16 +7054,21 @@ class VMAXCommonReplicationTest(test.TestCase):
|
|||||||
'rdf_group_label': self.data.rdf_group_name,
|
'rdf_group_label': self.data.rdf_group_name,
|
||||||
'allow_extend': 'True'}
|
'allow_extend': 'True'}
|
||||||
volume_utils.get_max_over_subscription_ratio = mock.Mock()
|
volume_utils.get_max_over_subscription_ratio = mock.Mock()
|
||||||
|
|
||||||
configuration = FakeConfiguration(
|
configuration = FakeConfiguration(
|
||||||
self.fake_xml, config_group,
|
None, 'CommonReplicationTests', 1, 1, san_ip='1.1.1.1',
|
||||||
|
san_login='smc', vmax_array=self.data.array, vmax_srp='SRP_1',
|
||||||
|
san_password='smc', san_api_port=8443,
|
||||||
|
vmax_port_groups=[self.data.port_group_name_f],
|
||||||
replication_device=self.replication_device)
|
replication_device=self.replication_device)
|
||||||
rest.VMAXRest._establish_rest_session = mock.Mock(
|
rest.VMAXRest._establish_rest_session = mock.Mock(
|
||||||
return_value=FakeRequestsSession())
|
return_value=FakeRequestsSession())
|
||||||
driver = fc.VMAXFCDriver(configuration=configuration)
|
driver = fc.VMAXFCDriver(configuration=configuration)
|
||||||
iscsi_fake_xml = FakeXML().create_fake_config_file(
|
|
||||||
config_group, self.data.port_group_name_i)
|
|
||||||
iscsi_config = FakeConfiguration(
|
iscsi_config = FakeConfiguration(
|
||||||
iscsi_fake_xml, config_group,
|
None, 'CommonReplicationTests', 1, 1, san_ip='1.1.1.1',
|
||||||
|
san_login='smc', vmax_array=self.data.array, vmax_srp='SRP_1',
|
||||||
|
san_password='smc', san_api_port=8443,
|
||||||
|
vmax_port_groups=[self.data.port_group_name_i],
|
||||||
replication_device=self.replication_device)
|
replication_device=self.replication_device)
|
||||||
iscsi_driver = iscsi.VMAXISCSIDriver(configuration=iscsi_config)
|
iscsi_driver = iscsi.VMAXISCSIDriver(configuration=iscsi_config)
|
||||||
self.iscsi_common = iscsi_driver.common
|
self.iscsi_common = iscsi_driver.common
|
||||||
@ -7299,8 +7082,8 @@ class VMAXCommonReplicationTest(test.TestCase):
|
|||||||
mock.Mock(
|
mock.Mock(
|
||||||
return_value=self.data.vol_type_extra_specs_rep_enabled))
|
return_value=self.data.vol_type_extra_specs_rep_enabled))
|
||||||
self.extra_specs = deepcopy(self.data.extra_specs_rep_enabled)
|
self.extra_specs = deepcopy(self.data.extra_specs_rep_enabled)
|
||||||
self.extra_specs['retries'] = 0
|
self.extra_specs['retries'] = 1
|
||||||
self.extra_specs['interval'] = 0
|
self.extra_specs['interval'] = 1
|
||||||
self.extra_specs['rep_mode'] = 'Synchronous'
|
self.extra_specs['rep_mode'] = 'Synchronous'
|
||||||
self.async_rep_device = {
|
self.async_rep_device = {
|
||||||
'target_device_id': self.data.remote_array,
|
'target_device_id': self.data.remote_array,
|
||||||
@ -7309,7 +7092,10 @@ class VMAXCommonReplicationTest(test.TestCase):
|
|||||||
'rdf_group_label': self.data.rdf_group_name,
|
'rdf_group_label': self.data.rdf_group_name,
|
||||||
'allow_extend': 'True', 'mode': 'async'}
|
'allow_extend': 'True', 'mode': 'async'}
|
||||||
async_configuration = FakeConfiguration(
|
async_configuration = FakeConfiguration(
|
||||||
self.fake_xml, config_group,
|
None, 'CommonReplicationTests', 1, 1, san_ip='1.1.1.1',
|
||||||
|
san_login='smc', vmax_array=self.data.array, vmax_srp='SRP_1',
|
||||||
|
san_password='smc', san_api_port=8443,
|
||||||
|
vmax_port_groups=[self.data.port_group_name_f],
|
||||||
replication_device=self.async_rep_device)
|
replication_device=self.async_rep_device)
|
||||||
self.async_driver = fc.VMAXFCDriver(configuration=async_configuration)
|
self.async_driver = fc.VMAXFCDriver(configuration=async_configuration)
|
||||||
self.metro_rep_device = {
|
self.metro_rep_device = {
|
||||||
@ -7319,7 +7105,10 @@ class VMAXCommonReplicationTest(test.TestCase):
|
|||||||
'rdf_group_label': self.data.rdf_group_name,
|
'rdf_group_label': self.data.rdf_group_name,
|
||||||
'allow_extend': 'True', 'mode': 'metro'}
|
'allow_extend': 'True', 'mode': 'metro'}
|
||||||
metro_configuration = FakeConfiguration(
|
metro_configuration = FakeConfiguration(
|
||||||
self.fake_xml, config_group,
|
None, 'CommonReplicationTests', 1, 1, san_ip='1.1.1.1',
|
||||||
|
san_login='smc', vmax_array=self.data.array, vmax_srp='SRP_1',
|
||||||
|
san_password='smc', san_api_port=8443,
|
||||||
|
vmax_port_groups=[self.data.port_group_name_f],
|
||||||
replication_device=self.metro_rep_device)
|
replication_device=self.metro_rep_device)
|
||||||
self.metro_driver = fc.VMAXFCDriver(configuration=metro_configuration)
|
self.metro_driver = fc.VMAXFCDriver(configuration=metro_configuration)
|
||||||
|
|
||||||
@ -7521,7 +7310,7 @@ class VMAXCommonReplicationTest(test.TestCase):
|
|||||||
self.data.device_id, volume_name, "5", extra_specs)
|
self.data.device_id, volume_name, "5", extra_specs)
|
||||||
|
|
||||||
def test_set_config_file_get_extra_specs_rep_enabled(self):
|
def test_set_config_file_get_extra_specs_rep_enabled(self):
|
||||||
extra_specs, _, _ = self.common._set_config_file_and_get_extra_specs(
|
extra_specs, _ = self.common._set_config_file_and_get_extra_specs(
|
||||||
self.data.test_volume)
|
self.data.test_volume)
|
||||||
self.assertTrue(extra_specs['replication_enabled'])
|
self.assertTrue(extra_specs['replication_enabled'])
|
||||||
|
|
||||||
@ -7853,8 +7642,7 @@ class VMAXCommonReplicationTest(test.TestCase):
|
|||||||
def test_get_secondary_stats(self):
|
def test_get_secondary_stats(self):
|
||||||
rep_config = self.utils.get_replication_config(
|
rep_config = self.utils.get_replication_config(
|
||||||
[self.replication_device])
|
[self.replication_device])
|
||||||
array_map = self.utils.parse_file_to_get_array_map(
|
array_map = self.common.get_attributes_from_cinder_config()
|
||||||
self.common.pool_info['config_file'])
|
|
||||||
finalarrayinfolist = self.common._get_slo_workload_combinations(
|
finalarrayinfolist = self.common._get_slo_workload_combinations(
|
||||||
array_map)
|
array_map)
|
||||||
array_info = finalarrayinfolist[0]
|
array_info = finalarrayinfolist[0]
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
import ast
|
import ast
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
import math
|
import math
|
||||||
import os.path
|
|
||||||
import random
|
import random
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
@ -41,9 +40,6 @@ LOG = logging.getLogger(__name__)
|
|||||||
|
|
||||||
CONF = cfg.CONF
|
CONF = cfg.CONF
|
||||||
|
|
||||||
CINDER_EMC_CONFIG_FILE = '/etc/cinder/cinder_dell_emc_config.xml'
|
|
||||||
CINDER_EMC_CONFIG_FILE_PREFIX = '/etc/cinder/cinder_dell_emc_config_'
|
|
||||||
CINDER_EMC_CONFIG_FILE_POSTFIX = '.xml'
|
|
||||||
BACKENDNAME = 'volume_backend_name'
|
BACKENDNAME = 'volume_backend_name'
|
||||||
PREFIXBACKENDNAME = 'capabilities:volume_backend_name'
|
PREFIXBACKENDNAME = 'capabilities:volume_backend_name'
|
||||||
|
|
||||||
@ -56,11 +52,6 @@ REPLICATION_ERROR = fields.ReplicationStatus.ERROR
|
|||||||
|
|
||||||
|
|
||||||
vmax_opts = [
|
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',
|
cfg.IntOpt('interval',
|
||||||
default=3,
|
default=3,
|
||||||
help='Use this value to specify '
|
help='Use this value to specify '
|
||||||
@ -137,8 +128,10 @@ class VMAXCommon(object):
|
|||||||
self._get_attributes_from_config()
|
self._get_attributes_from_config()
|
||||||
array_info = self.get_attributes_from_cinder_config()
|
array_info = self.get_attributes_from_cinder_config()
|
||||||
if array_info is None:
|
if array_info is None:
|
||||||
array_info = self.utils.parse_file_to_get_array_map(
|
LOG.error("Unable to get attributes from cinder.conf. Please "
|
||||||
self.pool_info['config_file'])
|
"refer to the current online documentation for correct "
|
||||||
|
"configuration and note that the xml file is no "
|
||||||
|
"longer supported.")
|
||||||
self.rest.set_rest_credentials(array_info)
|
self.rest.set_rest_credentials(array_info)
|
||||||
finalarrayinfolist = self._get_slo_workload_combinations(
|
finalarrayinfolist = self._get_slo_workload_combinations(
|
||||||
array_info)
|
array_info)
|
||||||
@ -146,12 +139,6 @@ class VMAXCommon(object):
|
|||||||
|
|
||||||
def _get_attributes_from_config(self):
|
def _get_attributes_from_config(self):
|
||||||
"""Get relevent details from configuration file."""
|
"""Get relevent details from configuration file."""
|
||||||
if hasattr(self.configuration, 'cinder_dell_emc_config_file'):
|
|
||||||
self.pool_info['config_file'] = (
|
|
||||||
self.configuration.cinder_dell_emc_config_file)
|
|
||||||
else:
|
|
||||||
self.pool_info['config_file'] = (
|
|
||||||
self.configuration.safe_get('cinder_dell_emc_config_file'))
|
|
||||||
self.interval = self.configuration.safe_get('interval')
|
self.interval = self.configuration.safe_get('interval')
|
||||||
self.retries = self.configuration.safe_get('retries')
|
self.retries = self.configuration.safe_get('retries')
|
||||||
self.pool_info['backend_name'] = (
|
self.pool_info['backend_name'] = (
|
||||||
@ -563,8 +550,8 @@ class VMAXCommon(object):
|
|||||||
storage_group_name = OS-<shortHostName>-<srpName>-<shortProtocol>-SG
|
storage_group_name = OS-<shortHostName>-<srpName>-<shortProtocol>-SG
|
||||||
e.g OS-myShortHost-SRP_1-I-SG
|
e.g OS-myShortHost-SRP_1-I-SG
|
||||||
port_group_name = OS-<target>-PG The port_group_name will come from
|
port_group_name = OS-<target>-PG The port_group_name will come from
|
||||||
the EMC configuration xml file.
|
the cinder.conf or as an extra spec on the volume
|
||||||
These are precreated. If the portGroup does not
|
type. These are precreated. If the portGroup does not
|
||||||
exist then an error will be returned to the user
|
exist then an error will be returned to the user
|
||||||
maskingview_name = OS-<shortHostName>-<srpName>-<shortProtocol>-MV
|
maskingview_name = OS-<shortHostName>-<srpName>-<shortProtocol>-MV
|
||||||
e.g OS-myShortHost-SRP_1-I-MV
|
e.g OS-myShortHost-SRP_1-I-MV
|
||||||
@ -939,8 +926,7 @@ class VMAXCommon(object):
|
|||||||
array_reserve_percent)
|
array_reserve_percent)
|
||||||
|
|
||||||
def _set_config_file_and_get_extra_specs(self, volume,
|
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.
|
||||||
|
|
||||||
Given the volume object get the associated volumetype and the
|
Given the volume object get the associated volumetype and the
|
||||||
@ -950,7 +936,7 @@ class VMAXCommon(object):
|
|||||||
:param volume: the volume object including the volume_type_id
|
:param volume: the volume object including the volume_type_id
|
||||||
:param volume_type_id: Optional override of volume.volume_type_id
|
:param volume_type_id: Optional override of volume.volume_type_id
|
||||||
:returns: dict -- the extra specs dict
|
:returns: dict -- the extra specs dict
|
||||||
:returns: string -- configuration file
|
:returns: dict -- QoS specs
|
||||||
"""
|
"""
|
||||||
qos_specs = {}
|
qos_specs = {}
|
||||||
extra_specs = self.utils.get_volumetype_extra_specs(
|
extra_specs = self.utils.get_volumetype_extra_specs(
|
||||||
@ -960,11 +946,8 @@ class VMAXCommon(object):
|
|||||||
res = volume_types.get_volume_type_qos_specs(type_id)
|
res = volume_types.get_volume_type_qos_specs(type_id)
|
||||||
qos_specs = res['qos_specs']
|
qos_specs = res['qos_specs']
|
||||||
|
|
||||||
config_group = None
|
|
||||||
config_file = None
|
|
||||||
# If there are no extra specs then the default case is assumed.
|
# If there are no extra specs then the default case is assumed.
|
||||||
if extra_specs:
|
if extra_specs:
|
||||||
config_group = self.configuration.config_group
|
|
||||||
if extra_specs.get('replication_enabled') == '<is> True':
|
if extra_specs.get('replication_enabled') == '<is> True':
|
||||||
extra_specs[utils.IS_RE] = True
|
extra_specs[utils.IS_RE] = True
|
||||||
if self.rep_config and self.rep_config.get('mode'):
|
if self.rep_config and self.rep_config.get('mode'):
|
||||||
@ -972,10 +955,7 @@ class VMAXCommon(object):
|
|||||||
if self.rep_config and self.rep_config.get(utils.METROBIAS):
|
if self.rep_config and self.rep_config.get(utils.METROBIAS):
|
||||||
extra_specs[utils.METROBIAS] = self.rep_config[
|
extra_specs[utils.METROBIAS] = self.rep_config[
|
||||||
utils.METROBIAS]
|
utils.METROBIAS]
|
||||||
if register_config_file:
|
return extra_specs, qos_specs
|
||||||
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):
|
def _find_device_on_array(self, volume, extra_specs):
|
||||||
"""Given the volume get the VMAX device Id.
|
"""Given the volume get the VMAX device Id.
|
||||||
@ -1126,45 +1106,6 @@ class VMAXCommon(object):
|
|||||||
all_masking_view_list)
|
all_masking_view_list)
|
||||||
return maskingview_list, all_masking_view_list
|
return maskingview_list, all_masking_view_list
|
||||||
|
|
||||||
def _register_config_file_from_config_group(self, config_group_name):
|
|
||||||
"""Given the config group name register the file.
|
|
||||||
|
|
||||||
:param config_group_name: the config group name
|
|
||||||
:returns: string -- configurationFile - name of the configuration file
|
|
||||||
:raises: VolumeBackendAPIException:
|
|
||||||
"""
|
|
||||||
if config_group_name is None:
|
|
||||||
return CINDER_EMC_CONFIG_FILE
|
|
||||||
if hasattr(self.configuration, 'cinder_dell_emc_config_file'):
|
|
||||||
config_file = self.configuration.cinder_dell_emc_config_file
|
|
||||||
else:
|
|
||||||
config_file = (
|
|
||||||
("%(prefix)s%(configGroupName)s%(postfix)s"
|
|
||||||
% {'prefix': CINDER_EMC_CONFIG_FILE_PREFIX,
|
|
||||||
'configGroupName': config_group_name,
|
|
||||||
'postfix': CINDER_EMC_CONFIG_FILE_POSTFIX}))
|
|
||||||
|
|
||||||
# The file saved in self.configuration may not be the correct one,
|
|
||||||
# double check.
|
|
||||||
if config_group_name not in config_file:
|
|
||||||
config_file = (
|
|
||||||
("%(prefix)s%(configGroupName)s%(postfix)s"
|
|
||||||
% {'prefix': CINDER_EMC_CONFIG_FILE_PREFIX,
|
|
||||||
'configGroupName': config_group_name,
|
|
||||||
'postfix': CINDER_EMC_CONFIG_FILE_POSTFIX}))
|
|
||||||
|
|
||||||
if os.path.isfile(config_file):
|
|
||||||
LOG.debug("Configuration file : %(configurationFile)s exists.",
|
|
||||||
{'configurationFile': config_file})
|
|
||||||
else:
|
|
||||||
exception_message = (_(
|
|
||||||
"Configuration file %(configurationFile)s does not exist.")
|
|
||||||
% {'configurationFile': config_file})
|
|
||||||
LOG.error(exception_message)
|
|
||||||
raise exception.VolumeBackendAPIException(data=exception_message)
|
|
||||||
|
|
||||||
return config_file
|
|
||||||
|
|
||||||
def _initial_setup(self, volume, volume_type_id=None):
|
def _initial_setup(self, volume, volume_type_id=None):
|
||||||
"""Necessary setup to accumulate the relevant information.
|
"""Necessary setup to accumulate the relevant information.
|
||||||
|
|
||||||
@ -1180,18 +1121,15 @@ class VMAXCommon(object):
|
|||||||
try:
|
try:
|
||||||
array_info = self.get_attributes_from_cinder_config()
|
array_info = self.get_attributes_from_cinder_config()
|
||||||
if array_info:
|
if array_info:
|
||||||
extra_specs, config_file, qos_specs = (
|
extra_specs, 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(
|
self._set_config_file_and_get_extra_specs(
|
||||||
volume, volume_type_id))
|
volume, volume_type_id))
|
||||||
array_info = self.utils.parse_file_to_get_array_map(
|
else:
|
||||||
self.pool_info['config_file'])
|
|
||||||
if not array_info:
|
|
||||||
exception_message = (_(
|
exception_message = (_(
|
||||||
"Unable to get corresponding record for srp."))
|
"Unable to get corresponding record for srp. Please "
|
||||||
|
"refer to the current online documentation for correct "
|
||||||
|
"configuration and note that the xml file is no longer "
|
||||||
|
"supported."))
|
||||||
raise exception.VolumeBackendAPIException(
|
raise exception.VolumeBackendAPIException(
|
||||||
data=exception_message)
|
data=exception_message)
|
||||||
|
|
||||||
@ -1491,11 +1429,7 @@ class VMAXCommon(object):
|
|||||||
The pool_name extra spec must be set, otherwise a default slo/workload
|
The pool_name extra spec must be set, otherwise a default slo/workload
|
||||||
will be chosen. The portgroup can either be passed as an extra spec
|
will be chosen. The portgroup can either be passed as an extra spec
|
||||||
on the volume type (e.g. 'storagetype:portgroupname = os-pg1-pg'), or
|
on the volume type (e.g. 'storagetype:portgroupname = os-pg1-pg'), or
|
||||||
can be chosen from a list provided in the xml file, e.g.:
|
can be chosen from a list provided in the cinder.conf
|
||||||
<PortGroups>
|
|
||||||
<PortGroup>OS-PORTGROUP1-PG</PortGroup>
|
|
||||||
<PortGroup>OS-PORTGROUP2-PG</PortGroup>
|
|
||||||
</PortGroups>.
|
|
||||||
|
|
||||||
:param extra_specs: extra specifications
|
:param extra_specs: extra specifications
|
||||||
:param pool_record: pool record
|
:param pool_record: pool record
|
||||||
@ -1504,19 +1438,16 @@ class VMAXCommon(object):
|
|||||||
# set extra_specs from pool_record
|
# set extra_specs from pool_record
|
||||||
extra_specs[utils.SRP] = pool_record['srpName']
|
extra_specs[utils.SRP] = pool_record['srpName']
|
||||||
extra_specs[utils.ARRAY] = pool_record['SerialNumber']
|
extra_specs[utils.ARRAY] = pool_record['SerialNumber']
|
||||||
|
try:
|
||||||
if not extra_specs.get(utils.PORTGROUPNAME):
|
if not extra_specs.get(utils.PORTGROUPNAME):
|
||||||
extra_specs[utils.PORTGROUPNAME] = pool_record['PortGroup']
|
extra_specs[utils.PORTGROUPNAME] = pool_record['PortGroup']
|
||||||
if not extra_specs[utils.PORTGROUPNAME]:
|
except Exception:
|
||||||
error_message = (_("Port group name has not been provided - "
|
error_message = (_("Port group name has not been provided - "
|
||||||
"please configure the "
|
"please configure the "
|
||||||
"'storagetype:portgroupname' extra spec on "
|
"'storagetype:portgroupname' extra spec on "
|
||||||
"the volume type, or enter a list of "
|
"the volume type, or enter a list of "
|
||||||
"portgroups to the xml file associated with "
|
"portgroups in the cinder.conf associated with "
|
||||||
"this backend e.g."
|
"this backend."))
|
||||||
"<PortGroups>"
|
|
||||||
" <PortGroup>OS-PORTGROUP1-PG</PortGroup>"
|
|
||||||
" <PortGroup>OS-PORTGROUP2-PG</PortGroup>"
|
|
||||||
"</PortGroups>."))
|
|
||||||
LOG.exception(error_message)
|
LOG.exception(error_message)
|
||||||
raise exception.VolumeBackendAPIException(data=error_message)
|
raise exception.VolumeBackendAPIException(data=error_message)
|
||||||
|
|
||||||
@ -1544,7 +1475,7 @@ class VMAXCommon(object):
|
|||||||
if not workload_from_extra_spec:
|
if not workload_from_extra_spec:
|
||||||
workload_from_extra_spec = 'NONE'
|
workload_from_extra_spec = 'NONE'
|
||||||
LOG.info("Pool_name is not present in the extra_specs "
|
LOG.info("Pool_name is not present in the extra_specs "
|
||||||
"- using slo/ workload from xml file: %(slo)s/%(wl)s.",
|
"- using slo/ workload from cinder.conf: %(slo)s/%(wl)s.",
|
||||||
{'slo': slo_from_extra_spec,
|
{'slo': slo_from_extra_spec,
|
||||||
'wl': workload_from_extra_spec})
|
'wl': workload_from_extra_spec})
|
||||||
|
|
||||||
@ -1558,10 +1489,10 @@ class VMAXCommon(object):
|
|||||||
else:
|
else:
|
||||||
slo_from_extra_spec = 'None'
|
slo_from_extra_spec = 'None'
|
||||||
workload_from_extra_spec = 'NONE'
|
workload_from_extra_spec = 'NONE'
|
||||||
LOG.warning("Pool_name is not present in the extra_specs"
|
LOG.warning("Pool_name is not present in the extra_specs "
|
||||||
"and no slo/ workload information is present "
|
"so no slo/ workload information is present "
|
||||||
"in the xml file - using default slo/ workload "
|
"using default slo/ workload combination: "
|
||||||
"combination: %(slo)s/%(wl)s.",
|
"%(slo)s/%(wl)s.",
|
||||||
{'slo': slo_from_extra_spec,
|
{'slo': slo_from_extra_spec,
|
||||||
'wl': workload_from_extra_spec})
|
'wl': workload_from_extra_spec})
|
||||||
# Standardize slo and workload 'NONE' naming conventions
|
# Standardize slo and workload 'NONE' naming conventions
|
||||||
|
@ -15,9 +15,7 @@
|
|||||||
|
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
import datetime
|
import datetime
|
||||||
from defusedxml import minidom
|
|
||||||
import hashlib
|
import hashlib
|
||||||
import random
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from cinder.objects.group import Group
|
from cinder.objects.group import Group
|
||||||
@ -309,136 +307,6 @@ class VMAXUtils(object):
|
|||||||
max_over_sub_ratio = 20.0
|
max_over_sub_ratio = 20.0
|
||||||
return max_over_sub_ratio
|
return max_over_sub_ratio
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _process_tag(element, tag_name):
|
|
||||||
"""Process the tag to get the value.
|
|
||||||
|
|
||||||
:param element: the parent element
|
|
||||||
:param tag_name: the tag name
|
|
||||||
:returns: nodeValue(can be None)
|
|
||||||
"""
|
|
||||||
node_value = None
|
|
||||||
try:
|
|
||||||
processed_element = element.getElementsByTagName(tag_name)[0]
|
|
||||||
node_value = processed_element.childNodes[0].nodeValue
|
|
||||||
if node_value:
|
|
||||||
node_value = node_value.strip()
|
|
||||||
except IndexError:
|
|
||||||
pass
|
|
||||||
return node_value
|
|
||||||
|
|
||||||
def _get_connection_info(self, rest_element):
|
|
||||||
"""Given the filename get the rest server connection details.
|
|
||||||
|
|
||||||
:param rest_element: the rest element
|
|
||||||
:returns: dict -- connargs - the connection info dictionary
|
|
||||||
:raises: VolumeBackendAPIException
|
|
||||||
"""
|
|
||||||
connargs = {
|
|
||||||
'RestServerIp': (
|
|
||||||
self._process_tag(rest_element, 'RestServerIp')),
|
|
||||||
'RestServerPort': (
|
|
||||||
self._process_tag(rest_element, 'RestServerPort')),
|
|
||||||
'RestUserName': (
|
|
||||||
self._process_tag(rest_element, 'RestUserName')),
|
|
||||||
'RestPassword': (
|
|
||||||
self._process_tag(rest_element, 'RestPassword'))}
|
|
||||||
|
|
||||||
for k, __ in connargs.items():
|
|
||||||
if connargs[k] is None:
|
|
||||||
exception_message = (_(
|
|
||||||
"RestServerIp, RestServerPort, RestUserName, "
|
|
||||||
"RestPassword must have valid values."))
|
|
||||||
LOG.error(exception_message)
|
|
||||||
raise exception.VolumeBackendAPIException(
|
|
||||||
data=exception_message)
|
|
||||||
|
|
||||||
# These can be None
|
|
||||||
connargs['SSLCert'] = self._process_tag(rest_element, 'SSLCert')
|
|
||||||
connargs['SSLVerify'] = (
|
|
||||||
self._process_tag(rest_element, 'SSLVerify'))
|
|
||||||
|
|
||||||
return connargs
|
|
||||||
|
|
||||||
def parse_file_to_get_array_map(self, file_name):
|
|
||||||
"""Parses a file and gets array map.
|
|
||||||
|
|
||||||
Given a file, parse it to get array and pool(srp).
|
|
||||||
|
|
||||||
.. code:: ini
|
|
||||||
|
|
||||||
<EMC>
|
|
||||||
<RestServerIp>10.108.246.202</RestServerIp>
|
|
||||||
<RestServerPort>8443</RestServerPort>
|
|
||||||
<RestUserName>smc</RestUserName>
|
|
||||||
<RestPassword>smc</RestPassword>
|
|
||||||
<SSLCert>/path/client.cert</SSLCert>
|
|
||||||
<SSLVerify>/path/to/certfile.pem</SSLVerify>
|
|
||||||
<PortGroups>
|
|
||||||
<PortGroup>OS-PORTGROUP1-PG</PortGroup>
|
|
||||||
</PortGroups>
|
|
||||||
<Array>000198700439</Array>
|
|
||||||
<SRP>SRP_1</SRP>
|
|
||||||
</EMC>
|
|
||||||
|
|
||||||
: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()
|
|
||||||
my_file.close()
|
|
||||||
dom = minidom.parseString(data)
|
|
||||||
try:
|
|
||||||
connargs = self._get_connection_info(dom)
|
|
||||||
portgroup = self._get_random_portgroup(dom)
|
|
||||||
serialnumber = self._process_tag(dom, 'Array')
|
|
||||||
if serialnumber is None:
|
|
||||||
LOG.error("Array Serial Number must be in the file %(file)s.",
|
|
||||||
{'file': file_name})
|
|
||||||
srp_name = self._process_tag(dom, 'SRP')
|
|
||||||
if srp_name is None:
|
|
||||||
LOG.error("SRP Name must be in the file %(file)s.",
|
|
||||||
{'file': file_name})
|
|
||||||
slo = self._process_tag(dom, 'ServiceLevel')
|
|
||||||
workload = self._process_tag(dom, 'Workload')
|
|
||||||
kwargs = (
|
|
||||||
{'RestServerIp': connargs['RestServerIp'],
|
|
||||||
'RestServerPort': connargs['RestServerPort'],
|
|
||||||
'RestUserName': connargs['RestUserName'],
|
|
||||||
'RestPassword': connargs['RestPassword'],
|
|
||||||
'SSLCert': connargs['SSLCert'],
|
|
||||||
'SSLVerify': connargs['SSLVerify'],
|
|
||||||
'SerialNumber': serialnumber,
|
|
||||||
'srpName': srp_name,
|
|
||||||
'PortGroup': portgroup})
|
|
||||||
if slo is not None:
|
|
||||||
kwargs.update({'ServiceLevel': slo, 'Workload': workload})
|
|
||||||
|
|
||||||
except IndexError:
|
|
||||||
pass
|
|
||||||
return kwargs
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _get_random_portgroup(element):
|
|
||||||
"""Randomly choose a portgroup from list of portgroups.
|
|
||||||
|
|
||||||
:param element: the parent element
|
|
||||||
:returns: the randomly chosen port group
|
|
||||||
"""
|
|
||||||
portgroupelements = element.getElementsByTagName('PortGroup')
|
|
||||||
if portgroupelements and len(portgroupelements) > 0:
|
|
||||||
portgroupnames = [portgroupelement.childNodes[0].nodeValue.strip()
|
|
||||||
for portgroupelement in portgroupelements
|
|
||||||
if portgroupelement.childNodes]
|
|
||||||
portgroupnames = list(set(filter(None, portgroupnames)))
|
|
||||||
pg_len = len(portgroupnames)
|
|
||||||
if pg_len > 0:
|
|
||||||
return portgroupnames[random.randint(0, pg_len - 1)]
|
|
||||||
return None
|
|
||||||
|
|
||||||
def get_temp_snap_name(self, clone_name, source_device_id):
|
def get_temp_snap_name(self, clone_name, source_device_id):
|
||||||
"""Construct a temporary snapshot name for clone operation.
|
"""Construct a temporary snapshot name for clone operation.
|
||||||
|
|
||||||
|
@ -154,9 +154,8 @@ VMAX Driver Integration
|
|||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
For security and backend uniformity, the use of the XML file for VMAX
|
For security and backend uniformity, the use of the XML file for VMAX
|
||||||
backend configuration has been deprecated in Queens. While the xml file
|
backend configuration was deprecated in Queens and removed entirely
|
||||||
usage will still be supported, a warning will be issued on its impending
|
in Rocky.
|
||||||
deprecation.
|
|
||||||
|
|
||||||
+-----------------+------------------------+---------+----------+---------------------------+
|
+-----------------+------------------------+---------+----------+---------------------------+
|
||||||
| VMAX parameter | cinder.conf parameter | Default | Required | Description |
|
| VMAX parameter | cinder.conf parameter | Default | Required | Description |
|
||||||
@ -1182,8 +1181,7 @@ Configure the source and target arrays
|
|||||||
|
|
||||||
#. Configure an SRDF group between the chosen source and target
|
#. Configure an SRDF group between the chosen source and target
|
||||||
arrays for the VMAX cinder driver to use. The source array must correspond
|
arrays for the VMAX cinder driver to use. The source array must correspond
|
||||||
with the 'vmax_array' entry in the cinder.conf (or the ``<Array>`` entry
|
with the 'vmax_array' entry in the cinder.conf.
|
||||||
in the VMAX XML file for legacy setups).
|
|
||||||
#. Select both the director and the ports for the SRDF emulation to use on
|
#. Select both the director and the ports for the SRDF emulation to use on
|
||||||
both sides. Bear in mind that network topology is important when choosing
|
both sides. Bear in mind that network topology is important when choosing
|
||||||
director endpoints. Supported modes are `Synchronous`, `Asynchronous`,
|
director endpoints. Supported modes are `Synchronous`, `Asynchronous`,
|
||||||
|
@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
upgrade:
|
||||||
|
- |
|
||||||
|
VMAX driver - Removed deprecated option ``cinder_dell_emc_config_file``
|
Loading…
x
Reference in New Issue
Block a user