EMC VMAX - Oversubscription support
When max_over_subscription_ratio is 2.0 the pool are oversubscribed by a factor of 2, or 200% over subscribed. The reserved_percentage is the high water mark where by the physical remaining space cannot be exceeded. For example, if there is only 4% of physical space left and the reserve percentage is 5, user would not be permitted to provision a volume. This is a safety mechanism to prevent a scenario that a provisioning request failing due to insufficient raw space. Change-Id: I55614d05701d461d4b0b85f6f57c49d98b014641 Implements: blueprint vmax-oversubscription
This commit is contained in:
parent
7a8804aa20
commit
5377ed5810
@ -301,8 +301,11 @@ class EMCVMAXCommonData(object):
|
||||
poolname = 'gold'
|
||||
totalmanagedspace_bits = '1000000000000'
|
||||
subscribedcapacity_bits = '500000000000'
|
||||
remainingmanagedspace_bits = '500000000000'
|
||||
maxsubscriptionpercent = 150
|
||||
totalmanagedspace_gbs = 931
|
||||
subscribedcapacity_gbs = 466
|
||||
subscribedcapacity_gbs = 465
|
||||
remainingmanagedspace_gbs = 465
|
||||
fake_host = 'HostX@Backend#gold+1234567891011'
|
||||
fake_host_v3 = 'HostX@Backend#Bronze+SRP_1+1234567891011'
|
||||
fake_host_2_v3 = 'HostY@Backend#SRP_1+1234567891011'
|
||||
@ -1114,6 +1117,8 @@ class FakeEcomConnection(object):
|
||||
pool['SystemName'] = self.data.storage_system
|
||||
pool['TotalManagedSpace'] = self.data.totalmanagedspace_bits
|
||||
pool['EMCSubscribedCapacity'] = self.data.subscribedcapacity_bits
|
||||
pool['RemainingManagedSpace'] = self.data.remainingmanagedspace_bits
|
||||
pool['EMCMaxSubscriptionPercent'] = self.data.maxsubscriptionpercent
|
||||
return pool
|
||||
|
||||
def _getinstance_replicationgroup(self, objectpath):
|
||||
@ -2843,22 +2848,25 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase):
|
||||
# Bug 1393555 - policy has been deleted by another process.
|
||||
def test_get_capacities_associated_to_policy(self):
|
||||
conn = self.fake_ecom_connection()
|
||||
total_capacity_gb, free_capacity_gb = (
|
||||
(total_capacity_gb, free_capacity_gb, provisioned_capacity_gb,
|
||||
array_max_over_subscription) = (
|
||||
self.driver.common.fast.get_capacities_associated_to_policy(
|
||||
conn, self.data.storage_system, self.data.policyrule))
|
||||
# The capacities associated to the policy have been found.
|
||||
self.assertEqual(self.data.totalmanagedspace_gbs, total_capacity_gb)
|
||||
self.assertEqual(self.data.subscribedcapacity_gbs, free_capacity_gb)
|
||||
self.assertEqual(self.data.remainingmanagedspace_gbs, free_capacity_gb)
|
||||
|
||||
self.driver.common.fast.utils.get_existing_instance = mock.Mock(
|
||||
return_value=None)
|
||||
total_capacity_gb_2, free_capacity_gb_2 = (
|
||||
(total_capacity_gb_2, free_capacity_gb_2, provisioned_capacity_gb_2,
|
||||
array_max_over_subscription_2) = (
|
||||
self.driver.common.fast.get_capacities_associated_to_policy(
|
||||
conn, self.data.storage_system, self.data.policyrule))
|
||||
# The capacities have not been found as the policy has been
|
||||
# removed externally.
|
||||
self.assertEqual(0, total_capacity_gb_2)
|
||||
self.assertEqual(0, free_capacity_gb_2)
|
||||
self.assertEqual(0, provisioned_capacity_gb_2)
|
||||
|
||||
# Bug 1393555 - storage group has been deleted by another process.
|
||||
def test_find_storage_masking_group(self):
|
||||
@ -2994,7 +3002,7 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase):
|
||||
@mock.patch.object(
|
||||
emc_vmax_utils.EMCVMAXUtils,
|
||||
'get_pool_capacities',
|
||||
return_value=(1234, 1200))
|
||||
return_value=(1234, 1200, 1200, 1))
|
||||
@mock.patch.object(
|
||||
emc_vmax_fast.EMCVMAXFast,
|
||||
'is_tiering_policy_enabled',
|
||||
@ -3824,7 +3832,7 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase):
|
||||
@mock.patch.object(
|
||||
emc_vmax_common.EMCVMAXCommon,
|
||||
'_update_pool_stats',
|
||||
return_value={1, 2, 3})
|
||||
return_value={1, 2, 3, 4, 5})
|
||||
def test_ssl_support(self, pool_stats):
|
||||
self.driver.common.update_volume_stats()
|
||||
self.assertTrue(self.driver.common.ecomUseSSL)
|
||||
@ -3955,7 +3963,11 @@ class EMCVMAXISCSIDriverFastTestCase(test.TestCase):
|
||||
@mock.patch.object(
|
||||
emc_vmax_fast.EMCVMAXFast,
|
||||
'get_capacities_associated_to_policy',
|
||||
return_value=(1234, 1200))
|
||||
return_value=(1234, 1200, 1200, 1))
|
||||
@mock.patch.object(
|
||||
emc_vmax_utils.EMCVMAXUtils,
|
||||
'get_pool_capacities',
|
||||
return_value=(1234, 1200, 1200, 1))
|
||||
@mock.patch.object(
|
||||
emc_vmax_fast.EMCVMAXFast,
|
||||
'get_tier_policy_by_name',
|
||||
@ -3972,7 +3984,8 @@ class EMCVMAXISCSIDriverFastTestCase(test.TestCase):
|
||||
mock_storage_system,
|
||||
mock_is_fast_enabled,
|
||||
mock_get_policy,
|
||||
mock_capacity):
|
||||
mock_pool_capacities,
|
||||
mock_capacities_associated_to_policy):
|
||||
self.driver.get_volume_stats(True)
|
||||
|
||||
@mock.patch.object(
|
||||
@ -4591,7 +4604,7 @@ class EMCVMAXFCDriverNoFastTestCase(test.TestCase):
|
||||
@mock.patch.object(
|
||||
emc_vmax_utils.EMCVMAXUtils,
|
||||
'get_pool_capacities',
|
||||
return_value=(1234, 1200))
|
||||
return_value=(1234, 1200, 1200, 1))
|
||||
@mock.patch.object(
|
||||
emc_vmax_fast.EMCVMAXFast,
|
||||
'is_tiering_policy_enabled',
|
||||
@ -5163,7 +5176,11 @@ class EMCVMAXFCDriverFastTestCase(test.TestCase):
|
||||
@mock.patch.object(
|
||||
emc_vmax_fast.EMCVMAXFast,
|
||||
'get_capacities_associated_to_policy',
|
||||
return_value=(1234, 1200))
|
||||
return_value=(1234, 1200, 1200, 1))
|
||||
@mock.patch.object(
|
||||
emc_vmax_utils.EMCVMAXUtils,
|
||||
'get_pool_capacities',
|
||||
return_value=(1234, 1200, 1200, 1))
|
||||
@mock.patch.object(
|
||||
emc_vmax_fast.EMCVMAXFast,
|
||||
'get_tier_policy_by_name',
|
||||
@ -5180,7 +5197,8 @@ class EMCVMAXFCDriverFastTestCase(test.TestCase):
|
||||
mock_storage_system,
|
||||
mock_is_fast_enabled,
|
||||
mock_get_policy,
|
||||
mock_capacity):
|
||||
mock_pool_capacities,
|
||||
mock_capacities_associated_to_policy):
|
||||
self.driver.get_volume_stats(True)
|
||||
|
||||
@mock.patch.object(
|
||||
@ -5734,7 +5752,7 @@ class EMCV3DriverTestCase(test.TestCase):
|
||||
def set_configuration(self):
|
||||
configuration = mock.Mock()
|
||||
configuration.cinder_emc_config_file = self.config_file_path
|
||||
configuration.safe_get.return_value = 'V3'
|
||||
configuration.safe_get.return_value = 3
|
||||
configuration.config_group = 'V3'
|
||||
|
||||
self.stubs.Set(emc_vmax_common.EMCVMAXCommon, '_get_ecom_connection',
|
||||
@ -7944,6 +7962,45 @@ class EMCVMAXUtilsTest(test.TestCase):
|
||||
self.assertFalse(self.driver.utils.is_clone_licensed(
|
||||
conn, capabilityInstanceName, isV3))
|
||||
|
||||
def test_get_pool_capacities(self):
|
||||
conn = FakeEcomConnection()
|
||||
|
||||
(total_capacity_gb, free_capacity_gb, provisioned_capacity_gb,
|
||||
array_max_over_subscription) = (
|
||||
self.driver.utils.get_pool_capacities(
|
||||
conn, self.data.poolname, self.data.storage_system))
|
||||
self.assertEqual(931, total_capacity_gb)
|
||||
self.assertEqual(465, free_capacity_gb)
|
||||
self.assertEqual(465, provisioned_capacity_gb)
|
||||
self.assertEqual(1.5, array_max_over_subscription)
|
||||
|
||||
def test_get_pool_capacities_none_array_max_oversubscription(self):
|
||||
conn = FakeEcomConnection()
|
||||
null_emcmaxsubscriptionpercent = {
|
||||
'TotalManagedSpace': '1000000000000',
|
||||
'ElementName': 'gold',
|
||||
'RemainingManagedSpace': '500000000000',
|
||||
'SystemName': 'SYMMETRIX+000195900551',
|
||||
'CreationClassName': 'Symm_VirtualProvisioningPool',
|
||||
'EMCSubscribedCapacity': '500000000000'}
|
||||
conn.GetInstance = mock.Mock(
|
||||
return_value=null_emcmaxsubscriptionpercent)
|
||||
(total_capacity_gb, free_capacity_gb, provisioned_capacity_gb,
|
||||
array_max_over_subscription) = (
|
||||
self.driver.utils.get_pool_capacities(
|
||||
conn, self.data.poolname, self.data.storage_system))
|
||||
self.assertEqual(65534, array_max_over_subscription)
|
||||
|
||||
def test_get_ratio_from_max_sub_per(self):
|
||||
max_subscription_percent_float = (
|
||||
self.driver.utils.get_ratio_from_max_sub_per(150))
|
||||
self.assertEqual(1.5, max_subscription_percent_float)
|
||||
|
||||
def test_get_ratio_from_max_sub_per_none_value(self):
|
||||
max_subscription_percent_float = (
|
||||
self.driver.utils.get_ratio_from_max_sub_per(str(0)))
|
||||
self.assertIsNone(max_subscription_percent_float)
|
||||
|
||||
|
||||
class EMCVMAXCommonTest(test.TestCase):
|
||||
def setUp(self):
|
||||
|
@ -102,7 +102,10 @@ class EMCVMAXCommon(object):
|
||||
|
||||
pool_info = {'backend_name': None,
|
||||
'config_file': None,
|
||||
'arrays_info': {}}
|
||||
'arrays_info': {},
|
||||
'max_over_subscription_ratio': None,
|
||||
'reserved_percentage': None
|
||||
}
|
||||
|
||||
def __init__(self, prtcl, version, configuration=None):
|
||||
|
||||
@ -137,6 +140,10 @@ class EMCVMAXCommon(object):
|
||||
|
||||
self.pool_info['backend_name'] = (
|
||||
self.configuration.safe_get('volume_backend_name'))
|
||||
self.pool_info['max_over_subscription_ratio'] = (
|
||||
self.configuration.safe_get('max_over_subscription_ratio'))
|
||||
self.pool_info['reserved_percentage'] = (
|
||||
self.configuration.safe_get('reserved_percentage'))
|
||||
LOG.debug(
|
||||
"Updating volume stats on file %(emcConfigFileName)s on "
|
||||
"backend %(backendName)s.",
|
||||
@ -626,20 +633,27 @@ class EMCVMAXCommon(object):
|
||||
"""Retrieve stats info."""
|
||||
pools = []
|
||||
backendName = self.pool_info['backend_name']
|
||||
max_oversubscription_ratio = (
|
||||
self.pool_info['max_over_subscription_ratio'])
|
||||
reservedPercentage = self.pool_info['reserved_percentage']
|
||||
array_max_over_subscription = None
|
||||
array_reserve_percent = None
|
||||
for arrayInfo in self.pool_info['arrays_info']:
|
||||
self._set_ecom_credentials(arrayInfo)
|
||||
# Check what type of array it is
|
||||
isV3 = self.utils.isArrayV3(self.conn, arrayInfo['SerialNumber'])
|
||||
if isV3:
|
||||
location_info, total_capacity_gb, free_capacity_gb = (
|
||||
self._update_srp_stats(arrayInfo))
|
||||
(location_info, total_capacity_gb, free_capacity_gb,
|
||||
provisioned_capacity_gb,
|
||||
array_reserve_percent) = self._update_srp_stats(arrayInfo)
|
||||
poolName = ("%(slo)s+%(poolName)s+%(array)s"
|
||||
% {'slo': arrayInfo['SLO'],
|
||||
'poolName': arrayInfo['PoolName'],
|
||||
'array': arrayInfo['SerialNumber']})
|
||||
else:
|
||||
# This is V2
|
||||
location_info, total_capacity_gb, free_capacity_gb = (
|
||||
(location_info, total_capacity_gb, free_capacity_gb,
|
||||
provisioned_capacity_gb, array_max_over_subscription) = (
|
||||
self._update_pool_stats(backendName, arrayInfo))
|
||||
poolName = ("%(poolName)s+%(array)s"
|
||||
% {'poolName': arrayInfo['PoolName'],
|
||||
@ -648,10 +662,25 @@ class EMCVMAXCommon(object):
|
||||
pool = {'pool_name': poolName,
|
||||
'total_capacity_gb': total_capacity_gb,
|
||||
'free_capacity_gb': free_capacity_gb,
|
||||
'reserved_percentage': 0,
|
||||
'provisioned_capacity_gb': provisioned_capacity_gb,
|
||||
'QoS_support': False,
|
||||
'location_info': location_info,
|
||||
'consistencygroup_support': True}
|
||||
'consistencygroup_support': True,
|
||||
'thin_provisioning_support': True,
|
||||
'thick_provisioning_support': False,
|
||||
'max_over_subscription_ratio': max_oversubscription_ratio
|
||||
}
|
||||
if array_max_over_subscription:
|
||||
pool['max_over_subscription_ratio'] = (
|
||||
self.utils.override_ratio(
|
||||
max_oversubscription_ratio,
|
||||
array_max_over_subscription))
|
||||
|
||||
if array_reserve_percent and (
|
||||
array_reserve_percent > reservedPercentage):
|
||||
pool['reserved_percentage'] = array_reserve_percent
|
||||
else:
|
||||
pool['reserved_percentage'] = reservedPercentage
|
||||
pools.append(pool)
|
||||
|
||||
data = {'vendor_name': "EMC",
|
||||
@ -662,6 +691,7 @@ class EMCVMAXCommon(object):
|
||||
# Use zero capacities here so we always use a pool.
|
||||
'total_capacity_gb': 0,
|
||||
'free_capacity_gb': 0,
|
||||
'provisioned_capacity_gb': 0,
|
||||
'reserved_percentage': 0,
|
||||
'pools': pools}
|
||||
|
||||
@ -674,20 +704,24 @@ class EMCVMAXCommon(object):
|
||||
:returns: location_info
|
||||
:returns: totalManagedSpaceGbs
|
||||
:returns: remainingManagedSpaceGbs
|
||||
:returns: provisionedManagedSpaceGbs
|
||||
:returns: array_reserve_percent
|
||||
"""
|
||||
|
||||
totalManagedSpaceGbs, remainingManagedSpaceGbs = (
|
||||
self.provisionv3.get_srp_pool_stats(self.conn,
|
||||
arrayInfo))
|
||||
(totalManagedSpaceGbs, remainingManagedSpaceGbs,
|
||||
provisionedManagedSpaceGbs, array_reserve_percent) = (
|
||||
self.provisionv3.get_srp_pool_stats(self.conn, arrayInfo))
|
||||
|
||||
LOG.info(_LI(
|
||||
"Capacity stats for SRP pool %(poolName)s on array "
|
||||
"%(arrayName)s total_capacity_gb=%(total_capacity_gb)lu, "
|
||||
"free_capacity_gb=%(free_capacity_gb)lu"),
|
||||
"free_capacity_gb=%(free_capacity_gb)lu, "
|
||||
"provisioned_capacity_gb=%(provisioned_capacity_gb)lu"),
|
||||
{'poolName': arrayInfo['PoolName'],
|
||||
'arrayName': arrayInfo['SerialNumber'],
|
||||
'total_capacity_gb': totalManagedSpaceGbs,
|
||||
'free_capacity_gb': remainingManagedSpaceGbs})
|
||||
'free_capacity_gb': remainingManagedSpaceGbs,
|
||||
'provisioned_capacity_gb': provisionedManagedSpaceGbs})
|
||||
|
||||
location_info = ("%(arrayName)s#%(poolName)s#%(slo)s#%(workload)s"
|
||||
% {'arrayName': arrayInfo['SerialNumber'],
|
||||
@ -695,7 +729,9 @@ class EMCVMAXCommon(object):
|
||||
'slo': arrayInfo['SLO'],
|
||||
'workload': arrayInfo['Workload']})
|
||||
|
||||
return location_info, totalManagedSpaceGbs, remainingManagedSpaceGbs
|
||||
return (location_info, totalManagedSpaceGbs,
|
||||
remainingManagedSpaceGbs, provisionedManagedSpaceGbs,
|
||||
array_reserve_percent)
|
||||
|
||||
def retype(self, ctxt, volume, new_type, diff, host):
|
||||
"""Migrate volume to another host using retype.
|
||||
@ -3193,7 +3229,8 @@ class EMCVMAXCommon(object):
|
||||
|
||||
:param backendName: the backend name
|
||||
:param arrayInfo: the arrayInfo
|
||||
:returns: location_info, total_capacity_gb, free_capacity_gb
|
||||
:returns: location_info, total_capacity_gb, free_capacity_gb,
|
||||
provisioned_capacity_gb
|
||||
"""
|
||||
|
||||
if arrayInfo['FastPolicy']:
|
||||
@ -3216,7 +3253,8 @@ class EMCVMAXCommon(object):
|
||||
|
||||
if (arrayInfo['FastPolicy'] is not None and
|
||||
isTieringPolicySupported is True): # FAST enabled
|
||||
total_capacity_gb, free_capacity_gb = (
|
||||
(total_capacity_gb, free_capacity_gb, provisioned_capacity_gb,
|
||||
array_max_over_subscription) = (
|
||||
self.fast.get_capacities_associated_to_policy(
|
||||
self.conn, arrayInfo['SerialNumber'],
|
||||
arrayInfo['FastPolicy']))
|
||||
@ -3229,7 +3267,8 @@ class EMCVMAXCommon(object):
|
||||
'total_capacity_gb': total_capacity_gb,
|
||||
'free_capacity_gb': free_capacity_gb})
|
||||
else: # NON-FAST
|
||||
total_capacity_gb, free_capacity_gb = (
|
||||
(total_capacity_gb, free_capacity_gb, provisioned_capacity_gb,
|
||||
array_max_over_subscription) = (
|
||||
self.utils.get_pool_capacities(self.conn,
|
||||
arrayInfo['PoolName'],
|
||||
arrayInfo['SerialNumber']))
|
||||
@ -3247,7 +3286,8 @@ class EMCVMAXCommon(object):
|
||||
'poolName': arrayInfo['PoolName'],
|
||||
'policyName': arrayInfo['FastPolicy']})
|
||||
|
||||
return location_info, total_capacity_gb, free_capacity_gb
|
||||
return (location_info, total_capacity_gb, free_capacity_gb,
|
||||
provisioned_capacity_gb, array_max_over_subscription)
|
||||
|
||||
def _set_v2_extra_specs(self, extraSpecs, poolRecord):
|
||||
"""Set the VMAX V2 extra specs.
|
||||
|
@ -697,14 +697,19 @@ class EMCVMAXFast(object):
|
||||
:param policyName: the name of policy rule, a string value
|
||||
:returns: int -- total capacity in GB of all pools associated with
|
||||
the policy
|
||||
:returns: int -- (total capacity-EMCSubscribedCapacity) in GB of all
|
||||
pools associated with the policy
|
||||
:returns: int -- real physical capacity in GB of all pools
|
||||
available to be used
|
||||
:returns: int -- (Provisioned capacity-EMCSubscribedCapacity) in GB
|
||||
is the the capacity that has been provisioned
|
||||
:returns: int -- the maximum oversubscription ration
|
||||
"""
|
||||
policyInstanceName = self.get_tier_policy_by_name(
|
||||
conn, arrayName, policyName)
|
||||
|
||||
total_capacity_gb = 0
|
||||
allocated_capacity_gb = 0
|
||||
provisioned_capacity_gb = 0
|
||||
free_capacity_gb = 0
|
||||
array_max_over_subscription = None
|
||||
|
||||
tierInstanceNames = self.get_associated_tier_from_tier_policy(
|
||||
conn, policyInstanceName)
|
||||
@ -726,17 +731,25 @@ class EMCVMAXFast(object):
|
||||
break
|
||||
total_capacity_gb += self.utils.convert_bits_to_gbs(
|
||||
storagePoolInstance['TotalManagedSpace'])
|
||||
allocated_capacity_gb += self.utils.convert_bits_to_gbs(
|
||||
provisioned_capacity_gb += self.utils.convert_bits_to_gbs(
|
||||
storagePoolInstance['EMCSubscribedCapacity'])
|
||||
free_capacity_gb += self.utils.convert_bits_to_gbs(
|
||||
storagePoolInstance['RemainingManagedSpace'])
|
||||
try:
|
||||
array_max_over_subscription = (
|
||||
self.utils.get_ratio_from_max_sub_per(
|
||||
storagePoolInstance['EMCMaxSubscriptionPercent']))
|
||||
except KeyError:
|
||||
array_max_over_subscription = 65534
|
||||
LOG.debug(
|
||||
"PolicyName:%(policyName)s, pool: %(poolInstanceName)s, "
|
||||
"allocated_capacity_gb = %(allocated_capacity_gb)lu.",
|
||||
"provisioned_capacity_gb = %(provisioned_capacity_gb)lu.",
|
||||
{'policyName': policyName,
|
||||
'poolInstanceName': poolInstanceName,
|
||||
'allocated_capacity_gb': allocated_capacity_gb})
|
||||
'provisioned_capacity_gb': provisioned_capacity_gb})
|
||||
|
||||
free_capacity_gb = total_capacity_gb - allocated_capacity_gb
|
||||
return (total_capacity_gb, free_capacity_gb)
|
||||
return (total_capacity_gb, free_capacity_gb,
|
||||
provisioned_capacity_gb, array_max_over_subscription)
|
||||
|
||||
def get_or_create_default_storage_group(
|
||||
self, conn, controllerConfigService, fastPolicyName,
|
||||
|
@ -69,7 +69,7 @@ class EMCVMAXFCDriver(driver.FibreChannelDriver):
|
||||
- Operations and timeout issues (bug #1538214)
|
||||
2.4.0 - EMC VMAX - locking SG for concurrent threads (bug #1554634)
|
||||
- SnapVX licensing checks for VMAX3 (bug #1587017)
|
||||
|
||||
- VMAX oversubscription Support (blueprint vmax-oversubscription)
|
||||
"""
|
||||
|
||||
VERSION = "2.4.0"
|
||||
|
@ -75,6 +75,7 @@ class EMCVMAXISCSIDriver(driver.ISCSIDriver):
|
||||
- Operations and timeout issues (bug #1538214)
|
||||
2.4.0 - EMC VMAX - locking SG for concurrent threads (bug #1554634)
|
||||
- SnapVX licensing checks for VMAX3 (bug #1587017)
|
||||
- VMAX oversubscription Support (blueprint vmax-oversubscription)
|
||||
|
||||
"""
|
||||
|
||||
|
@ -704,9 +704,13 @@ class EMCVMAXProvisionV3(object):
|
||||
:param arrayInfo: the array dict
|
||||
:returns: totalCapacityGb
|
||||
:returns: remainingCapacityGb
|
||||
:returns: subscribedCapacityGb
|
||||
:returns: array_reserve_percent
|
||||
"""
|
||||
totalCapacityGb = -1
|
||||
remainingCapacityGb = -1
|
||||
subscribedCapacityGb = -1
|
||||
array_reserve_percent = -1
|
||||
storageSystemInstanceName = self.utils.find_storageSystem(
|
||||
conn, arrayInfo['SerialNumber'])
|
||||
|
||||
@ -735,6 +739,15 @@ class EMCVMAXProvisionV3(object):
|
||||
remainingCapacityGb = (
|
||||
self.utils.convert_bits_to_gbs(
|
||||
remainingManagedSpace))
|
||||
elif properties[0] == 'EMCSubscribedCapacity':
|
||||
cimProperties = properties[1]
|
||||
subscribedManagedSpace = cimProperties.value
|
||||
subscribedCapacityGb = (
|
||||
self.utils.convert_bits_to_gbs(
|
||||
subscribedManagedSpace))
|
||||
elif properties[0] == 'EMCPercentReservedCapacity':
|
||||
cimProperties = properties[1]
|
||||
array_reserve_percent = int(cimProperties.value)
|
||||
except Exception:
|
||||
pass
|
||||
remainingSLOCapacityGb = (
|
||||
@ -751,7 +764,8 @@ class EMCVMAXProvisionV3(object):
|
||||
"not be what you expect."),
|
||||
{'remainingCapacityGb': remainingCapacityGb})
|
||||
|
||||
return totalCapacityGb, remainingCapacityGb
|
||||
return (totalCapacityGb, remainingCapacityGb, subscribedCapacityGb,
|
||||
array_reserve_percent)
|
||||
|
||||
def _get_remaining_slo_capacity_wlp(self, conn, srpPoolInstanceName,
|
||||
arrayInfo, systemName):
|
||||
|
@ -978,7 +978,8 @@ class EMCVMAXUtils(object):
|
||||
:param conn: connection to the ecom server
|
||||
:param poolName: string value of the storage pool name
|
||||
:param storageSystemName: the storage system name
|
||||
:returns: tuple -- (total_capacity_gb, free_capacity_gb)
|
||||
:returns: tuple -- (total_capacity_gb, free_capacity_gb,
|
||||
provisioned_capacity_gb)
|
||||
"""
|
||||
LOG.debug(
|
||||
"Retrieving capacity for pool %(poolName)s on array %(array)s.",
|
||||
@ -997,10 +998,17 @@ class EMCVMAXUtils(object):
|
||||
poolInstanceName, LocalOnly=False)
|
||||
total_capacity_gb = self.convert_bits_to_gbs(
|
||||
storagePoolInstance['TotalManagedSpace'])
|
||||
allocated_capacity_gb = self.convert_bits_to_gbs(
|
||||
provisioned_capacity_gb = self.convert_bits_to_gbs(
|
||||
storagePoolInstance['EMCSubscribedCapacity'])
|
||||
free_capacity_gb = total_capacity_gb - allocated_capacity_gb
|
||||
return (total_capacity_gb, free_capacity_gb)
|
||||
free_capacity_gb = self.convert_bits_to_gbs(
|
||||
storagePoolInstance['RemainingManagedSpace'])
|
||||
try:
|
||||
array_max_over_subscription = self.get_ratio_from_max_sub_per(
|
||||
storagePoolInstance['EMCMaxSubscriptionPercent'])
|
||||
except KeyError:
|
||||
array_max_over_subscription = 65534
|
||||
return (total_capacity_gb, free_capacity_gb,
|
||||
provisioned_capacity_gb, array_max_over_subscription)
|
||||
|
||||
def get_pool_by_name(self, conn, storagePoolName, storageSystemName):
|
||||
"""Returns the instance name associated with a storage pool name.
|
||||
@ -2598,3 +2606,42 @@ class EMCVMAXUtils(object):
|
||||
sgInstanceName = self.find_storage_masking_group(
|
||||
conn, controllerConfigService, storageGroupName)
|
||||
return storageGroupName, controllerConfigService, sgInstanceName
|
||||
|
||||
def get_ratio_from_max_sub_per(self, max_subscription_percent):
|
||||
"""Get ratio from max subscription percent if it exists.
|
||||
|
||||
Check if the max subscription is set on the pool, if it is convert
|
||||
it to a ratio.
|
||||
|
||||
:param max_subscription_percent: max subscription percent
|
||||
:returns: max_over_subscription_ratio
|
||||
"""
|
||||
if max_subscription_percent == '0':
|
||||
return None
|
||||
try:
|
||||
max_subscription_percent_int = int(max_subscription_percent)
|
||||
except ValueError:
|
||||
LOG.error(_LE("Cannot convert max subscription percent to int."))
|
||||
return None
|
||||
return float(max_subscription_percent_int) / 100
|
||||
|
||||
def override_ratio(self, max_over_sub_ratio, max_sub_ratio_from_per):
|
||||
"""Override ratio if necessary
|
||||
|
||||
The over subscription ratio will be overriden if the max subscription
|
||||
percent is less than the user supplied max oversubscription ratio.
|
||||
|
||||
:param max_over_sub_ratio: user supplied over subscription ratio
|
||||
:param max_sub_ratio_from_per: property on the pool
|
||||
:returns: max_over_sub_ratio
|
||||
"""
|
||||
if max_over_sub_ratio:
|
||||
try:
|
||||
max_over_sub_ratio = max(float(max_over_sub_ratio),
|
||||
float(max_sub_ratio_from_per))
|
||||
except ValueError:
|
||||
max_over_sub_ratio = float(max_sub_ratio_from_per)
|
||||
elif max_sub_ratio_from_per:
|
||||
max_over_sub_ratio = float(max_sub_ratio_from_per)
|
||||
|
||||
return max_over_sub_ratio
|
||||
|
@ -0,0 +1,3 @@
|
||||
---
|
||||
features:
|
||||
- Added oversubscription support in the VMAX driver
|
Loading…
Reference in New Issue
Block a user