Merge "IBM XIV: Report backend state in service list"

This commit is contained in:
Zuul 2018-06-11 21:20:08 +00:00 committed by Gerrit Code Review
commit c0a6d72c9f
5 changed files with 99 additions and 35 deletions

View File

@ -26,7 +26,7 @@ pyxcli_client.events = mock.Mock()
pyxcli_client.mirroring = mock.Mock() pyxcli_client.mirroring = mock.Mock()
pyxcli_client.transports = fake_pyxcli_exceptions pyxcli_client.transports = fake_pyxcli_exceptions
pyxcli_client.mirroring.cg_recovery_manager = mock.Mock() pyxcli_client.mirroring.cg_recovery_manager = mock.Mock()
pyxcli_client.version = '1.1.5' pyxcli_client.version = '1.1.6'
pyxcli_client.mirroring.mirrored_entities = mock.Mock() pyxcli_client.mirroring.mirrored_entities = mock.Mock()
sys.modules['pyxcli'] = pyxcli_client sys.modules['pyxcli'] = pyxcli_client

View File

@ -126,6 +126,8 @@ REPLICA_PARAMS = {
'san_password': cryptish.encrypt(REPLICA_PASSWORD), 'san_password': cryptish.encrypt(REPLICA_PASSWORD),
'san_clustername': REPLICA_POOL 'san_clustername': REPLICA_POOL
} }
TEST_POOL = [
{'name': 'WTF32', 'size': 10026, 'empty_space': 6925}]
class XIVProxyTest(test.TestCase): class XIVProxyTest(test.TestCase):
@ -189,6 +191,25 @@ class XIVProxyTest(test.TestCase):
self.assertRaises(test_mock.cinder.exception.InvalidParameterValue, self.assertRaises(test_mock.cinder.exception.InvalidParameterValue,
p.setup, {}) p.setup, {})
@mock.patch("cinder.volume.drivers.ibm.ibm_storage.xiv_proxy.client."
"XCLIClient")
def test_setup_should_fail_if_pool_is_invalid(self, mock_xcli):
"""Setup should raise exception if pool is invalid"""
driver = mock.MagicMock()
driver.VERSION = "VERSION"
p = self.proxy(
self.default_storage_info,
mock.MagicMock(),
test_mock.cinder.exception,
driver)
cmd = mock_xcli.connect_multiendpoint_ssl.return_value.cmd
cmd.pool_list.return_value.as_list = []
self.assertRaises(test_mock.cinder.exception.VolumeBackendAPIException,
p.setup, {})
@mock.patch("cinder.volume.drivers.ibm.ibm_storage.xiv_proxy.client." @mock.patch("cinder.volume.drivers.ibm.ibm_storage.xiv_proxy.client."
"XCLIClient") "XCLIClient")
@mock.patch("cinder.volume.drivers.ibm.ibm_storage.xiv_proxy.socket." @mock.patch("cinder.volume.drivers.ibm.ibm_storage.xiv_proxy.socket."
@ -338,6 +359,26 @@ class XIVProxyTest(test.TestCase):
self.assertRaises(exception.VolumeBackendAPIException, p.setup, {}) self.assertRaises(exception.VolumeBackendAPIException, p.setup, {})
def test_get_volume_stats(self):
driver = mock.MagicMock()
driver.VERSION = "VERSION"
p = self.proxy(
self.default_storage_info,
mock.MagicMock(),
test_mock.cinder.exception,
driver)
p.ibm_storage_cli = mock.MagicMock()
p.ibm_storage_cli.cmd.pool_list.return_value.as_list = TEST_POOL
stats = p.get_volume_stats()
self.assertEqual("up", stats['backend_state'])
p.ibm_storage_cli.cmd.pool_list.return_value.as_list = None
stats = p.get_volume_stats(refresh=True)
self.assertEqual("down", stats['backend_state'])
def test_create_volume_should_call_xcli(self): def test_create_volume_should_call_xcli(self):
"""Create volume should call xcli with the correct parameters""" """Create volume should call xcli with the correct parameters"""
driver = mock.MagicMock() driver = mock.MagicMock()

View File

@ -77,9 +77,10 @@ class IBMStorageDriver(san.SanDriver,
2.1.0 - Support Consistency groups through Generic volume groups 2.1.0 - Support Consistency groups through Generic volume groups
- Support XIV/A9000 Volume independent QoS - Support XIV/A9000 Volume independent QoS
- Support Consistency groups replication - Support Consistency groups replication
2.3.0 - Support Report backend state
""" """
VERSION = "2.1.0" VERSION = "2.3.0"
# ThirdPartySystems wiki page # ThirdPartySystems wiki page
CI_WIKI_NAME = "IBM_STORAGE_CI" CI_WIKI_NAME = "IBM_STORAGE_CI"

View File

@ -57,7 +57,7 @@ SYNC = 'sync'
ASYNC = 'async' ASYNC = 'async'
SYNC_TIMEOUT = 300 SYNC_TIMEOUT = 300
SYNCHED_STATES = ['synchronized', 'rpo ok'] SYNCHED_STATES = ['synchronized', 'rpo ok']
PYXCLI_VERSION = '1.1.5' PYXCLI_VERSION = '1.1.6'
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -96,7 +96,7 @@ DELETE_VOLUME_BASE_ERROR = ("Unable to delete volume '%(volume)s': "
MANAGE_VOLUME_BASE_ERROR = _("Unable to manage the volume '%(volume)s': " MANAGE_VOLUME_BASE_ERROR = _("Unable to manage the volume '%(volume)s': "
"%(error)s.") "%(error)s.")
INCOMPATIBLE_PYXCLI = _('Incompatible pyxcli found. Required: %(required)s ' INCOMPATIBLE_PYXCLI = _('Incompatible pyxcli found. Mininum: %(required)s '
'Found: %(found)s') 'Found: %(found)s')
@ -104,8 +104,8 @@ class XIVProxy(proxy.IBMStorageProxy):
"""Proxy between the Cinder Volume and Spectrum Accelerate Storage. """Proxy between the Cinder Volume and Spectrum Accelerate Storage.
Supports IBM XIV, Spectrum Accelerate, A9000, A9000R Supports IBM XIV, Spectrum Accelerate, A9000, A9000R
Version: 2.1.0 Version: 2.3.0
Required pyxcli version: 1.1.5 Required pyxcli version: 1.1.6
.. code:: text .. code:: text
@ -113,6 +113,7 @@ class XIVProxy(proxy.IBMStorageProxy):
2.1.0 - Support Consistency groups through Generic volume groups 2.1.0 - Support Consistency groups through Generic volume groups
- Support XIV/A9000 Volume independent QoS - Support XIV/A9000 Volume independent QoS
- Support groups replication - Support groups replication
2.3.0 - Support Report backend state
""" """
@ -140,7 +141,7 @@ class XIVProxy(proxy.IBMStorageProxy):
def setup(self, context): def setup(self, context):
msg = '' msg = ''
if pyxcli: if pyxcli:
if pyxcli.version != PYXCLI_VERSION: if pyxcli.version < PYXCLI_VERSION:
msg = (INCOMPATIBLE_PYXCLI % msg = (INCOMPATIBLE_PYXCLI %
{'required': PYXCLI_VERSION, {'required': PYXCLI_VERSION,
'found': pyxcli.version 'found': pyxcli.version
@ -184,7 +185,7 @@ class XIVProxy(proxy.IBMStorageProxy):
if remote_id: if remote_id:
self.ibm_storage_remote_cli = self._init_xcli(remote_id) self.ibm_storage_remote_cli = self._init_xcli(remote_id)
self._event_service_start() self._event_service_start()
self._update_stats() self._get_pool()
LOG.info("IBM Storage %(common_ver)s " LOG.info("IBM Storage %(common_ver)s "
"xiv_proxy %(proxy_ver)s. ", "xiv_proxy %(proxy_ver)s. ",
{'common_ver': self.full_version, {'common_ver': self.full_version,
@ -1569,6 +1570,8 @@ class XIVProxy(proxy.IBMStorageProxy):
if self.driver: if self.driver:
backend_name = self.driver.configuration.safe_get( backend_name = self.driver.configuration.safe_get(
'volume_backend_name') 'volume_backend_name')
self.meta['stat']['reserved_percentage'] = (
self.driver.configuration.safe_get('reserved_percentage'))
self.meta['stat']["volume_backend_name"] = ( self.meta['stat']["volume_backend_name"] = (
backend_name or '%s_%s_%s_%s' % ( backend_name or '%s_%s_%s_%s' % (
strings.XIV_BACKEND_PREFIX, strings.XIV_BACKEND_PREFIX,
@ -1591,33 +1594,7 @@ class XIVProxy(proxy.IBMStorageProxy):
'pool': self.storage_info[storage.FLAG_KEYS['storage_pool']] 'pool': self.storage_info[storage.FLAG_KEYS['storage_pool']]
})) }))
pools = self._call_xiv_xcli( self._retrieve_pool_stats(self.meta)
"pool_list",
pool=self.storage_info[storage.FLAG_KEYS['storage_pool']]).as_list
if len(pools) != 1:
LOG.error(
"_update_stats: Pool %(pool)s not available on storage",
{'pool': self.storage_info[storage.FLAG_KEYS['storage_pool']]})
return
pool = pools[0]
# handle different fields in pool_list between Gen3 and BR
soft_size = pool.get('soft_size')
if soft_size is None:
soft_size = pool.get('size')
hard_size = 0
else:
hard_size = pool.hard_size
self.meta['stat']['total_capacity_gb'] = int(soft_size)
self.meta['stat']['free_capacity_gb'] = int(
pool.get('empty_space_soft', pool.get('empty_space')))
self.meta['stat']['reserved_percentage'] = (
self.driver.configuration.safe_get('reserved_percentage'))
self.meta['stat']['consistent_group_snapshot_enabled'] = True
# thin/thick provision
self.meta['stat']['thin_provision'] = ('True' if soft_size > hard_size
else 'False')
if self.targets: if self.targets:
self.meta['stat']['replication_enabled'] = True self.meta['stat']['replication_enabled'] = True
@ -1632,6 +1609,46 @@ class XIVProxy(proxy.IBMStorageProxy):
LOG.debug("Exiting XIVProxy::_update_stats: %(stat)s", LOG.debug("Exiting XIVProxy::_update_stats: %(stat)s",
{'stat': self.meta['stat']}) {'stat': self.meta['stat']})
@proxy._trace_time
def _get_pool(self):
pools = self._call_xiv_xcli(
"pool_list", pool=self.storage_info[
storage.FLAG_KEYS['storage_pool']]).as_list
if not pools:
msg = (_(
"Pool %(pool)s not available on storage") %
{'pool': self.storage_info[storage.FLAG_KEYS['storage_pool']]})
LOG.error(msg)
raise self.meta['exception'].VolumeBackendAPIException(data=msg)
return pools
def _retrieve_pool_stats(self, data):
try:
pools = self._get_pool()
pool = pools[0]
data['stat']['pool_name'] = pool.get('name')
# handle different fields in pool_list between Gen3 and BR
soft_size = pool.get('soft_size')
if soft_size is None:
soft_size = pool.get('size')
hard_size = 0
else:
hard_size = pool.hard_size
data['stat']['total_capacity_gb'] = int(soft_size)
data['stat']['free_capacity_gb'] = int(
pool.get('empty_space_soft', pool.get('empty_space')))
# thin/thick provision
data['stat']['thin_provisioning_support'] = (
'True' if soft_size > hard_size else 'False')
data['stat']['backend_state'] = 'up'
except Exception as e:
data['stat']['total_capacity_gb'] = 0
data['stat']['free_capacity_gb'] = 0
data['stat']['thin_provision'] = False
data['stat']['backend_state'] = 'down'
error = self._get_code_and_status_or_message(e)
LOG.error(error)
@proxy._trace_time @proxy._trace_time
def create_cloned_volume(self, volume, src_vref): def create_cloned_volume(self, volume, src_vref):
"""Create cloned volume.""" """Create cloned volume."""

View File

@ -0,0 +1,5 @@
---
features:
- |
Added flag 'backend_state: up/down' which will give backend state info in
service list.