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.transports = fake_pyxcli_exceptions
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()
sys.modules['pyxcli'] = pyxcli_client

View File

@ -126,6 +126,8 @@ REPLICA_PARAMS = {
'san_password': cryptish.encrypt(REPLICA_PASSWORD),
'san_clustername': REPLICA_POOL
}
TEST_POOL = [
{'name': 'WTF32', 'size': 10026, 'empty_space': 6925}]
class XIVProxyTest(test.TestCase):
@ -189,6 +191,25 @@ class XIVProxyTest(test.TestCase):
self.assertRaises(test_mock.cinder.exception.InvalidParameterValue,
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."
"XCLIClient")
@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, {})
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):
"""Create volume should call xcli with the correct parameters"""
driver = mock.MagicMock()

View File

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

View File

@ -57,7 +57,7 @@ SYNC = 'sync'
ASYNC = 'async'
SYNC_TIMEOUT = 300
SYNCHED_STATES = ['synchronized', 'rpo ok']
PYXCLI_VERSION = '1.1.5'
PYXCLI_VERSION = '1.1.6'
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': "
"%(error)s.")
INCOMPATIBLE_PYXCLI = _('Incompatible pyxcli found. Required: %(required)s '
INCOMPATIBLE_PYXCLI = _('Incompatible pyxcli found. Mininum: %(required)s '
'Found: %(found)s')
@ -104,8 +104,8 @@ class XIVProxy(proxy.IBMStorageProxy):
"""Proxy between the Cinder Volume and Spectrum Accelerate Storage.
Supports IBM XIV, Spectrum Accelerate, A9000, A9000R
Version: 2.1.0
Required pyxcli version: 1.1.5
Version: 2.3.0
Required pyxcli version: 1.1.6
.. code:: text
@ -113,6 +113,7 @@ class XIVProxy(proxy.IBMStorageProxy):
2.1.0 - Support Consistency groups through Generic volume groups
- Support XIV/A9000 Volume independent QoS
- Support groups replication
2.3.0 - Support Report backend state
"""
@ -140,7 +141,7 @@ class XIVProxy(proxy.IBMStorageProxy):
def setup(self, context):
msg = ''
if pyxcli:
if pyxcli.version != PYXCLI_VERSION:
if pyxcli.version < PYXCLI_VERSION:
msg = (INCOMPATIBLE_PYXCLI %
{'required': PYXCLI_VERSION,
'found': pyxcli.version
@ -184,7 +185,7 @@ class XIVProxy(proxy.IBMStorageProxy):
if remote_id:
self.ibm_storage_remote_cli = self._init_xcli(remote_id)
self._event_service_start()
self._update_stats()
self._get_pool()
LOG.info("IBM Storage %(common_ver)s "
"xiv_proxy %(proxy_ver)s. ",
{'common_ver': self.full_version,
@ -1569,6 +1570,8 @@ class XIVProxy(proxy.IBMStorageProxy):
if self.driver:
backend_name = self.driver.configuration.safe_get(
'volume_backend_name')
self.meta['stat']['reserved_percentage'] = (
self.driver.configuration.safe_get('reserved_percentage'))
self.meta['stat']["volume_backend_name"] = (
backend_name or '%s_%s_%s_%s' % (
strings.XIV_BACKEND_PREFIX,
@ -1591,33 +1594,7 @@ class XIVProxy(proxy.IBMStorageProxy):
'pool': self.storage_info[storage.FLAG_KEYS['storage_pool']]
}))
pools = self._call_xiv_xcli(
"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')
self._retrieve_pool_stats(self.meta)
if self.targets:
self.meta['stat']['replication_enabled'] = True
@ -1632,6 +1609,46 @@ class XIVProxy(proxy.IBMStorageProxy):
LOG.debug("Exiting XIVProxy::_update_stats: %(stat)s",
{'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
def create_cloned_volume(self, volume, src_vref):
"""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.