EMC VNX: Add multi-pools support

This commit is to add multi-pools support in EMC VNX driver.

Change-Id: I7c8ce89ddc359d27fce4cafd6d9c4d0b7579ee8f
Implements: blueprint emc-vnx-driver-multipool-support
This commit is contained in:
Jay Xu 2015-12-11 00:58:22 -05:00
parent 969c530986
commit 6da2e7787e
7 changed files with 436 additions and 105 deletions

View File

@ -29,6 +29,7 @@ from manila.share.drivers.emc import plugin_manager as manager
LOG = log.getLogger(__name__)
EMC_NAS_OPTS = [
cfg.StrOpt('emc_nas_login',
help='User name for the EMC server.'),
@ -47,8 +48,10 @@ EMC_NAS_OPTS = [
cfg.StrOpt('emc_nas_server_container',
default='server_2',
help='Container of share servers.'),
cfg.StrOpt('emc_nas_pool_name',
help='EMC pool name.'),
cfg.StrOpt('emc_nas_pool_names',
deprecated_name='emc_nas_pool_name',
default=None,
help='EMC pool names.'),
cfg.StrOpt('emc_nas_root_dir',
help='The root directory where shares will be located.'),
]
@ -118,7 +121,7 @@ class EMCShareDriver(driver.ShareDriver):
def check_for_setup_error(self):
"""Check for setup error."""
pass
self.plugin.check_for_setup_error()
def do_setup(self, context):
"""Any initialization the share driver does while starting."""

View File

@ -283,6 +283,9 @@ class IsilonStorageConnection(base.StorageConnection):
resp = self._isilon_api.request('PUT', url, data=share_params)
resp.raise_for_status()
def check_for_setup_error(self):
"""Check for setup error."""
def connect(self, emc_share_driver, context):
"""Connect to an Isilon cluster."""
self._server = emc_share_driver.configuration.safe_get(

View File

@ -15,6 +15,7 @@
"""VNX backend for the EMC Manila driver."""
import copy
import fnmatch
import random
from oslo_log import log
@ -30,6 +31,7 @@ from manila.share.drivers.emc.plugins import base as driver
from manila.share.drivers.emc.plugins.vnx import constants
from manila.share.drivers.emc.plugins.vnx import object_manager as manager
from manila.share.drivers.emc.plugins.vnx import utils as vnx_utils
from manila.share import utils as share_utils
from manila import utils
VERSION = "2.0.0"
@ -46,8 +48,10 @@ class VNXStorageConnection(driver.StorageConnection):
def __init__(self, *args, **kwargs):
super(VNXStorageConnection, self).__init__(*args, **kwargs)
self.mover_name = None
self.pool_name = None
self.pools = None
self.manager = None
self.pool_conf = None
self.reserved_percentage = None
self.driver_handles_share_servers = True
def create_share(self, context, share, share_server=None):
@ -57,11 +61,20 @@ class VNXStorageConnection(driver.StorageConnection):
share_proto = share['share_proto']
# Validate the share protocol
if share_proto.upper() not in ('NFS', 'CIFS'):
raise exception.InvalidShare(
reason=(_('Invalid NAS protocol supplied: %s.')
% share_proto))
# Get the pool name from share host field
pool_name = share_utils.extract_host(share['host'], level='pool')
if not pool_name:
message = (_("Pool is not available in the share host %s.") %
share['host'])
raise exception.InvalidHost(reason=message)
# Validate share server
self._share_server_validation(share_server)
if share_proto == 'CIFS':
@ -76,7 +89,7 @@ class VNXStorageConnection(driver.StorageConnection):
LOG.error(message)
raise exception.EMCVnxXMLAPIError(err=message)
self._allocate_container(share_name, size, share_server)
self._allocate_container(share_name, size, share_server, pool_name)
if share_proto == 'NFS':
location = self._create_nfs_share(share_name, share_server)
@ -100,14 +113,15 @@ class VNXStorageConnection(driver.StorageConnection):
LOG.error(message)
raise exception.EMCVnxXMLAPIError(err=message)
def _allocate_container(self, share_name, size, share_server):
def _allocate_container(self, share_name, size, share_server, pool_name):
"""Allocate file system for share."""
vdm_name = self._get_share_server_name(share_server)
self._get_context('FileSystem').create(
share_name, size, self.pool_name, vdm_name)
share_name, size, pool_name, vdm_name)
def _allocate_container_from_snapshot(self, share, snapshot, share_server):
def _allocate_container_from_snapshot(self, share, snapshot, share_server,
pool_name):
"""Allocate file system from snapshot."""
vdm_name = self._get_share_server_name(share_server)
@ -116,10 +130,10 @@ class VNXStorageConnection(driver.StorageConnection):
self._get_context('FileSystem').create_from_snapshot(
share['id'], snapshot['id'], snapshot['share_id'],
self.pool_name, vdm_name, interconn_id)
pool_name, vdm_name, interconn_id)
nwe_size = share['size'] * units.Ki
self._get_context('FileSystem').extend(share['id'], self.pool_name,
self._get_context('FileSystem').extend(share['id'], pool_name,
nwe_size)
@vnx_utils.log_enter_exit
@ -170,14 +184,23 @@ class VNXStorageConnection(driver.StorageConnection):
share_proto = share['share_proto']
# Validate the share protocol
if share_proto.upper() not in ('NFS', 'CIFS'):
raise exception.InvalidShare(
reason=(_('Invalid NAS protocol supplied: %s.')
% share_proto))
# Get the pool name from share host field
pool_name = share_utils.extract_host(share['host'], level='pool')
if not pool_name:
message = (_("Pool is not available in the share host %s.") %
share['host'])
raise exception.InvalidHost(reason=message)
self._share_server_validation(share_server)
self._allocate_container_from_snapshot(share, snapshot, share_server)
self._allocate_container_from_snapshot(
share, snapshot, share_server, pool_name)
if share_proto == 'NFS':
self._create_nfs_share(share_name, share_server)
@ -191,9 +214,18 @@ class VNXStorageConnection(driver.StorageConnection):
def create_snapshot(self, context, snapshot, share_server=None):
"""Create snapshot from share."""
share_name = snapshot['share_id']
status, filesystem = self._get_context('FileSystem').get(share_name)
if status != constants.STATUS_OK:
message = (_("File System %s not found.") % share_name)
LOG.error(message)
raise exception.EMCVnxXMLAPIError(err=message)
pool_id = filesystem['pools_id'][0]
self._get_context('Snapshot').create(snapshot['id'],
snapshot['share_id'],
self.pool_name)
pool_id)
def delete_share(self, context, share, share_server=None):
"""Delete a share."""
@ -261,9 +293,17 @@ class VNXStorageConnection(driver.StorageConnection):
"""Ensure that the share is exported."""
def extend_share(self, share, new_size, share_server=None):
# Get the pool name from share host field
pool_name = share_utils.extract_host(share['host'], level='pool')
if not pool_name:
message = (_("Pool is not available in the share host %s.") %
share['host'])
raise exception.InvalidHost(reason=message)
share_name = share['id']
self._get_context('FileSystem').extend(
share_name, self.pool_name, new_size * units.Ki)
share_name, pool_name, new_size * units.Ki)
def allow_access(self, context, share, access, share_server=None):
"""Allow access to a share."""
@ -395,20 +435,7 @@ class VNXStorageConnection(driver.StorageConnection):
def check_for_setup_error(self):
"""Check for setup error."""
pass
def connect(self, emc_share_driver, context):
"""Connect to VNX NAS server."""
self.mover_name = (
emc_share_driver.configuration.emc_nas_server_container)
self.pool_name = emc_share_driver.configuration.emc_nas_pool_name
configuration = emc_share_driver.configuration
self.manager = manager.StorageObjectManager(configuration)
# To verify the input from manila configuration
# To verify the input from Manila configuration
status, out = self._get_context('Mover').get_ref(self.mover_name,
True)
if constants.STATUS_ERROR == status:
@ -417,13 +444,68 @@ class VNXStorageConnection(driver.StorageConnection):
LOG.error(message)
raise exception.InvalidParameterValue(err=message)
status, out = self._get_context('StoragePool').get(self.pool_name,
True)
if constants.STATUS_ERROR == status:
message = (_("Could not find storage pool by name: %s.") %
self.pool_name)
LOG.error(message)
raise exception.InvalidParameterValue(err=message)
self.pools = self._get_managed_storage_pools(self.pool_conf)
def _get_managed_storage_pools(self, pools):
matched_pools = set()
if pools:
# Get the real pools from the backend storage
status, backend_pools = self._get_context('StoragePool').get_all()
if status != constants.STATUS_OK:
message = (_("Failed to get storage pool information. "
"Reason: %s") % backend_pools)
LOG.error(message)
raise exception.EMCVnxXMLAPIError(err=message)
real_pools = set([item for item in backend_pools])
conf_pools = set([item.strip() for item in pools.split(",")])
for pool in real_pools:
for matcher in conf_pools:
if fnmatch.fnmatchcase(pool, matcher):
matched_pools.add(pool)
nonexistent_pools = real_pools.difference(matched_pools)
if not matched_pools:
msg = (_("All the specified storage pools to be managed "
"do not exist. Please check your configuration "
"emc_nas_pool_names in manila.conf. "
"The available pools in the backend are %s") %
",".join(real_pools))
raise exception.InvalidParameterValue(err=msg)
if nonexistent_pools:
LOG.warning(_LW("The following specified storage pools "
"do not exist: %(unexist)s. "
"This host will only manage the storage "
"pools: %(exist)s"),
{'unexist': ",".join(nonexistent_pools),
'exist': ",".join(matched_pools)})
else:
LOG.debug("Storage pools: %s will be managed.",
",".join(matched_pools))
else:
LOG.debug("No storage pool is specified, so all pools "
"in storage system will be managed.")
return matched_pools
def connect(self, emc_share_driver, context):
"""Connect to VNX NAS server."""
self.mover_name = (
emc_share_driver.configuration.emc_nas_server_container)
self.pool_conf = emc_share_driver.configuration.safe_get(
'emc_nas_pool_names')
self.reserved_percentage = emc_share_driver.configuration.safe_get(
'reserved_share_percentage')
if self.reserved_percentage is None:
self.reserved_percentage = 0
configuration = emc_share_driver.configuration
self.manager = manager.StorageObjectManager(configuration)
def update_share_stats(self, stats_dict):
"""Communicate with EMCNASClient to get the stats."""
@ -431,12 +513,58 @@ class VNXStorageConnection(driver.StorageConnection):
self._get_context('Mover').get_ref(self.mover_name, True)
status, pool = self._get_context('StoragePool').get(self.pool_name,
True)
stats_dict['pools'] = []
stats_dict['total_capacity_gb'] = int(pool['total_size'])
stats_dict['free_capacity_gb'] = (
int(pool['total_size']) - int(pool['used_size']))
status, pools = self._get_context('StoragePool').get_all()
for name, pool in pools.items():
if not self.pools or pool['name'] in self.pools:
total_size = float(pool['total_size'])
used_size = float(pool['used_size'])
pool_stat = dict(
pool_name=pool['name'],
total_capacity_gb=total_size,
free_capacity_gb=total_size - used_size,
QoS_support=False,
reserved_percentage=self.reserved_percentage,
)
stats_dict['pools'].append(pool_stat)
if not stats_dict['pools']:
message = _("Failed to update storage pool.")
LOG.error(message)
raise exception.EMCVnxXMLAPIError(err=message)
def get_pool(self, share):
"""Get the pool name of the share."""
share_name = share['id']
status, filesystem = self._get_context('FileSystem').get(share_name)
if status != constants.STATUS_OK:
message = (_("File System %(name)s not found. "
"Reason: %(err)s") %
{'name': share_name, 'err': filesystem})
LOG.error(message)
raise exception.EMCVnxXMLAPIError(err=message)
pool_id = filesystem['pools_id'][0]
# Get the real pools from the backend storage
status, backend_pools = self._get_context('StoragePool').get_all()
if status != constants.STATUS_OK:
message = (_("Failed to get storage pool information. "
"Reason: %s") % backend_pools)
LOG.error(message)
raise exception.EMCVnxXMLAPIError(err=message)
for name, pool_info in backend_pools.items():
if pool_info['id'] == pool_id:
return name
available_pools = [item for item in backend_pools]
message = (_("No matched pool name for share: %(share)s. "
"Available pools: %(pools)s") %
{'share': share_name, 'pools': available_pools})
raise exception.EMCVnxXMLAPIError(err=message)
def get_network_allocations_number(self):
"""Returns number of network allocations for creating VIFs."""

