Merge "IBM XIV: Report backend state in service list"
This commit is contained in:
commit
c0a6d72c9f
@ -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
|
||||||
|
@ -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()
|
||||||
|
@ -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"
|
||||||
|
@ -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."""
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Added flag 'backend_state: up/down' which will give backend state info in
|
||||||
|
service list.
|
Loading…
Reference in New Issue
Block a user