From b3aee0a201abb68cb0495263e2af93fee639b155 Mon Sep 17 00:00:00 2001 From: Mark Sturdevant Date: Fri, 27 Feb 2015 01:12:02 -0800 Subject: [PATCH] HP 3PAR use one filestore per tenant Using one filestore per tenant allows more shares to be created on an array. The original behavior of one filestore per share can still be used with the hp3par_fstore_per_share=True configuration (default is False). Change-Id: I17a8ee138eef0157819ea33c74a43c30ee644817 Implements: blueprint hp3par-filestore-per-tenant --- manila/share/drivers/hp/hp_3par_driver.py | 24 +- manila/share/drivers/hp/hp_3par_mediator.py | 298 ++++++++---- .../drivers/hp/test_hp_3par_constants.py | 10 +- .../share/drivers/hp/test_hp_3par_driver.py | 99 ++-- .../share/drivers/hp/test_hp_3par_mediator.py | 433 +++++++++++++++--- 5 files changed, 654 insertions(+), 210 deletions(-) diff --git a/manila/share/drivers/hp/hp_3par_driver.py b/manila/share/drivers/hp/hp_3par_driver.py index 0534709b53..b020f7e43b 100644 --- a/manila/share/drivers/hp/hp_3par_driver.py +++ b/manila/share/drivers/hp/hp_3par_driver.py @@ -59,6 +59,9 @@ HP3PAR_OPTS = [ cfg.StrOpt('hp3par_share_ip_address', default='', help="The IP address for shares not using a share server"), + cfg.BoolOpt('hp3par_fstore_per_share', + default=False, + help="Use one filestore per share"), cfg.BoolOpt('hp3par_debug', default=False, help="Enable HTTP debugging to 3PAR"), @@ -105,6 +108,7 @@ class HP3ParShareDriver(driver.ShareDriver): hp3par_san_login=self.configuration.hp3par_san_login, hp3par_san_password=self.configuration.hp3par_san_password, hp3par_san_ssh_port=self.configuration.hp3par_san_ssh_port, + hp3par_fstore_per_share=self.configuration.hp3par_fstore_per_share, ssh_conn_timeout=self.configuration.ssh_conn_timeout, ) @@ -170,6 +174,7 @@ class HP3ParShareDriver(driver.ShareDriver): protocol = share['share_proto'] path = self._hp3par.create_share( + share['project_id'], share['id'], protocol, self.fpg, self.vfs, @@ -188,7 +193,9 @@ class HP3ParShareDriver(driver.ShareDriver): path = self._hp3par.create_share_from_snapshot( share['id'], protocol, + snapshot['share']['project_id'], snapshot['share']['id'], + snapshot['share']['share_proto'], snapshot['id'], self.fpg, self.vfs @@ -199,7 +206,8 @@ class HP3ParShareDriver(driver.ShareDriver): def delete_share(self, context, share, share_server=None): """Deletes share and its fstore.""" - self._hp3par.delete_share(share['id'], + self._hp3par.delete_share(share['project_id'], + share['id'], share['share_proto'], self.fpg, self.vfs) @@ -207,7 +215,9 @@ class HP3ParShareDriver(driver.ShareDriver): def create_snapshot(self, context, snapshot, share_server=None): """Creates a snapshot of a share.""" - self._hp3par.create_snapshot(snapshot['share']['id'], + self._hp3par.create_snapshot(snapshot['share']['project_id'], + snapshot['share']['id'], + snapshot['share']['share_proto'], snapshot['id'], self.fpg, self.vfs) @@ -215,7 +225,9 @@ class HP3ParShareDriver(driver.ShareDriver): def delete_snapshot(self, context, snapshot, share_server=None): """Deletes a snapshot of a share.""" - self._hp3par.delete_snapshot(snapshot['share']['id'], + self._hp3par.delete_snapshot(snapshot['share']['project_id'], + snapshot['share']['id'], + snapshot['share']['share_proto'], snapshot['id'], self.fpg, self.vfs) @@ -225,7 +237,8 @@ class HP3ParShareDriver(driver.ShareDriver): def allow_access(self, context, share, access, share_server=None): """Allow access to the share.""" - self._hp3par.allow_access(share['id'], + self._hp3par.allow_access(share['project_id'], + share['id'], share['share_proto'], access['access_type'], access['access_to'], @@ -234,7 +247,8 @@ class HP3ParShareDriver(driver.ShareDriver): def deny_access(self, context, share, access, share_server=None): """Deny access to the share.""" - self._hp3par.deny_access(share['id'], + self._hp3par.deny_access(share['project_id'], + share['id'], share['share_proto'], access['access_type'], access['access_to'], diff --git a/manila/share/drivers/hp/hp_3par_mediator.py b/manila/share/drivers/hp/hp_3par_mediator.py index 81412f461f..f05c2c82d7 100644 --- a/manila/share/drivers/hp/hp_3par_mediator.py +++ b/manila/share/drivers/hp/hp_3par_mediator.py @@ -24,7 +24,6 @@ import six from manila import exception from manila.i18n import _ -from manila.i18n import _LI from manila.openstack.common import log as logging hp3parclient = importutils.try_import("hp3parclient") @@ -51,6 +50,7 @@ class HP3ParMediator(object): self.hp3par_san_password = kwargs.get('hp3par_san_password') self.hp3par_san_ssh_port = kwargs.get('hp3par_san_ssh_port') self.hp3par_san_private_key = kwargs.get('hp3par_san_private_key') + self.hp3par_fstore_per_share = kwargs.get('hp3par_fstore_per_share') self.ssh_conn_timeout = kwargs.get('ssh_conn_timeout') self._client = None @@ -132,13 +132,22 @@ class HP3ParMediator(object): return protocol @staticmethod - def ensure_prefix(id): - if id.startswith('osf-'): - return id - else: - return 'osf-%s' % id + def other_protocol(share_proto): + """Given 'nfs' or 'smb' (or equivalent) return the other one.""" + protocol = HP3ParMediator.ensure_supported_protocol(share_proto) + return 'nfs' if protocol == 'smb' else 'smb' - def create_share(self, share_id, share_proto, fpg, vfs, + @staticmethod + def ensure_prefix(uid, protocol=None): + if uid.startswith('osf-'): + return uid + elif protocol: + return 'osf-%s-%s' % ( + HP3ParMediator.ensure_supported_protocol(protocol), uid) + else: + return 'osf-%s' % uid + + def create_share(self, project_id, share_id, share_proto, fpg, vfs, fstore=None, sharedir=None, readonly=False, size=None): """Create the share and return its path. @@ -146,6 +155,7 @@ class HP3ParMediator(object): called locally from create_share_from_snapshot(). The optional parameters allow re-use. + :param project_id: The tenant ID. :param share_id: The share-id with or without osf- prefix. :param share_proto: The protocol (to map to smb or nfs) :param fpg: The file provisioning group @@ -162,7 +172,11 @@ class HP3ParMediator(object): share_name = self.ensure_prefix(share_id) if not fstore: - fstore = share_name + if self.hp3par_fstore_per_share: + fstore = share_name + else: + fstore = self.ensure_prefix(project_id, protocol) + try: result = self._client.createfstore( vfs, fstore, fpg=fpg, @@ -175,11 +189,26 @@ class HP3ParMediator(object): raise exception.ShareBackendException(msg) if size: + if self.hp3par_fstore_per_share: + hcapacity = six.text_type(size * units.Ki) + scapacity = hcapacity + else: + hard_size_mb = size * units.Ki + soft_size_mb = hard_size_mb + result = self._client.getfsquota( + fpg=fpg, vfs=vfs, fstore=fstore) + LOG.debug("getfsquota result=%s", result) + quotas = result['members'] + if len(quotas) == 1: + hard_size_mb += int(quotas[0].get('hardBlock', '0')) + soft_size_mb += int(quotas[0].get('softBlock', '0')) + hcapacity = six.text_type(hard_size_mb) + scapacity = six.text_type(soft_size_mb) + try: - size_str = six.text_type(size) result = self._client.setfsquota( vfs, fpg=fpg, fstore=fstore, - scapacity=size_str, hcapacity=size_str) + scapacity=scapacity, hcapacity=hcapacity) LOG.debug("setfsquota result=%s", result) except Exception as e: msg = (_('Failed to setfsquota on %(fstore)s: %(e)s') % @@ -187,6 +216,9 @@ class HP3ParMediator(object): LOG.exception(msg) raise exception.ShareBackendException(msg) + if not (sharedir or self.hp3par_fstore_per_share): + sharedir = share_name + try: if protocol == 'nfs': if readonly: @@ -239,30 +271,45 @@ class HP3ParMediator(object): else: return result['members'][0]['shareName'] - def create_share_from_snapshot(self, share_id, share_proto, orig_share_id, + def create_share_from_snapshot(self, share_id, share_proto, + orig_project_id, orig_share_id, orig_proto, snapshot_id, fpg, vfs): - share_name = self.ensure_prefix(share_id) - orig_share_name = self.ensure_prefix(orig_share_id) - fstore = orig_share_name + protocol = self.ensure_supported_protocol(share_proto) snapshot_tag = self.ensure_prefix(snapshot_id) - snapshots = self.get_snapshots(fstore, snapshot_tag, fpg, vfs) + orig_share_name = self.ensure_prefix(orig_share_id) - if len(snapshots) != 1: + snapshot = self._find_fsnap(orig_project_id, + orig_share_name, + orig_proto, + snapshot_tag, + fpg, + vfs) + + if not snapshot: msg = (_('Failed to create share from snapshot for ' - 'FPG/VFS/fstore/tag %(fpg)s/%(vfs)s/%(fstore)s/%(tag)s.' - ' Expected to find 1 snapshot, found %(count)s.') % - {'fpg': fpg, 'vfs': vfs, 'fstore': fstore, - 'tag': snapshot_tag, 'count': len(snapshots)}) + 'FPG/VFS/tag %(fpg)s/%(vfs)s/%(tag)s. ' + 'Snapshot not found.') % + { + 'fpg': fpg, + 'vfs': vfs, + 'tag': snapshot_tag}) LOG.exception(msg) raise exception.ShareBackendException(msg) - snapshot = snapshots[0] - sharedir = '.snapshot/%s' % snapshot['snapName'] + fstore = snapshot['fstoreName'] + share_name = self.ensure_prefix(share_id) + if fstore == orig_share_name: + # No subdir for original share created with fstore_per_share + sharedir = '.snapshot/%s' % snapshot['snapName'] + else: + sharedir = '.snapshot/%s/%s' % (snapshot['snapName'], + orig_share_name) return self.create_share( + orig_project_id, share_name, - share_proto, + protocol, fpg, vfs, fstore=fstore, @@ -270,11 +317,12 @@ class HP3ParMediator(object): readonly=True, ) - def delete_share(self, share_id, share_proto, fpg, vfs): + def delete_share(self, project_id, share_id, share_proto, fpg, vfs): - share_name = self.ensure_prefix(share_id) - fstore = self.get_fstore(share_id, share_proto, fpg, vfs) protocol = self.ensure_supported_protocol(share_proto) + share_name = self.ensure_prefix(share_id) + fstore = self._find_fstore(project_id, share_name, protocol, fpg, vfs, + allow_cross_protocol=True) if not fstore: # Share does not exist. @@ -289,13 +337,14 @@ class HP3ParMediator(object): LOG.exception(msg) raise exception.ShareBackendException(message=msg) - try: - self._client.removefstore(vfs, fstore, fpg=fpg) - except Exception as e: - msg = (_('Failed to remove fstore %(fstore)s: %(e)s') % - {'fstore': fstore, 'e': six.text_type(e)}) - LOG.exception(msg) - raise exception.ShareBackendException(message=msg) + if fstore == share_name: + try: + self._client.removefstore(vfs, fstore, fpg=fpg) + except Exception as e: + msg = (_('Failed to remove fstore %(fstore)s: %(e)s') % + {'fstore': fstore, 'e': six.text_type(e)}) + LOG.exception(msg) + raise exception.ShareBackendException(message=msg) def get_vfs_name(self, fpg): return self.get_vfs(fpg)['vfsname'] @@ -331,10 +380,33 @@ class HP3ParMediator(object): return result['members'][0] - def create_snapshot(self, orig_share_id, snapshot_id, fpg, vfs): + def create_snapshot(self, orig_project_id, orig_share_id, orig_share_proto, + snapshot_id, fpg, vfs): """Creates a snapshot of a share.""" - fstore = self.ensure_prefix(orig_share_id) + fshare = self._find_fshare(orig_project_id, + orig_share_id, + orig_share_proto, + fpg, + vfs) + + if not fshare: + msg = (_('Failed to create snapshot for FPG/VFS/fshare ' + '%(fpg)s/%(vfs)s/%(fshare)s: Failed to find fshare.') % + {'fpg': fpg, 'vfs': vfs, 'fshare': orig_share_id}) + LOG.exception(msg) + raise exception.ShareBackendException(msg) + + sharedir = fshare.get('shareDir') + if sharedir and sharedir.startswith('.snapshot'): + msg = (_('Failed to create snapshot for FPG/VFS/fshare ' + '%(fpg)s/%(vfs)s/%(fshare)s: Share is a read-only ' + 'share of an existing snapshot.') % + {'fpg': fpg, 'vfs': vfs, 'fshare': orig_share_id}) + LOG.exception(msg) + raise exception.ShareBackendException(msg) + + fstore = fshare.get('fstoreName') snapshot_tag = self.ensure_prefix(snapshot_id) try: result = self._client.createfsnap( @@ -350,41 +422,20 @@ class HP3ParMediator(object): LOG.exception(msg) raise exception.ShareBackendException(msg) - def get_snapshots(self, orig_share_id, snapshot_tag, fpg, vfs): - fstore = self.ensure_prefix(orig_share_id) - try: - pattern = '*_%s' % snapshot_tag - result = self._client.getfsnap( - pattern, fpg=fpg, vfs=vfs, fstore=fstore, pat=True) - - LOG.debug("getfsnap result=%s", result) - - except Exception as e: - msg = (_('Failed to get snapshot for FPG/VFS/fstore/tag ' - '%(fpg)s/%(vfs)s/%(fstore)s/%(tag)s: %(e)s') % - {'fpg': fpg, 'vfs': vfs, 'fstore': fstore, - 'tag': snapshot_tag, 'e': six.text_type(e)}) - LOG.exception(msg) - raise exception.ShareBackendException(msg) - - if result['total'] == 0: - LOG.info((_LI('Found zero snapshots for FPG/VFS/fstore/tag ' - '%(fpg)s/%(vfs)s/%(fstore)s/%(tag)s.') % - {'fpg': fpg, 'vfs': vfs, 'fstore': fstore, - 'tag': snapshot_tag})) - - return result['members'] - - def delete_snapshot(self, orig_share_id, snapshot_id, fpg, vfs): + def delete_snapshot(self, orig_project_id, orig_share_id, orig_proto, + snapshot_id, fpg, vfs): """Deletes a snapshot of a share.""" - fstore = self.ensure_prefix(orig_share_id) snapshot_tag = self.ensure_prefix(snapshot_id) - snapshots = self.get_snapshots(fstore, snapshot_tag, fpg, vfs) - if not snapshots: + snapshot = self._find_fsnap(orig_project_id, orig_share_id, orig_proto, + snapshot_tag, fpg, vfs) + + if not snapshot: return + fstore = snapshot.get('fstoreName') + for protocol in ('nfs', 'smb'): try: shares = self._client.getfshare(protocol, @@ -417,23 +468,24 @@ class HP3ParMediator(object): 'dependent share.')) raise exception.Invalid(msg) - # Tag should be unique enough to only return one, but this method - # doesn't really need to know that. So just loop. - for snapshot in snapshots: - try: - snapname = snapshot['snapName'] - result = self._client.removefsnap( - vfs, fstore, snapname=snapname, fpg=fpg) + snapname = snapshot['snapName'] + try: + result = self._client.removefsnap( + vfs, fstore, snapname=snapname, fpg=fpg) - LOG.debug("removefsnap result=%s", result) + LOG.debug("removefsnap result=%s", result) - except Exception as e: - msg = (_('Failed to delete snapshot for FPG/VFS/fstore ' - '%(fpg)s/%(vfs)s/%(fstore)s: %(e)s') % - {'fpg': fpg, 'vfs': vfs, 'fstore': fstore, - 'e': six.text_type(e)}) - LOG.exception(msg) - raise exception.ShareBackendException(msg) + except Exception as e: + msg = (_('Failed to delete snapshot for FPG/VFS/fstore/snapshot ' + '%(fpg)s/%(vfs)s/%(fstore)s/%(snapname)s: %(e)s') % + { + 'fpg': fpg, + 'vfs': vfs, + 'fstore': fstore, + 'snapname': snapname, + 'e': six.text_type(e)}) + LOG.exception(msg) + raise exception.ShareBackendException(msg) # Try to reclaim the space try: @@ -461,7 +513,7 @@ class HP3ParMediator(object): return protocol - def _change_access(self, plus_or_minus, fstore, share_id, share_proto, + def _change_access(self, plus_or_minus, project_id, share_id, share_proto, access_type, access_to, fpg, vfs): """Allow or deny access to a share. @@ -469,12 +521,13 @@ class HP3ParMediator(object): allow list (-). """ - share_name = self.ensure_prefix(share_id) - fstore = self.ensure_prefix(fstore) - protocol = self.ensure_supported_protocol(share_proto) self.validate_access_type(protocol, access_type) + share_name = self.ensure_prefix(share_id) + fstore = self._find_fstore(project_id, share_id, protocol, fpg, vfs, + allow_cross_protocol=True) + try: if protocol == 'nfs': result = self._client.setfshare( @@ -507,37 +560,80 @@ class HP3ParMediator(object): LOG.exception(msg) raise exception.ShareBackendException(msg) - def get_fstore(self, share_id, share_proto, fpg, vfs): + def _find_fstore(self, project_id, share_id, share_proto, fpg, vfs, + allow_cross_protocol=False): + + share = self._find_fshare(project_id, share_id, share_proto, fpg, vfs) + + if not share and allow_cross_protocol: + share = self._find_fshare(project_id, + share_id, + self.other_protocol(share_proto), + fpg, + vfs) + + return share.get('fstoreName') if share else None + + def _find_fshare(self, project_id, share_id, share_proto, fpg, vfs): protocol = self.ensure_supported_protocol(share_proto) share_name = self.ensure_prefix(share_id) + + project_fstore = self.ensure_prefix(project_id, share_proto) + search_order = [ + {'fpg': fpg, 'vfs': vfs, 'fstore': project_fstore}, + {'fpg': fpg, 'vfs': vfs, 'fstore': share_name}, + {'fpg': fpg}, + {} + ] + try: - shares = self._client.getfshare(protocol, - share_name, - fpg=fpg, - vfs=vfs) + for search_params in search_order: + result = self._client.getfshare(protocol, share_name, + **search_params) + shares = result.get('members', []) + if len(shares) == 1: + return shares[0] except Exception as e: msg = (_('Unexpected exception while getting share list: %s') % six.text_type(e)) raise exception.ShareBackendException(msg) - members = shares['members'] - if members: - return members[0].get('fstoreName') + def _find_fsnap(self, project_id, share_id, orig_proto, snapshot_tag, + fpg, vfs): - def allow_access(self, share_id, share_proto, access_type, access_to, - fpg, vfs): + share_name = self.ensure_prefix(share_id) + osf_project_id = self.ensure_prefix(project_id, orig_proto) + pattern = '*_%s' % self.ensure_prefix(snapshot_tag) + + search_order = [ + {'pat': True, 'fpg': fpg, 'vfs': vfs, 'fstore': osf_project_id}, + {'pat': True, 'fpg': fpg, 'vfs': vfs, 'fstore': share_name}, + {'pat': True, 'fpg': fpg}, + {'pat': True}, + ] + + try: + for search_params in search_order: + result = self._client.getfsnap(pattern, **search_params) + snapshots = result.get('members', []) + if len(snapshots) == 1: + return snapshots[0] + except Exception as e: + msg = (_('Unexpected exception while getting snapshots: %s') % + six.text_type(e)) + raise exception.ShareBackendException(msg) + + def allow_access(self, project_id, share_id, share_proto, access_type, + access_to, fpg, vfs): """Grant access to a share.""" - fstore = self.get_fstore(share_id, share_proto, fpg, vfs) - self._change_access(ALLOW, fstore, share_id, share_proto, + self._change_access(ALLOW, project_id, share_id, share_proto, access_type, access_to, fpg, vfs) - def deny_access(self, share_id, share_proto, access_type, access_to, - fpg, vfs): + def deny_access(self, project_id, share_id, share_proto, access_type, + access_to, fpg, vfs): """Deny access to a share.""" - fstore = self.get_fstore(share_id, share_proto, fpg, vfs) - if fstore: - self._change_access(DENY, fstore, share_id, share_proto, - access_type, access_to, fpg, vfs) + self._change_access(DENY, project_id, share_id, share_proto, + access_type, access_to, fpg, vfs) diff --git a/manila/tests/share/drivers/hp/test_hp_3par_constants.py b/manila/tests/share/drivers/hp/test_hp_3par_constants.py index f4b69a23e6..f5e0009bd3 100644 --- a/manila/tests/share/drivers/hp/test_hp_3par_constants.py +++ b/manila/tests/share/drivers/hp/test_hp_3par_constants.py @@ -29,6 +29,7 @@ PORT = 22 EXPECTED_IP_10203040 = '10.20.30.40' EXPECTED_IP_1234 = '1.2.3.4' EXPECTED_IP_127 = '127.0.0.1' +EXPECTED_PROJECT_ID = 'osf-nfs-project-id' EXPECTED_SHARE_ID = 'osf-share-id' EXPECTED_SHARE_NAME = 'share-name' EXPECTED_SHARE_PATH = '/anyfpg/anyvfs/anyfstore' @@ -38,11 +39,12 @@ EXPECTED_SNAP_NAME = 'osf-snap-name' EXPECTED_SNAP_ID = 'osf-snap-id' EXPECTED_STATS = {'test': 'stats'} EXPECTED_FPG = 'FPG_1' -EXPECTED_FSTORE = 'osf-test_fstore' +EXPECTED_FSTORE = EXPECTED_PROJECT_ID EXPECTED_VFS = 'test_vfs' EXPECTED_HP_DEBUG = True NFS_SHARE_INFO = { + 'project_id': EXPECTED_PROJECT_ID, 'id': EXPECTED_SHARE_ID, 'share_proto': NFS, } @@ -55,5 +57,9 @@ ACCESS_INFO = { SNAPSHOT_INFO = { 'name': EXPECTED_SNAP_NAME, 'id': EXPECTED_SNAP_ID, - 'share': {'id': EXPECTED_SHARE_ID}, + 'share': { + 'project_id': EXPECTED_PROJECT_ID, + 'id': EXPECTED_SHARE_ID, + 'share_proto': NFS, + }, } diff --git a/manila/tests/share/drivers/hp/test_hp_3par_driver.py b/manila/tests/share/drivers/hp/test_hp_3par_driver.py index 297e9ed9a7..21ba2a1888 100644 --- a/manila/tests/share/drivers/hp/test_hp_3par_driver.py +++ b/manila/tests/share/drivers/hp/test_hp_3par_driver.py @@ -39,11 +39,12 @@ class HP3ParDriverTestCase(test.TestCase): self.conf.hp3par_api_url = constants.API_URL self.conf.hp3par_san_login = constants.SAN_LOGIN self.conf.hp3par_san_password = constants.SAN_PASSWORD - self.conf.hp3par.san_ip = constants.EXPECTED_IP_1234 + self.conf.hp3par_san_ip = constants.EXPECTED_IP_1234 self.conf.hp3par_fpg = constants.EXPECTED_FPG self.conf.hp3par_san_ssh_port = constants.PORT self.conf.ssh_conn_timeout = constants.TIMEOUT self.conf.hp3par_share_ip_address = constants.EXPECTED_IP_10203040 + self.conf.hp3par_fstore_per_share = False self.conf.network_config_group = 'test_network_config_group' def safe_get(attr): @@ -66,20 +67,22 @@ class HP3ParDriverTestCase(test.TestCase): self.mock_mediator.get_vfs_name.return_value = constants.EXPECTED_VFS self.driver.do_setup(None) + conf = self.conf self.mock_mediator_constructor.assert_has_calls([ - mock.call(hp3par_san_ssh_port=self.conf.hp3par_san_ssh_port, - hp3par_san_password=self.conf.hp3par_san_password, - hp3par_username=self.conf.hp3par_username, - hp3par_san_login=self.conf.hp3par_san_login, - hp3par_debug=self.conf.hp3par_debug, - hp3par_api_url=self.conf.hp3par_api_url, - hp3par_password=self.conf.hp3par_password, - hp3par_san_ip=self.conf.hp3par_san_ip, - ssh_conn_timeout=self.conf.ssh_conn_timeout)]) + mock.call(hp3par_san_ssh_port=conf.hp3par_san_ssh_port, + hp3par_san_password=conf.hp3par_san_password, + hp3par_username=conf.hp3par_username, + hp3par_san_login=conf.hp3par_san_login, + hp3par_debug=conf.hp3par_debug, + hp3par_api_url=conf.hp3par_api_url, + hp3par_password=conf.hp3par_password, + hp3par_san_ip=conf.hp3par_san_ip, + hp3par_fstore_per_share=conf.hp3par_fstore_per_share, + ssh_conn_timeout=conf.ssh_conn_timeout)]) self.mock_mediator.assert_has_calls([ mock.call.do_setup(), - mock.call.get_vfs_name(self.conf.hp3par_fpg)]) + mock.call.get_vfs_name(conf.hp3par_fpg)]) self.assertEqual(constants.EXPECTED_VFS, self.driver.vfs) @@ -92,16 +95,18 @@ class HP3ParDriverTestCase(test.TestCase): self.assertRaises(exception.ShareBackendException, self.driver.do_setup, None) + conf = self.conf self.mock_mediator_constructor.assert_has_calls([ - mock.call(hp3par_san_ssh_port=self.conf.hp3par_san_ssh_port, - hp3par_san_password=self.conf.hp3par_san_password, - hp3par_username=self.conf.hp3par_username, - hp3par_san_login=self.conf.hp3par_san_login, - hp3par_debug=self.conf.hp3par_debug, - hp3par_api_url=self.conf.hp3par_api_url, - hp3par_password=self.conf.hp3par_password, - hp3par_san_ip=self.conf.hp3par_san_ip, - ssh_conn_timeout=self.conf.ssh_conn_timeout)]) + mock.call(hp3par_san_ssh_port=conf.hp3par_san_ssh_port, + hp3par_san_password=conf.hp3par_san_password, + hp3par_username=conf.hp3par_username, + hp3par_san_login=conf.hp3par_san_login, + hp3par_debug=conf.hp3par_debug, + hp3par_api_url=conf.hp3par_api_url, + hp3par_password=conf.hp3par_password, + hp3par_san_ip=conf.hp3par_san_ip, + hp3par_fstore_per_share=conf.hp3par_fstore_per_share, + ssh_conn_timeout=conf.ssh_conn_timeout)]) self.mock_mediator.assert_has_calls([mock.call.do_setup()]) @@ -114,20 +119,22 @@ class HP3ParDriverTestCase(test.TestCase): self.assertRaises(exception.ShareBackendException, self.driver.do_setup, None) + conf = self.conf self.mock_mediator_constructor.assert_has_calls([ - mock.call(hp3par_san_ssh_port=self.conf.hp3par_san_ssh_port, - hp3par_san_password=self.conf.hp3par_san_password, - hp3par_username=self.conf.hp3par_username, - hp3par_san_login=self.conf.hp3par_san_login, - hp3par_debug=self.conf.hp3par_debug, - hp3par_api_url=self.conf.hp3par_api_url, - hp3par_password=self.conf.hp3par_password, - hp3par_san_ip=self.conf.hp3par_san_ip, - ssh_conn_timeout=self.conf.ssh_conn_timeout)]) + mock.call(hp3par_san_ssh_port=conf.hp3par_san_ssh_port, + hp3par_san_password=conf.hp3par_san_password, + hp3par_username=conf.hp3par_username, + hp3par_san_login=conf.hp3par_san_login, + hp3par_debug=conf.hp3par_debug, + hp3par_api_url=conf.hp3par_api_url, + hp3par_password=conf.hp3par_password, + hp3par_san_ip=conf.hp3par_san_ip, + hp3par_fstore_per_share=conf.hp3par_fstore_per_share, + ssh_conn_timeout=conf.ssh_conn_timeout)]) self.mock_mediator.assert_has_calls([ mock.call.do_setup(), - mock.call.get_vfs_name(self.conf.hp3par_fpg)]) + mock.call.get_vfs_name(conf.hp3par_fpg)]) def init_driver(self): """Simple driver setup for re-use with tests that need one.""" @@ -137,11 +144,13 @@ class HP3ParDriverTestCase(test.TestCase): self.driver.fpg = constants.EXPECTED_FPG self.driver.share_ip_address = self.conf.hp3par_share_ip_address - def do_create_share(self, protocol, expected_share_id, expected_size): + def do_create_share(self, protocol, expected_project_id, expected_share_id, + expected_size): """Re-usable code for create share.""" context = None share_server = None share = { + 'project_id': expected_project_id, 'id': expected_share_id, 'share_proto': protocol, 'size': expected_size, @@ -188,11 +197,13 @@ class HP3ParDriverTestCase(test.TestCase): constants.EXPECTED_SHARE_NAME) location = self.do_create_share(constants.CIFS, + constants.EXPECTED_PROJECT_ID, constants.EXPECTED_SHARE_ID, constants.EXPECTED_SIZE_2) self.assertEqual(expected_location, location) expected_calls = [mock.call.create_share( + constants.EXPECTED_PROJECT_ID, constants.EXPECTED_SHARE_ID, constants.CIFS, constants.EXPECTED_FPG, @@ -210,12 +221,14 @@ class HP3ParDriverTestCase(test.TestCase): constants.EXPECTED_SHARE_PATH) location = self.do_create_share(constants.NFS, + constants.EXPECTED_PROJECT_ID, constants.EXPECTED_SHARE_ID, constants.EXPECTED_SIZE_1) self.assertEqual(expected_location, location) expected_calls = [ - mock.call.create_share(constants.EXPECTED_SHARE_ID, + mock.call.create_share(constants.EXPECTED_PROJECT_ID, + constants.EXPECTED_SHARE_ID, constants.NFS, constants.EXPECTED_FPG, constants.EXPECTED_VFS, @@ -242,7 +255,9 @@ class HP3ParDriverTestCase(test.TestCase): expected_calls = [ mock.call.create_share_from_snapshot(constants.EXPECTED_SHARE_ID, constants.CIFS, + constants.EXPECTED_FSTORE, constants.EXPECTED_SHARE_ID, + constants.NFS, constants.EXPECTED_SNAP_ID, constants.EXPECTED_FPG, constants.EXPECTED_VFS)] @@ -267,7 +282,9 @@ class HP3ParDriverTestCase(test.TestCase): expected_calls = [ mock.call.create_share_from_snapshot(constants.EXPECTED_SHARE_ID, constants.NFS, + constants.EXPECTED_PROJECT_ID, constants.EXPECTED_SHARE_ID, + constants.NFS, constants.EXPECTED_SNAP_ID, constants.EXPECTED_FPG, constants.EXPECTED_VFS)] @@ -280,6 +297,7 @@ class HP3ParDriverTestCase(test.TestCase): context = None share_server = None share = { + 'project_id': constants.EXPECTED_PROJECT_ID, 'id': constants.EXPECTED_SHARE_ID, 'share_proto': constants.CIFS, 'size': constants.EXPECTED_SIZE_1, @@ -288,7 +306,8 @@ class HP3ParDriverTestCase(test.TestCase): self.driver.delete_share(context, share, share_server) expected_calls = [ - mock.call.delete_share(constants.EXPECTED_SHARE_ID, + mock.call.delete_share(constants.EXPECTED_PROJECT_ID, + constants.EXPECTED_SHARE_ID, constants.CIFS, constants.EXPECTED_FPG, constants.EXPECTED_VFS)] @@ -305,7 +324,9 @@ class HP3ParDriverTestCase(test.TestCase): share_server) expected_calls = [ - mock.call.create_snapshot(constants.EXPECTED_SHARE_ID, + mock.call.create_snapshot(constants.EXPECTED_PROJECT_ID, + constants.EXPECTED_SHARE_ID, + constants.NFS, constants.EXPECTED_SNAP_ID, constants.EXPECTED_FPG, constants.EXPECTED_VFS)] @@ -321,7 +342,9 @@ class HP3ParDriverTestCase(test.TestCase): share_server) expected_calls = [ - mock.call.delete_snapshot(constants.EXPECTED_SHARE_ID, + mock.call.delete_snapshot(constants.EXPECTED_PROJECT_ID, + constants.EXPECTED_SHARE_ID, + constants.NFS, constants.EXPECTED_SNAP_ID, constants.EXPECTED_FPG, constants.EXPECTED_VFS) @@ -337,7 +360,8 @@ class HP3ParDriverTestCase(test.TestCase): constants.ACCESS_INFO) expected_calls = [ - mock.call.allow_access(constants.EXPECTED_SHARE_ID, + mock.call.allow_access(constants.EXPECTED_PROJECT_ID, + constants.EXPECTED_SHARE_ID, constants.NFS, constants.IP, constants.EXPECTED_IP_1234, @@ -355,7 +379,8 @@ class HP3ParDriverTestCase(test.TestCase): constants.ACCESS_INFO) expected_calls = [ - mock.call.deny_access(constants.EXPECTED_SHARE_ID, + mock.call.deny_access(constants.EXPECTED_PROJECT_ID, + constants.EXPECTED_SHARE_ID, constants.NFS, constants.IP, constants.EXPECTED_IP_1234, diff --git a/manila/tests/share/drivers/hp/test_hp_3par_mediator.py b/manila/tests/share/drivers/hp/test_hp_3par_mediator.py index aea1aac4d1..b8a8bac08b 100644 --- a/manila/tests/share/drivers/hp/test_hp_3par_mediator.py +++ b/manila/tests/share/drivers/hp/test_hp_3par_mediator.py @@ -14,10 +14,10 @@ import sys +import ddt import mock if 'hp3parclient' not in sys.modules: sys.modules['hp3parclient'] = mock.Mock() -import six from manila import exception from manila.share.drivers.hp import hp_3par_mediator as hp3parmediator @@ -27,6 +27,7 @@ from manila.tests.share.drivers.hp import test_hp_3par_constants as constants from oslo_utils import units +@ddt.ddt class HP3ParMediatorTestCase(test.TestCase): def setUp(self): @@ -143,20 +144,23 @@ class HP3ParMediatorTestCase(test.TestCase): expected_fpg, expected_vfsname, expected_protocol, - expected_share_id, - expected_size): - size = six.text_type(expected_size) - expected_sharedir = None + expected_project_id, + expected_share_id): + expected_sharedir = expected_share_id if expected_protocol == constants.NFS_LOWER: expected_calls = [ - mock.call.createfstore(expected_vfsname, expected_share_id, + mock.call.createfstore(expected_vfsname, expected_project_id, comment='OpenStack Manila fstore', fpg=expected_fpg), - mock.call.setfsquota(expected_vfsname, fpg=expected_fpg, - hcapacity=size, - scapacity=size, - fstore=expected_share_id), + mock.call.getfsquota(fpg=expected_fpg, + vfs=expected_vfsname, + fstore=expected_project_id), + mock.call.setfsquota(expected_vfsname, + fpg=expected_fpg, + hcapacity='2048', + scapacity='2048', + fstore=expected_project_id), mock.call.createfshare(expected_protocol, expected_vfsname, expected_share_id, comment='OpenStack Manila fshare', @@ -164,29 +168,33 @@ class HP3ParMediatorTestCase(test.TestCase): sharedir=expected_sharedir, clientip='127.0.0.1', options='rw,no_root_squash,insecure', - fstore=expected_share_id), + fstore=expected_project_id), mock.call.getfshare(expected_protocol, expected_share_id, fpg=expected_fpg, vfs=expected_vfsname, - fstore=expected_share_id)] + fstore=expected_project_id)] else: expected_calls = [ - mock.call.createfstore(expected_vfsname, expected_share_id, + mock.call.createfstore(expected_vfsname, expected_project_id, comment='OpenStack Manila fstore', fpg=expected_fpg), - mock.call.setfsquota(expected_vfsname, fpg=expected_fpg, - hcapacity=size, - scapacity=size, - fstore=expected_share_id), + mock.call.getfsquota(fpg=expected_fpg, + vfs=expected_vfsname, + fstore=expected_project_id), + mock.call.setfsquota(expected_vfsname, + fpg=expected_fpg, + hcapacity='2048', + scapacity='2048', + fstore=expected_project_id), mock.call.createfshare(expected_protocol, expected_vfsname, expected_share_id, comment='OpenStack Manila fshare', fpg=expected_fpg, sharedir=expected_sharedir, allowip='127.0.0.1', - fstore=expected_share_id), + fstore=expected_project_id), mock.call.getfshare(expected_protocol, expected_share_id, fpg=expected_fpg, vfs=expected_vfsname, - fstore=expected_share_id)] + fstore=expected_project_id)] return expected_calls def test_mediator_create_cifs_share(self): @@ -198,11 +206,18 @@ class HP3ParMediatorTestCase(test.TestCase): 'members': [{'shareName': constants.EXPECTED_SHARE_NAME}] } - location = self.mediator.create_share(constants.EXPECTED_SHARE_ID, + self.mock_client.getfsquota.return_value = { + 'message': None, + 'total': 1, + 'members': [{'hardBlock': '1024', 'softBlock': '1024'}] + } + + location = self.mediator.create_share(constants.EXPECTED_PROJECT_ID, + constants.EXPECTED_SHARE_ID, constants.CIFS, constants.EXPECTED_FPG, constants.EXPECTED_VFS, - size=constants.EXPECTED_SIZE_2) + size=constants.EXPECTED_SIZE_1) self.assertEqual(constants.EXPECTED_SHARE_NAME, location) @@ -210,8 +225,8 @@ class HP3ParMediatorTestCase(test.TestCase): constants.EXPECTED_FPG, constants.EXPECTED_VFS, constants.SMB_LOWER, - constants.EXPECTED_SHARE_ID, - constants.EXPECTED_SIZE_2) + constants.EXPECTED_PROJECT_ID, + constants.EXPECTED_SHARE_ID) self.mock_client.assert_has_calls(expected_calls) @@ -224,7 +239,14 @@ class HP3ParMediatorTestCase(test.TestCase): 'members': [{'sharePath': constants.EXPECTED_SHARE_PATH}] } - location = self.mediator.create_share(constants.EXPECTED_SHARE_ID, + self.mock_client.getfsquota.return_value = { + 'message': None, + 'total': 1, + 'members': [{'hardBlock': '1024', 'softBlock': '1024'}] + } + + location = self.mediator.create_share(constants.EXPECTED_PROJECT_ID, + constants.EXPECTED_SHARE_ID, constants.NFS.lower(), constants.EXPECTED_FPG, constants.EXPECTED_VFS, @@ -233,10 +255,11 @@ class HP3ParMediatorTestCase(test.TestCase): self.assertEqual(constants.EXPECTED_SHARE_PATH, location) expected_calls = self.get_expected_calls_for_create_share( - constants.EXPECTED_FPG, constants.EXPECTED_VFS, + constants.EXPECTED_FPG, + constants.EXPECTED_VFS, constants.NFS.lower(), - constants.EXPECTED_SHARE_ID, - constants.EXPECTED_SIZE_1) + constants.EXPECTED_PROJECT_ID, + constants.EXPECTED_SHARE_ID) self.mock_client.assert_has_calls(expected_calls) @@ -246,13 +269,16 @@ class HP3ParMediatorTestCase(test.TestCase): self.mock_client.getfsnap.return_value = { 'message': None, 'total': 1, - 'members': [{'snapName': constants.EXPECTED_SNAP_ID}] + 'members': [{'snapName': constants.EXPECTED_SNAP_ID, + 'fstoreName': constants.EXPECTED_FSTORE}] } location = self.mediator.create_share_from_snapshot( constants.EXPECTED_SHARE_ID, constants.CIFS, + constants.EXPECTED_PROJECT_ID, constants.EXPECTED_SHARE_ID, + constants.NFS, constants.EXPECTED_SNAP_ID, constants.EXPECTED_FPG, constants.EXPECTED_VFS) @@ -264,21 +290,22 @@ class HP3ParMediatorTestCase(test.TestCase): vfs=constants.EXPECTED_VFS, fpg=constants.EXPECTED_FPG, pat=True, - fstore=constants.EXPECTED_SHARE_ID), + fstore=constants.EXPECTED_FSTORE), mock.call.createfshare(constants.SMB_LOWER, constants.EXPECTED_VFS, constants.EXPECTED_SHARE_ID, comment=mock.ANY, fpg=constants.EXPECTED_FPG, - sharedir='.snapshot/%s' % + sharedir='.snapshot/%s/%s' % ( constants.EXPECTED_SNAP_ID, - fstore=constants.EXPECTED_SHARE_ID, + constants.EXPECTED_SHARE_ID), + fstore=constants.EXPECTED_FSTORE, allowip=constants.EXPECTED_IP_127), mock.call.getfshare(constants.SMB_LOWER, constants.EXPECTED_SHARE_ID, fpg=constants.EXPECTED_FPG, vfs=constants.EXPECTED_VFS, - fstore=constants.EXPECTED_SHARE_ID)] + fstore=constants.EXPECTED_FSTORE)] self.mock_client.assert_has_calls(expected_calls) @@ -288,13 +315,16 @@ class HP3ParMediatorTestCase(test.TestCase): self.mock_client.getfsnap.return_value = { 'message': None, 'total': 1, - 'members': [{'snapName': constants.EXPECTED_SNAP_ID}] + 'members': [{'snapName': constants.EXPECTED_SNAP_ID, + 'fstoreName': constants.EXPECTED_FSTORE}] } location = self.mediator.create_share_from_snapshot( constants.EXPECTED_SHARE_ID, constants.NFS, + constants.EXPECTED_PROJECT_ID, constants.EXPECTED_SHARE_ID, + constants.NFS, constants.EXPECTED_SNAP_ID, constants.EXPECTED_FPG, constants.EXPECTED_VFS) @@ -306,22 +336,23 @@ class HP3ParMediatorTestCase(test.TestCase): vfs=constants.EXPECTED_VFS, fpg=constants.EXPECTED_FPG, pat=True, - fstore=constants.EXPECTED_SHARE_ID), + fstore=constants.EXPECTED_FSTORE), mock.call.createfshare(constants.NFS_LOWER, constants.EXPECTED_VFS, constants.EXPECTED_SHARE_ID, comment=mock.ANY, fpg=constants.EXPECTED_FPG, - sharedir='.snapshot/%s' % - constants.EXPECTED_SNAP_ID, - fstore=constants.EXPECTED_SHARE_ID, + sharedir='.snapshot/%s/%s' % + (constants.EXPECTED_SNAP_ID, + constants.EXPECTED_SHARE_ID), + fstore=constants.EXPECTED_FSTORE, clientip=constants.EXPECTED_IP_127, options='ro,no_root_squash,insecure'), mock.call.getfshare(constants.NFS_LOWER, constants.EXPECTED_SHARE_ID, fpg=constants.EXPECTED_FPG, vfs=constants.EXPECTED_VFS, - fstore=constants.EXPECTED_SHARE_ID)] + fstore=constants.EXPECTED_FSTORE)] self.mock_client.assert_has_calls(expected_calls) @@ -338,7 +369,9 @@ class HP3ParMediatorTestCase(test.TestCase): self.mediator.create_share_from_snapshot, constants.EXPECTED_SHARE_ID, constants.NFS, + constants.EXPECTED_PROJECT_ID, constants.EXPECTED_SHARE_ID, + constants.NFS, constants.EXPECTED_SNAP_ID, constants.EXPECTED_FPG, constants.EXPECTED_VFS) @@ -346,7 +379,12 @@ class HP3ParMediatorTestCase(test.TestCase): def test_mediator_delete_share(self): self.init_mediator() - self.mediator.delete_share(constants.EXPECTED_SHARE_ID, + self.mock_object(self.mediator, + '_find_fstore', + mock.Mock(return_value=constants.EXPECTED_SHARE_ID)) + + self.mediator.delete_share(constants.EXPECTED_PROJECT_ID, + constants.EXPECTED_SHARE_ID, constants.CIFS, constants.EXPECTED_FPG, constants.EXPECTED_VFS) @@ -356,10 +394,10 @@ class HP3ParMediatorTestCase(test.TestCase): constants.EXPECTED_VFS, constants.EXPECTED_SHARE_ID, fpg=constants.EXPECTED_FPG, - fstore=constants.EXPECTED_FSTORE), + fstore=constants.EXPECTED_SHARE_ID), mock.call.removefstore(constants.EXPECTED_VFS, - constants.EXPECTED_FSTORE, - fpg=constants.EXPECTED_FPG) + constants.EXPECTED_SHARE_ID, + fpg=constants.EXPECTED_FPG), ] self.mock_client.assert_has_calls(expected_calls) @@ -367,14 +405,16 @@ class HP3ParMediatorTestCase(test.TestCase): def test_mediator_create_snapshot(self): self.init_mediator() - self.mediator.create_snapshot(constants.EXPECTED_SHARE_ID, + self.mediator.create_snapshot(constants.EXPECTED_PROJECT_ID, + constants.EXPECTED_SHARE_ID, + constants.NFS, constants.EXPECTED_SNAP_NAME, constants.EXPECTED_FPG, constants.EXPECTED_VFS) expected_calls = [ mock.call.createfsnap(constants.EXPECTED_VFS, - constants.EXPECTED_SHARE_ID, + constants.EXPECTED_PROJECT_ID, constants.EXPECTED_SNAP_NAME, fpg=constants.EXPECTED_FPG) ] @@ -389,7 +429,9 @@ class HP3ParMediatorTestCase(test.TestCase): self.assertRaises(exception.ShareBackendException, self.mediator.create_snapshot, + constants.EXPECTED_PROJECT_ID, constants.EXPECTED_SHARE_ID, + constants.NFS, constants.EXPECTED_SNAP_NAME, constants.EXPECTED_FPG, constants.EXPECTED_VFS) @@ -401,7 +443,13 @@ class HP3ParMediatorTestCase(test.TestCase): self.mock_client.getfsnap.return_value = { 'total': 1, - 'members': [{'snapName': expected_name_from_array}] + 'members': [ + { + 'snapName': expected_name_from_array, + 'fstoreName': constants.EXPECTED_PROJECT_ID, + } + ], + 'message': None } self.mock_client.getfshare.side_effect = [ @@ -416,7 +464,9 @@ class HP3ParMediatorTestCase(test.TestCase): } ] - self.mediator.delete_snapshot(constants.EXPECTED_SHARE_ID, + self.mediator.delete_snapshot(constants.EXPECTED_PROJECT_ID, + constants.EXPECTED_SHARE_ID, + constants.NFS, constants.EXPECTED_SNAP_NAME, constants.EXPECTED_FPG, constants.EXPECTED_VFS) @@ -426,17 +476,17 @@ class HP3ParMediatorTestCase(test.TestCase): vfs=constants.EXPECTED_VFS, fpg=constants.EXPECTED_FPG, pat=True, - fstore=constants.EXPECTED_SHARE_ID), + fstore=constants.EXPECTED_PROJECT_ID), mock.call.getfshare(constants.NFS_LOWER, fpg=constants.EXPECTED_FPG, vfs=constants.EXPECTED_VFS, - fstore=constants.EXPECTED_SHARE_ID), + fstore=constants.EXPECTED_PROJECT_ID), mock.call.getfshare(constants.SMB_LOWER, fpg=constants.EXPECTED_FPG, vfs=constants.EXPECTED_VFS, - fstore=constants.EXPECTED_SHARE_ID), + fstore=constants.EXPECTED_PROJECT_ID), mock.call.removefsnap(constants.EXPECTED_VFS, - constants.EXPECTED_SHARE_ID, + constants.EXPECTED_PROJECT_ID, fpg=constants.EXPECTED_FPG, snapname=expected_name_from_array), mock.call.startfsnapclean(constants.EXPECTED_FPG, @@ -452,7 +502,9 @@ class HP3ParMediatorTestCase(test.TestCase): 'members': [], } - self.mediator.delete_snapshot(constants.EXPECTED_SHARE_ID, + self.mediator.delete_snapshot(constants.EXPECTED_PROJECT_ID, + constants.EXPECTED_SHARE_ID, + constants.NFS, constants.EXPECTED_SNAP_NAME, constants.EXPECTED_FPG, constants.EXPECTED_VFS) @@ -497,7 +549,9 @@ class HP3ParMediatorTestCase(test.TestCase): self.assertRaises(exception.Invalid, self.mediator.delete_snapshot, + constants.EXPECTED_PROJECT_ID, constants.EXPECTED_SHARE_ID, + constants.NFS, constants.EXPECTED_SNAP_NAME, constants.EXPECTED_FPG, constants.EXPECTED_VFS) @@ -527,7 +581,9 @@ class HP3ParMediatorTestCase(test.TestCase): self.assertRaises(exception.Invalid, self.mediator.delete_snapshot, + constants.EXPECTED_PROJECT_ID, constants.EXPECTED_SHARE_ID, + constants.NFS, constants.EXPECTED_SNAP_NAME, constants.EXPECTED_FPG, constants.EXPECTED_VFS) @@ -535,7 +591,9 @@ class HP3ParMediatorTestCase(test.TestCase): def _assert_delete_snapshot_raises(self): self.assertRaises(exception.ShareBackendException, self.mediator.delete_snapshot, + constants.EXPECTED_PROJECT_ID, constants.EXPECTED_SHARE_ID, + constants.NFS, constants.EXPECTED_SNAP_NAME, constants.EXPECTED_FPG, constants.EXPECTED_VFS) @@ -551,7 +609,8 @@ class HP3ParMediatorTestCase(test.TestCase): self.mock_client.getfsnap.side_effect = None self.mock_client.getfsnap.return_value = { 'total': 1, - 'members': [{'snapName': constants.EXPECTED_SNAP_NAME}] + 'members': [{'snapName': constants.EXPECTED_SNAP_NAME, + 'fstoreName': constants.EXPECTED_FSTORE}] } # getfshare exception @@ -563,12 +622,14 @@ class HP3ParMediatorTestCase(test.TestCase): if args[0] == constants.NFS_LOWER: return { 'total': 1, - 'members': [{'sharePath': '/anyfpg/anyvfs/anyfstore'}] + 'members': [{'sharePath': '/anyfpg/anyvfs/anyfstore', + 'fstoreName': constants.EXPECTED_FSTORE}] } else: return { 'total': 1, - 'members': [{'shareDir': []}] + 'members': [{'shareDir': [], + 'fstoreName': constants.EXPECTED_FSTORE}] } self.mock_client.getfshare.side_effect = mock_fshare @@ -587,7 +648,9 @@ class HP3ParMediatorTestCase(test.TestCase): 'startfsnapclean fail.') mock_log = self.mock_object(hp3parmediator, 'LOG') - self.mediator.delete_snapshot(constants.EXPECTED_SHARE_ID, + self.mediator.delete_snapshot(constants.EXPECTED_PROJECT_ID, + constants.EXPECTED_SHARE_ID, + constants.NFS, constants.EXPECTED_SNAP_NAME, constants.EXPECTED_FPG, constants.EXPECTED_VFS) @@ -597,17 +660,17 @@ class HP3ParMediatorTestCase(test.TestCase): vfs=constants.EXPECTED_VFS, fpg=constants.EXPECTED_FPG, pat=True, - fstore=constants.EXPECTED_SHARE_ID), + fstore=constants.EXPECTED_FSTORE), mock.call.getfshare(constants.NFS_LOWER, fpg=constants.EXPECTED_FPG, vfs=constants.EXPECTED_VFS, - fstore=constants.EXPECTED_SHARE_ID), + fstore=constants.EXPECTED_FSTORE), mock.call.getfshare(constants.SMB_LOWER, fpg=constants.EXPECTED_FPG, vfs=constants.EXPECTED_VFS, - fstore=constants.EXPECTED_SHARE_ID), + fstore=constants.EXPECTED_FSTORE), mock.call.removefsnap(constants.EXPECTED_VFS, - constants.EXPECTED_SHARE_ID, + constants.EXPECTED_FSTORE, fpg=constants.EXPECTED_FPG, snapname=constants.EXPECTED_SNAP_NAME), mock.call.startfsnapclean(constants.EXPECTED_FPG, @@ -651,7 +714,8 @@ class HP3ParMediatorTestCase(test.TestCase): expected_allowperm = '+%s:fullcontrol' % constants.USERNAME - self.mediator.allow_access(constants.EXPECTED_SHARE_ID, + self.mediator.allow_access(constants.EXPECTED_PROJECT_ID, + constants.EXPECTED_SHARE_ID, constants.CIFS, constants.USER, constants.USERNAME, @@ -675,7 +739,8 @@ class HP3ParMediatorTestCase(test.TestCase): expected_denyperm = '-%s:fullcontrol' % constants.USERNAME - self.mediator.deny_access(constants.EXPECTED_SHARE_ID, + self.mediator.deny_access(constants.EXPECTED_PROJECT_ID, + constants.EXPECTED_SHARE_ID, constants.CIFS, constants.USER, constants.USERNAME, @@ -699,7 +764,8 @@ class HP3ParMediatorTestCase(test.TestCase): expected_allowip = '+%s' % constants.EXPECTED_IP_1234 - self.mediator.allow_access(constants.EXPECTED_SHARE_ID, + self.mediator.allow_access(constants.EXPECTED_PROJECT_ID, + constants.EXPECTED_SHARE_ID, constants.CIFS, constants.IP, constants.EXPECTED_IP_1234, @@ -722,7 +788,8 @@ class HP3ParMediatorTestCase(test.TestCase): expected_denyip = '-%s' % constants.EXPECTED_IP_1234 - self.mediator.deny_access(constants.EXPECTED_SHARE_ID, + self.mediator.deny_access(constants.EXPECTED_PROJECT_ID, + constants.EXPECTED_SHARE_ID, constants.CIFS, constants.IP, constants.EXPECTED_IP_1234, @@ -745,7 +812,8 @@ class HP3ParMediatorTestCase(test.TestCase): expected_clientip = '+%s' % constants.EXPECTED_IP_1234 - self.mediator.allow_access(constants.EXPECTED_SHARE_ID, + self.mediator.allow_access(constants.EXPECTED_PROJECT_ID, + constants.EXPECTED_SHARE_ID, constants.NFS, constants.IP, constants.EXPECTED_IP_1234, @@ -768,7 +836,8 @@ class HP3ParMediatorTestCase(test.TestCase): expected_clientip = '-%s' % constants.EXPECTED_IP_1234 - self.mediator.deny_access(constants.EXPECTED_SHARE_ID, + self.mediator.deny_access(constants.EXPECTED_PROJECT_ID, + constants.EXPECTED_SHARE_ID, constants.NFS, constants.IP, constants.EXPECTED_IP_1234, @@ -791,6 +860,7 @@ class HP3ParMediatorTestCase(test.TestCase): self.assertRaises(exception.HP3ParInvalid, self.mediator.allow_access, + constants.EXPECTED_PROJECT_ID, constants.EXPECTED_SHARE_ID, constants.NFS, constants.USER, @@ -804,6 +874,7 @@ class HP3ParMediatorTestCase(test.TestCase): self.assertRaises(exception.InvalidInput, self.mediator.allow_access, + constants.EXPECTED_PROJECT_ID, constants.EXPECTED_SHARE_ID, 'unsupported_other_protocol', constants.USER, @@ -817,9 +888,241 @@ class HP3ParMediatorTestCase(test.TestCase): self.assertRaises(exception.InvalidInput, self.mediator.allow_access, + constants.EXPECTED_PROJECT_ID, constants.EXPECTED_SHARE_ID, constants.CIFS, 'unsupported_other_type', constants.USERNAME, constants.EXPECTED_FPG, constants.EXPECTED_VFS) + + @ddt.data((('nfs', 'NFS', 'nFs'), 'smb'), + (('smb', 'SMB', 'SmB', 'CIFS', 'cifs', 'CiFs'), 'nfs')) + @ddt.unpack + def test_other_protocol(self, protocols, expected_other): + for protocol in protocols: + self.assertEqual(expected_other, + hp3parmediator.HP3ParMediator().other_protocol( + protocol)) + + @ddt.data('', 'bogus') + def test_other_protocol_exception(self, protocol): + self.assertRaises(exception.InvalidInput, + hp3parmediator.HP3ParMediator().other_protocol, + protocol) + + @ddt.data(('osf-uid', None, 'osf-uid'), + ('uid', None, 'osf-uid'), + ('uid', 'smb', 'osf-smb-uid'), + ('uid', 'smb', 'osf-smb-uid')) + @ddt.unpack + def test_ensure_prefix(self, uid, protocol, expected): + self.assertEqual(expected, + hp3parmediator.HP3ParMediator().ensure_prefix( + uid, protocol=protocol)) + + def test_find_fstore_search(self): + self.init_mediator() + + mock_find_fshare = self.mock_object(self.mediator, + '_find_fshare', + mock.Mock(return_value=None)) + + result = self.mediator._find_fstore(constants.EXPECTED_PROJECT_ID, + constants.EXPECTED_SHARE_ID, + constants.NFS, + constants.EXPECTED_FPG, + constants.EXPECTED_VFS) + + mock_find_fshare.assert_called_once_with(constants.EXPECTED_PROJECT_ID, + constants.EXPECTED_SHARE_ID, + constants.NFS, + constants.EXPECTED_FPG, + constants.EXPECTED_VFS) + self.assertIsNone(result) + + def test_find_fstore_search_xproto(self): + self.init_mediator() + + mock_find_fshare = self.mock_object(self.mediator, + '_find_fshare', + mock.Mock(return_value=None)) + + result = self.mediator._find_fstore(constants.EXPECTED_PROJECT_ID, + constants.EXPECTED_SHARE_ID, + constants.NFS, + constants.EXPECTED_FPG, + constants.EXPECTED_VFS, + allow_cross_protocol=True) + + expected_calls = [ + mock.call(constants.EXPECTED_PROJECT_ID, + constants.EXPECTED_SHARE_ID, + constants.NFS, + constants.EXPECTED_FPG, + constants.EXPECTED_VFS), + mock.call(constants.EXPECTED_PROJECT_ID, + constants.EXPECTED_SHARE_ID, + constants.SMB_LOWER, + constants.EXPECTED_FPG, + constants.EXPECTED_VFS), + ] + mock_find_fshare.assert_has_calls(expected_calls) + self.assertIsNone(result) + + def test_find_fshare_search(self): + self.init_mediator() + + self.mock_client.getfshare.return_value = {} + + result = self.mediator._find_fshare(constants.EXPECTED_PROJECT_ID, + constants.EXPECTED_SHARE_ID, + constants.NFS, + constants.EXPECTED_FPG, + constants.EXPECTED_VFS) + + expected_calls = [ + mock.call.getfshare(constants.NFS_LOWER, + constants.EXPECTED_SHARE_ID, + fpg=constants.EXPECTED_FPG, + vfs=constants.EXPECTED_VFS, + fstore=constants.EXPECTED_PROJECT_ID), + mock.call.getfshare(constants.NFS_LOWER, + constants.EXPECTED_SHARE_ID, + fpg=constants.EXPECTED_FPG, + vfs=constants.EXPECTED_VFS, + fstore=constants.EXPECTED_SHARE_ID), + mock.call.getfshare(constants.NFS_LOWER, + constants.EXPECTED_SHARE_ID, + fpg=constants.EXPECTED_FPG), + mock.call.getfshare(constants.NFS_LOWER, + constants.EXPECTED_SHARE_ID), + ] + self.mock_client.assert_has_calls(expected_calls) + self.assertIsNone(result) + + def test_find_fshare_exception(self): + self.init_mediator() + + self.mock_client.getfshare.side_effect = Exception('test unexpected') + + self.assertRaises(exception.ShareBackendException, + self.mediator._find_fshare, + constants.EXPECTED_PROJECT_ID, + constants.EXPECTED_SHARE_ID, + constants.NFS, + constants.EXPECTED_FPG, + constants.EXPECTED_VFS) + + self.mock_client.getfshare.assert_called_once_with( + constants.NFS_LOWER, + constants.EXPECTED_SHARE_ID, + fpg=constants.EXPECTED_FPG, + vfs=constants.EXPECTED_VFS, + fstore=constants.EXPECTED_PROJECT_ID) + + def test_find_fshare_hit(self): + self.init_mediator() + + expected_result = {'shareName': 'hit'} + self.mock_client.getfshare.return_value = { + 'total': 1, + 'members': [expected_result] + } + + result = self.mediator._find_fshare(constants.EXPECTED_PROJECT_ID, + constants.EXPECTED_SHARE_ID, + constants.NFS, + constants.EXPECTED_FPG, + constants.EXPECTED_VFS) + + self.mock_client.getfshare.assert_called_once_with( + constants.NFS_LOWER, + constants.EXPECTED_SHARE_ID, + fpg=constants.EXPECTED_FPG, + vfs=constants.EXPECTED_VFS, + fstore=constants.EXPECTED_PROJECT_ID), + self.assertEqual(expected_result, result) + + def test_find_fsnap_search(self): + self.init_mediator() + + self.mock_client.getfsnap.return_value = {} + + result = self.mediator._find_fsnap(constants.EXPECTED_PROJECT_ID, + constants.EXPECTED_SHARE_ID, + constants.NFS, + constants.EXPECTED_SNAP_ID, + constants.EXPECTED_FPG, + constants.EXPECTED_VFS) + + expected_snap_pattern = '*_%s' % constants.EXPECTED_SNAP_ID + + expected_calls = [ + mock.call.getfsnap(expected_snap_pattern, + vfs=constants.EXPECTED_VFS, + fpg=constants.EXPECTED_FPG, + pat=True, + fstore=constants.EXPECTED_PROJECT_ID), + mock.call.getfsnap(expected_snap_pattern, + vfs=constants.EXPECTED_VFS, + fpg=constants.EXPECTED_FPG, + pat=True, + fstore=constants.EXPECTED_SHARE_ID), + mock.call.getfsnap(expected_snap_pattern, + fpg=constants.EXPECTED_FPG, + pat=True), + mock.call.getfsnap(expected_snap_pattern, pat=True), + ] + self.mock_client.assert_has_calls(expected_calls) + self.assertIsNone(result) + + def test_find_fsnap_exception(self): + self.init_mediator() + + self.mock_client.getfsnap.side_effect = Exception('test unexpected') + + self.assertRaises(exception.ShareBackendException, + self.mediator._find_fsnap, + constants.EXPECTED_PROJECT_ID, + constants.EXPECTED_SHARE_ID, + constants.NFS, + constants.EXPECTED_SNAP_ID, + constants.EXPECTED_FPG, + constants.EXPECTED_VFS) + + expected_snap_pattern = '*_%s' % constants.EXPECTED_SNAP_ID + + self.mock_client.getfsnap.assert_called_once_with( + expected_snap_pattern, + vfs=constants.EXPECTED_VFS, + fpg=constants.EXPECTED_FPG, + pat=True, + fstore=constants.EXPECTED_PROJECT_ID) + + def test_find_fsnap_hit(self): + self.init_mediator() + + expected_result = {'snapName': 'hit'} + self.mock_client.getfsnap.return_value = { + 'total': 1, + 'members': [expected_result] + } + + result = self.mediator._find_fsnap(constants.EXPECTED_PROJECT_ID, + constants.EXPECTED_SHARE_ID, + constants.NFS, + constants.EXPECTED_SNAP_ID, + constants.EXPECTED_FPG, + constants.EXPECTED_VFS) + + expected_snap_pattern = '*_%s' % constants.EXPECTED_SNAP_ID + + self.mock_client.getfsnap.assert_called_once_with( + expected_snap_pattern, + vfs=constants.EXPECTED_VFS, + fpg=constants.EXPECTED_FPG, + pat=True, + fstore=constants.EXPECTED_PROJECT_ID) + + self.assertEqual(expected_result, result)