View File

@ -1026,11 +1026,9 @@ class Snapshot(StorageObject):
super(Snapshot, self).__init__(conn, elt_maker, xml_parser, manager)
self.snap_map = dict()
def create(self, name, fs_name, pool_name, ckpt_size=None):
def create(self, name, fs_name, pool_id, ckpt_size=None):
fs_id = self.get_context('FileSystem').get_id(fs_name)
pool_id = self.get_context('StoragePool').get_id(pool_name)
if ckpt_size:
elt_pool = self.elt_maker.StoragePool(
pool=pool_id,

View File

@ -62,6 +62,7 @@ def response(func):
class FakeData(object):
# Share informaiton
share_id = '7cf7c200_d3af_4e05_b87e_9167c95df4f9'
host = 'HostA@BackendB#fake_pool_name'
share_name = share_id
share_size = 10
new_size = 20
@ -769,9 +770,11 @@ class PoolTestData(StorageObjectTestData):
)
@response
def resp_get_succeed(self, name=None):
def resp_get_succeed(self, name=None, id=None):
if not name:
name = self.pool_name
if not id:
id = self.pool_id
return (
'<QueryStatus maxSeverity="ok"/>'
'<StoragePool movers="1 2" memberVolumes="98" storageSystems="1" '
@ -800,7 +803,7 @@ class PoolTestData(StorageObjectTestData):
'potentialAdditionalSize="0" isBackendPool="true"/>'
'</StoragePool>' %
{'name': name,
'id': self.pool_id,
'id': id,
'pool_used_size': self.pool_used_size,
'pool_total_size': self.pool_total_size}
)
@ -1404,7 +1407,6 @@ class FakeEMCShareDriver(object):
self.configuration.append_config_values = mock.Mock(return_value=0)
self.configuration.emc_share_backend = FakeData.emc_share_backend
self.configuration.emc_nas_server_container = FakeData.mover_name
self.configuration.emc_nas_pool_name = FakeData.pool_name
self.configuration.emc_nas_server = FakeData.emc_nas_server
self.configuration.emc_nas_login = FakeData.emc_nas_login
self.configuration.emc_nas_password = FakeData.emc_nas_password
@ -1416,6 +1418,7 @@ CIFS_SHARE = fake_share.fake_share(
size=FakeData.share_size,
share_network_id=FakeData.share_network_id,
share_server_id=FakeData.share_server_id,
host=FakeData.host,
share_proto='CIFS')
NFS_SHARE = fake_share.fake_share(
@ -1424,6 +1427,7 @@ NFS_SHARE = fake_share.fake_share(
size=FakeData.share_size,
share_network_id=FakeData.share_network_id,
share_server_id=FakeData.share_server_id,
host=FakeData.host,
share_proto='NFS')
CIFS_RW_ACCESS = fake_share.fake_access(
@ -1500,6 +1504,4 @@ STATS = dict(
share_backend_name='VNX',
vendor_name='EMC',
storage_protocol='NFS_CIFS',
driver_version='2.0.0,',
total_capacity_gb='unknown',
free_capacity_gb='unknow')
driver_version='2.0.0,')

View File

@ -15,12 +15,14 @@
import copy
import ddt
import mock
from oslo_log import log
from manila import exception
from manila.share.drivers.emc.plugins.vnx import connection
from manila.share.drivers.emc.plugins.vnx import connector
from manila.share.drivers.emc.plugins.vnx import object_manager
from manila import test
from manila.tests import fake_share
from manila.tests.share.drivers.emc.plugins.vnx import fakes
@ -29,17 +31,13 @@ from manila.tests.share.drivers.emc.plugins.vnx import utils
LOG = log.getLogger(__name__)
@ddt.ddt
class StorageConnectionTestCase(test.TestCase):
@mock.patch.object(connector.XMLAPIConnector, "_do_setup", mock.Mock())
def setUp(self):
super(StorageConnectionTestCase, self).setUp()
self.emc_share_driver = fakes.FakeEMCShareDriver()
self.cifs_server_name = fakes.FakeData.vdm_name
self.pool_name = fakes.FakeData.pool_name
self.vdm_name = fakes.FakeData.vdm_name
self.mover_name = fakes.FakeData.mover_name
self.connection = connection.VNXStorageConnection(LOG)
self.pool = fakes.PoolTestData()
@ -53,51 +51,91 @@ class StorageConnectionTestCase(test.TestCase):
self.cifs_server = fakes.CIFSServerTestData()
self.dns = fakes.DNSDomainTestData()
hook = utils.RequestSideEffect()
hook.append(self.mover.resp_get_ref_succeed())
hook.append(self.pool.resp_get_succeed())
with mock.patch.object(connector.XMLAPIConnector, 'request',
mock.Mock(side_effect=hook)):
mock.Mock()):
self.connection.connect(self.emc_share_driver, None)
expected_calls = [
mock.call(self.mover.req_get_ref()),
mock.call(self.pool.req_get()),
]
connector.XMLAPIConnector.request.assert_has_calls(expected_calls)
@mock.patch.object(connector.XMLAPIConnector, "_do_setup", mock.Mock())
def test_connect_with_invalid_mover_name(self):
hook = utils.RequestSideEffect()
hook.append(self.mover.resp_get_error())
with mock.patch.object(connector.XMLAPIConnector, 'request',
mock.Mock(side_effect=hook)):
self.assertRaises(exception.InvalidParameterValue,
self.connection.connect,
self.emc_share_driver, None)
expected_calls = [mock.call(self.mover.req_get_ref())]
connector.XMLAPIConnector.request.assert_has_calls(expected_calls)
@mock.patch.object(connector.XMLAPIConnector, "_do_setup", mock.Mock())
def test_connect_with_invalid_pool_name(self):
def test_check_for_setup_error(self):
hook = utils.RequestSideEffect()
hook.append(self.mover.resp_get_ref_succeed())
xml_req_mock = utils.EMCMock(side_effect=hook)
self.connection.manager.connectors['XML'].request = xml_req_mock
with mock.patch.object(connection.VNXStorageConnection,
'_get_managed_storage_pools',
mock.Mock()):
self.connection.check_for_setup_error()
expected_calls = [mock.call(self.mover.req_get_ref())]
xml_req_mock.assert_has_calls(expected_calls)
def test_check_for_setup_error_with_invalid_mover_name(self):
hook = utils.RequestSideEffect()
hook.append(self.mover.resp_get_error())
xml_req_mock = utils.EMCMock(side_effect=hook)
self.connection.manager.connectors['XML'].request = xml_req_mock
self.assertRaises(exception.InvalidParameterValue,
self.connection.check_for_setup_error)
expected_calls = [mock.call(self.mover.req_get_ref())]
xml_req_mock.assert_has_calls(expected_calls)
@ddt.data({'pool_conf': None,
'real_pools': ['fake_pool', 'nas_pool'],
'matched_pool': set()},
{'pool_conf': '*',
'real_pools': ['fake_pool', 'nas_pool'],
'matched_pool': {'fake_pool', 'nas_pool'}},
{'pool_conf': 'fake_*',
'real_pools': ['fake_pool', 'nas_pool', 'Perf_Pool'],
'matched_pool': {'fake_pool'}},
{'pool_conf': '*pool',
'real_pools': ['fake_pool', 'NAS_Pool', 'Perf_POOL'],
'matched_pool': {'fake_pool'}},
{'pool_conf': 'nas_pool',
'real_pools': ['fake_pool', 'nas_pool', 'perf_pool'],
'matched_pool': {'nas_pool'}})
@ddt.unpack
def test__get_managed_storage_pools(self, pool_conf, real_pools,
matched_pool):
with mock.patch.object(object_manager.StoragePool,
'get_all',
mock.Mock(return_value=('ok', real_pools))):
pool = self.connection._get_managed_storage_pools(pool_conf)
self.assertEqual(matched_pool, pool)
def test__get_managed_storage_pools_failed_to_get_pool_info(self):
hook = utils.RequestSideEffect()
hook.append(self.pool.resp_get_error())
xml_req_mock = utils.EMCMock(side_effect=hook)
self.connection.manager.connectors['XML'].request = xml_req_mock
with mock.patch.object(connector.XMLAPIConnector, 'request',
mock.Mock(side_effect=hook)):
pool_conf = fakes.FakeData.pool_name
self.assertRaises(exception.EMCVnxXMLAPIError,
self.connection._get_managed_storage_pools,
pool_conf)
expected_calls = [mock.call(self.pool.req_get())]
xml_req_mock.assert_has_calls(expected_calls)
@ddt.data(
{'pool_conf': 'fake_*',
'real_pools': ['nas_pool', 'Perf_Pool']},
{'pool_conf': '*pool',
'real_pools': ['NAS_Pool', 'Perf_POOL']},
{'pool_conf': 'nas_pool',
'real_pools': ['fake_pool', 'perf_pool']},
)
@ddt.unpack
def test__get_managed_storage_pools_without_matched_pool(self, pool_conf,
real_pools):
with mock.patch.object(object_manager.StoragePool,
'get_all',
mock.Mock(return_value=('ok', real_pools))):
self.assertRaises(exception.InvalidParameterValue,
self.connection.connect,
self.emc_share_driver, None)
expected_calls = [
mock.call(self.mover.req_get_ref()),
mock.call(self.pool.req_get()),
]
connector.XMLAPIConnector.request.assert_has_calls(expected_calls)
self.connection._get_managed_storage_pools,
pool_conf)
def test_create_cifs_share(self):
share_server = fakes.SHARE_SERVER
@ -107,6 +145,7 @@ class StorageConnectionTestCase(test.TestCase):
hook.append(self.vdm.resp_get_succeed())
hook.append(self.cifs_server.resp_get_succeed(
mover_id=self.vdm.vdm_id, is_vdm=True, join_domain=True))
hook.append(self.pool.resp_get_succeed())
hook.append(self.fs.resp_task_succeed())
hook.append(self.cifs_share.resp_task_succeed())
xml_req_mock = utils.EMCMock(side_effect=hook)
@ -122,6 +161,7 @@ class StorageConnectionTestCase(test.TestCase):
expected_calls = [
mock.call(self.vdm.req_get()),
mock.call(self.cifs_server.req_get(self.vdm.vdm_id)),
mock.call(self.pool.req_get()),
mock.call(self.fs.req_create_on_vdm()),
mock.call(self.cifs_share.req_create(self.vdm.vdm_id)),
]
@ -138,6 +178,7 @@ class StorageConnectionTestCase(test.TestCase):
share = fakes.NFS_SHARE
hook = utils.RequestSideEffect()
hook.append(self.pool.resp_get_succeed())
hook.append(self.vdm.resp_get_succeed())
hook.append(self.fs.resp_task_succeed())
xml_req_mock = utils.EMCMock(side_effect=hook)
@ -151,6 +192,7 @@ class StorageConnectionTestCase(test.TestCase):
location = self.connection.create_share(None, share, share_server)
expected_calls = [
mock.call(self.pool.req_get()),
mock.call(self.vdm.req_get()),
mock.call(self.fs.req_create_on_vdm()),
]
@ -206,6 +248,7 @@ class StorageConnectionTestCase(test.TestCase):
hook.append(self.vdm.resp_get_succeed())
hook.append(self.cifs_server.resp_get_without_interface(
mover_id=self.vdm.vdm_id, is_vdm=True, join_domain=True))
hook.append(self.pool.resp_get_succeed())
hook.append(self.fs.resp_task_succeed())
xml_req_mock = utils.EMCMock(side_effect=hook)
self.connection.manager.connectors['XML'].request = xml_req_mock
@ -217,11 +260,21 @@ class StorageConnectionTestCase(test.TestCase):
expected_calls = [
mock.call(self.vdm.req_get()),
mock.call(self.cifs_server.req_get(self.vdm.vdm_id)),
mock.call(self.pool.req_get()),
mock.call(self.fs.req_create_on_vdm()),
]
xml_req_mock.assert_has_calls(expected_calls)
def test_create_cifs_share_without_pool_name(self):
share_server = fakes.SHARE_SERVER
share = fake_share.fake_share(host='HostA@BackendB',
share_proto='CIFS')
self.assertRaises(exception.InvalidHost,
self.connection.create_share,
None, share, share_server)
def test_create_cifs_share_from_snapshot(self):
share_server = fakes.SHARE_SERVER
share = fakes.CIFS_SHARE
@ -348,6 +401,16 @@ class StorageConnectionTestCase(test.TestCase):
self.connection.create_share_from_snapshot,
None, share, snapshot, share_server)
def test_create_share_from_snapshot_without_pool_name(self):
share_server = fakes.SHARE_SERVER
share = fake_share.fake_share(host='HostA@BackendB',
share_proto='CIFS')
snapshot = fake_share.fake_snapshot()
self.assertRaises(exception.InvalidHost,
self.connection.create_share_from_snapshot,
None, share, snapshot, share_server)
def test_delete_cifs_share(self):
share_server = fakes.SHARE_SERVER
share = fakes.CIFS_SHARE
@ -458,8 +521,8 @@ class StorageConnectionTestCase(test.TestCase):
hook = utils.RequestSideEffect()
hook.append(self.fs.resp_get_succeed())
hook.append(self.pool.resp_get_succeed())
hook.append(self.fs.resp_task_succeed())
xml_req_mock = utils.EMCMock(side_effect=hook)
self.connection.manager.connectors['XML'].request = xml_req_mock
@ -467,10 +530,21 @@ class StorageConnectionTestCase(test.TestCase):
expected_calls = [
mock.call(self.fs.req_get()),
mock.call(self.pool.req_get()),
mock.call(self.fs.req_extend()),
]
xml_req_mock.assert_has_calls(expected_calls)
def test_extend_share_without_pool_name(self):
share_server = fakes.SHARE_SERVER
share = fake_share.fake_share(host='HostA@BackendB',
share_proto='CIFS')
new_size = fakes.FakeData.new_size
self.assertRaises(exception.InvalidHost,
self.connection.extend_share,
share, new_size, share_server)
def test_create_snapshot(self):
share_server = fakes.SHARE_SERVER
snapshot = fake_share.fake_snapshot(
@ -492,6 +566,25 @@ class StorageConnectionTestCase(test.TestCase):
]
xml_req_mock.assert_has_calls(expected_calls)
def test_create_snapshot_with_incorrect_share_info(self):
share_server = fakes.SHARE_SERVER
snapshot = fake_share.fake_snapshot(
id=fakes.FakeData.snapshot_name,
share_id=fakes.FakeData.filesystem_name,
share_name=fakes.FakeData.share_name)
hook = utils.RequestSideEffect()
hook.append(self.fs.resp_get_but_not_found())
xml_req_mock = utils.EMCMock(side_effect=hook)
self.connection.manager.connectors['XML'].request = xml_req_mock
self.assertRaises(exception.EMCVnxXMLAPIError,
self.connection.create_snapshot,
None, snapshot, share_server)
expected_calls = [mock.call(self.fs.req_get())]
xml_req_mock.assert_has_calls(expected_calls)
def test_delete_snapshot(self):
share_server = fakes.SHARE_SERVER
snapshot = fake_share.fake_snapshot(
@ -516,6 +609,7 @@ class StorageConnectionTestCase(test.TestCase):
def test_setup_server(self):
hook = utils.RequestSideEffect()
hook.append(self.vdm.resp_get_but_not_found())
hook.append(self.mover.resp_get_ref_succeed())
hook.append(self.vdm.resp_task_succeed())
hook.append(self.mover.resp_task_succeed())
hook.append(self.mover.resp_task_succeed())
@ -538,6 +632,7 @@ class StorageConnectionTestCase(test.TestCase):
expected_calls = [
mock.call(self.vdm.req_get()),
mock.call(self.mover.req_get_ref()),
mock.call(self.vdm.req_create()),
mock.call(self.mover.req_create_interface(
if_name=if_name_1,
@ -560,6 +655,7 @@ class StorageConnectionTestCase(test.TestCase):
def test_setup_server_with_existing_vdm(self):
hook = utils.RequestSideEffect()
hook.append(self.vdm.resp_get_succeed())
hook.append(self.mover.resp_get_ref_succeed())
hook.append(self.mover.resp_task_succeed())
hook.append(self.mover.resp_task_succeed())
hook.append(self.dns.resp_task_succeed())
@ -580,6 +676,7 @@ class StorageConnectionTestCase(test.TestCase):
expected_calls = [
mock.call(self.vdm.req_get()),
mock.call(self.mover.req_get_ref()),
mock.call(self.mover.req_create_interface(
if_name=if_name_1,
ip=fakes.FakeData.network_allocations_ip1)),
@ -608,6 +705,7 @@ class StorageConnectionTestCase(test.TestCase):
def test_setup_server_without_valid_physical_device(self):
hook = utils.RequestSideEffect()
hook.append(self.vdm.resp_get_but_not_found())
hook.append(self.mover.resp_get_ref_succeed())
hook.append(self.vdm.resp_task_succeed())
hook.append(self.vdm.resp_get_succeed())
hook.append(self.cifs_server.resp_get_without_value())
@ -627,6 +725,7 @@ class StorageConnectionTestCase(test.TestCase):
expected_calls = [
mock.call(self.vdm.req_get()),
mock.call(self.mover.req_get_ref()),
mock.call(self.vdm.req_create()),
mock.call(self.vdm.req_get()),
mock.call(self.cifs_server.req_get(self.vdm.vdm_id)),
@ -643,6 +742,7 @@ class StorageConnectionTestCase(test.TestCase):
def test_setup_server_with_exception(self):
hook = utils.RequestSideEffect()
hook.append(self.vdm.resp_get_but_not_found())
hook.append(self.mover.resp_get_ref_succeed())
hook.append(self.vdm.resp_task_succeed())
hook.append(self.mover.resp_task_succeed())
hook.append(self.mover.resp_task_error())
@ -668,6 +768,7 @@ class StorageConnectionTestCase(test.TestCase):
expected_calls = [
mock.call(self.vdm.req_get()),
mock.call(self.mover.req_get_ref()),
mock.call(self.vdm.req_create()),
mock.call(self.mover.req_create_interface(
if_name=if_name_1,
@ -697,6 +798,7 @@ class StorageConnectionTestCase(test.TestCase):
hook.append(self.cifs_server.resp_task_succeed())
hook.append(self.cifs_server.resp_get_succeed(
mover_id=self.vdm.vdm_id, is_vdm=True, join_domain=False))
hook.append(self.mover.resp_get_ref_succeed())
hook.append(self.mover.resp_task_succeed())
hook.append(self.mover.resp_task_succeed())
hook.append(self.vdm.resp_task_succeed())
@ -718,6 +820,7 @@ class StorageConnectionTestCase(test.TestCase):
mock.call(self.cifs_server.req_modify(
mover_id=self.vdm.vdm_id, is_vdm=True, join_domain=False)),
mock.call(self.cifs_server.req_delete(self.vdm.vdm_id)),
mock.call(self.mover.req_get_ref()),
mock.call(self.mover.req_delete_interface(
fakes.FakeData.network_allocations_ip1)),
mock.call(self.mover.req_delete_interface(
@ -738,6 +841,7 @@ class StorageConnectionTestCase(test.TestCase):
def test_teardown_server_without_security_services(self):
hook = utils.RequestSideEffect()
hook.append(self.vdm.resp_get_succeed())
hook.append(self.mover.resp_get_ref_succeed())
hook.append(self.mover.resp_task_succeed())
hook.append(self.mover.resp_task_succeed())
hook.append(self.vdm.resp_task_succeed())
@ -754,6 +858,7 @@ class StorageConnectionTestCase(test.TestCase):
expected_calls = [
mock.call(self.vdm.req_get()),
mock.call(self.mover.req_get_ref()),
mock.call(self.mover.req_delete_interface(
fakes.FakeData.network_allocations_ip1)),
mock.call(self.mover.req_delete_interface(
@ -791,6 +896,7 @@ class StorageConnectionTestCase(test.TestCase):
hook = utils.RequestSideEffect()
hook.append(self.vdm.resp_get_succeed())
hook.append(self.cifs_server.resp_get_error())
hook.append(self.mover.resp_get_ref_succeed())
hook.append(self.cifs_server.resp_task_succeed())
hook.append(self.cifs_server.resp_get_succeed(
mover_id=self.vdm.vdm_id, is_vdm=True, join_domain=False))
@ -812,6 +918,7 @@ class StorageConnectionTestCase(test.TestCase):
expected_calls = [
mock.call(self.vdm.req_get()),
mock.call(self.cifs_server.req_get(self.vdm.vdm_id)),
mock.call(self.mover.req_get_ref()),
mock.call(self.mover.req_delete_interface(
fakes.FakeData.network_allocations_ip1)),
mock.call(self.mover.req_delete_interface(
@ -833,6 +940,7 @@ class StorageConnectionTestCase(test.TestCase):
mover_id=self.vdm.vdm_id, is_vdm=True, join_domain=True))
hook.append(self.cifs_server.resp_task_error())
hook.append(self.cifs_server.resp_task_succeed())
hook.append(self.mover.resp_get_ref_succeed())
hook.append(self.mover.resp_task_succeed())
hook.append(self.mover.resp_task_succeed())
hook.append(self.vdm.resp_task_succeed())
@ -853,6 +961,7 @@ class StorageConnectionTestCase(test.TestCase):
mock.call(self.cifs_server.req_get(self.vdm.vdm_id)),
mock.call(self.cifs_server.req_modify(self.vdm.vdm_id)),
mock.call(self.cifs_server.req_delete(self.vdm.vdm_id)),
mock.call(self.mover.req_get_ref()),
mock.call(self.mover.req_delete_interface(
fakes.FakeData.network_allocations_ip1)),
mock.call(self.mover.req_delete_interface(
@ -1198,9 +1307,103 @@ class StorageConnectionTestCase(test.TestCase):
]
xml_req_mock.assert_has_calls(expected_calls)
self.assertEqual(fakes.FakeData.pool_total_size,
fakes.STATS['total_capacity_gb'])
for pool in fakes.STATS['pools']:
if pool['pool_name'] == fakes.FakeData.pool_name:
self.assertEqual(fakes.FakeData.pool_total_size,
pool['total_capacity_gb'])
free_size = (fakes.FakeData.pool_total_size -
fakes.FakeData.pool_used_size)
self.assertEqual(free_size, fakes.STATS['free_capacity_gb'])
free_size = (fakes.FakeData.pool_total_size -
fakes.FakeData.pool_used_size)
self.assertEqual(free_size, pool['free_capacity_gb'])
def test_update_share_stats_without_matched_config_pools(self):
self.connection.pools = set('fake_pool')
hook = utils.RequestSideEffect()
hook.append(self.mover.resp_get_ref_succeed())
hook.append(self.pool.resp_get_succeed())
xml_req_mock = utils.EMCMock(side_effect=hook)
self.connection.manager.connectors['XML'].request = xml_req_mock
self.assertRaises(exception.EMCVnxXMLAPIError,
self.connection.update_share_stats,
fakes.STATS)
expected_calls = [
mock.call(self.mover.req_get_ref()),
mock.call(self.pool.req_get()),
]
xml_req_mock.assert_has_calls(expected_calls)
def test_get_pool(self):
share = fakes.CIFS_SHARE
hook = utils.RequestSideEffect()
hook.append(self.fs.resp_get_succeed())
hook.append(self.pool.resp_get_succeed())
xml_req_mock = utils.EMCMock(side_effect=hook)
self.connection.manager.connectors['XML'].request = xml_req_mock
pool_name = self.connection.get_pool(share)
expected_calls = [
mock.call(self.fs.req_get()),
mock.call(self.pool.req_get()),
]
xml_req_mock.assert_has_calls(expected_calls)
self.assertEqual(fakes.FakeData.pool_name, pool_name)
def test_get_pool_failed_to_get_filesystem_info(self):
share = fakes.CIFS_SHARE
hook = utils.RequestSideEffect()
hook.append(self.fs.resp_get_error())
xml_req_mock = utils.EMCMock(side_effect=hook)
self.connection.manager.connectors['XML'].request = xml_req_mock
self.assertRaises(exception.EMCVnxXMLAPIError,
self.connection.get_pool,
share)
expected_calls = [mock.call(self.fs.req_get())]
xml_req_mock.assert_has_calls(expected_calls)
def test_get_pool_failed_to_get_pool_info(self):
share = fakes.CIFS_SHARE
hook = utils.RequestSideEffect()
hook.append(self.fs.resp_get_succeed())
hook.append(self.pool.resp_get_error())
xml_req_mock = utils.EMCMock(side_effect=hook)
self.connection.manager.connectors['XML'].request = xml_req_mock
self.assertRaises(exception.EMCVnxXMLAPIError,
self.connection.get_pool,
share)
expected_calls = [
mock.call(self.fs.req_get()),
mock.call(self.pool.req_get()),
]
xml_req_mock.assert_has_calls(expected_calls)
def test_get_pool_failed_to_find_matched_pool_name(self):
share = fakes.CIFS_SHARE
hook = utils.RequestSideEffect()
hook.append(self.fs.resp_get_succeed())
hook.append(self.pool.resp_get_succeed(name='unmatch_pool_name',
id='unmatch_pool_id'))
xml_req_mock = utils.EMCMock(side_effect=hook)
self.connection.manager.connectors['XML'].request = xml_req_mock
self.assertRaises(exception.EMCVnxXMLAPIError,
self.connection.get_pool,
share)
expected_calls = [
mock.call(self.fs.req_get()),
mock.call(self.pool.req_get()),
]
xml_req_mock.assert_has_calls(expected_calls)

View File

@ -1338,7 +1338,6 @@ class SnapshotTestCase(StorageObjectTestCase):
def test_create_snapshot(self):
self.hook.append(self.fs.resp_get_succeed())
self.hook.append(self.pool.resp_get_succeed())
self.hook.append(self.snap.resp_task_succeed())
context = self.manager.getStorageContext('Snapshot')
@ -1346,18 +1345,16 @@ class SnapshotTestCase(StorageObjectTestCase):
context.create(name=self.snap.snapshot_name,
fs_name=self.fs.filesystem_name,
pool_name=self.pool.pool_name)
pool_id=self.pool.pool_id)
expected_calls = [
mock.call(self.fs.req_get()),
mock.call(self.pool.req_get()),
mock.call(self.snap.req_create()),
]
context.conn['XML'].request.assert_has_calls(expected_calls)
def test_create_snapshot_but_already_exist(self):
self.hook.append(self.fs.resp_get_succeed())
self.hook.append(self.pool.resp_get_succeed())
self.hook.append(self.snap.resp_create_but_already_exist())
context = self.manager.getStorageContext('Snapshot')
@ -1365,19 +1362,17 @@ class SnapshotTestCase(StorageObjectTestCase):
context.create(name=self.snap.snapshot_name,
fs_name=self.fs.filesystem_name,
pool_name=self.pool.pool_name,
pool_id=self.pool.pool_id,
ckpt_size=self.snap.snapshot_size)
expected_calls = [
mock.call(self.fs.req_get()),
mock.call(self.pool.req_get()),
mock.call(self.snap.req_create_with_size()),
]
context.conn['XML'].request.assert_has_calls(expected_calls)
def test_create_snapshot_with_error(self):
self.hook.append(self.fs.resp_get_succeed())
self.hook.append(self.pool.resp_get_succeed())
self.hook.append(self.snap.resp_task_error())
context = self.manager.getStorageContext('Snapshot')
@ -1387,12 +1382,11 @@ class SnapshotTestCase(StorageObjectTestCase):
context.create,
name=self.snap.snapshot_name,
fs_name=self.fs.filesystem_name,
pool_name=self.pool.pool_name,
pool_id=self.pool.pool_id,
ckpt_size=self.snap.snapshot_size)
expected_calls = [
mock.call(self.fs.req_get()),
mock.call(self.pool.req_get()),
mock.call(self.snap.req_create_with_size()),
]
context.conn['XML'].request.assert_has_calls(expected_calls)