Skip to content

Commit

Permalink
Merge pull request hpe-storage#34 from hpe-storage/plugin_v2
Browse files Browse the repository at this point in the history
Plugin v2
  • Loading branch information
sonivi authored and sonivi committed Sep 26, 2018
2 parents 487b1ec + c25d849 commit b1d1c9e
Show file tree
Hide file tree
Showing 8 changed files with 63 additions and 48 deletions.
5 changes: 2 additions & 3 deletions hpedockerplugin/hpe/hpe_3par_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
from oslo_utils import importutils
from oslo_config import cfg
from oslo_log import log as logging
from oslo_service import loopingcall
from oslo_utils import units

from hpedockerplugin import exception
Expand Down Expand Up @@ -1336,8 +1335,8 @@ def create_cloned_volume(self, dst_volume, src_vref):

optional = {'priority': 1}
self.client.copyVolume(src_3par_vol_name,
dst_3par_vol_name, None,
optional=optional)
dst_3par_vol_name, None,
optional=optional)

comments = {'volume_id': dst_volume['id'],
'name': dst_volume['name'],
Expand Down
3 changes: 3 additions & 0 deletions hpedockerplugin/hpe/volume.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import uuid
from hpedockerplugin.hpe import utils

DEFAULT_SIZE = 100
DEFAULT_PROV = "thin"
Expand All @@ -25,6 +26,8 @@ def createvol(name, size=DEFAULT_SIZE, prov=DEFAULT_PROV,
volume = {}
volume['id'] = str(uuid.uuid4())
volume['name'] = volume['id']
volume['3par_vol_name'] = utils.get_3par_name(volume['id'],
is_snap)
volume['host'] = ''
volume['size'] = size
volume['availability_zone'] = ''
Expand Down
41 changes: 34 additions & 7 deletions hpedockerplugin/volume_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,8 +242,10 @@ def create_volume(self, volname, vol_size, vol_prov,
vol_flash, compression_val, vol_qos,
mount_conflict_delay, False, cpg, snap_cpg,
False, current_backend)

bkend_vol_name = ""
try:
self._create_volume(vol, undo_steps)
bkend_vol_name = self._create_volume(vol, undo_steps)
self._apply_volume_specs(vol, undo_steps)
if rcg_name:
# bkend_rcg_name = self._get_3par_rcg_name(rcg_name)
Expand All @@ -260,6 +262,7 @@ def create_volume(self, volname, vol_size, vol_prov,
# This will make get_vol_byname more efficient
vol['fsOwner'] = fs_owner
vol['fsMode'] = fs_mode
vol['3par_vol_name'] = bkend_vol_name
self._etcd.save_vol(vol)

except Exception as ex:
Expand Down Expand Up @@ -508,14 +511,14 @@ def clone_volume(self, src_vol_name, clone_name,
# add prefix '*' because offline copy task name have pattern like
# e.g. dcv-m0o5ZAwPReaZVoymnLTrMA->dcv-N.9ikeA.RiaxPP4LzecaEQ
# this will check both offline as well as online copy task
if self._hpeplugin_driver.is_vol_having_active_task("*%s" % volume_3par):
if self._hpeplugin_driver.is_vol_having_active_task(
"*%s" % volume_3par):
msg = 'source volume: %s / %s is having some active task ' \
'running on array' % (src_vol_name, volume_3par)
LOG.debug(msg)
response = json.dumps({u"Err": msg})
return response


if not size:
size = src_vol['size']
if not cpg:
Expand Down Expand Up @@ -602,13 +605,13 @@ def _create_snapshot(self, src_vol_name, schedName, snapshot_name,
# add prefix '*' because offline copy task name have pattern like
# e.g. dcv-m0o5ZAwPReaZVoymnLTrMA->dcv-N.9ikeA.RiaxPP4LzecaEQ
# this will check both offline as well as online copy task
if self._hpeplugin_driver.is_vol_having_active_task("*%s" % volume_3par):
if self._hpeplugin_driver.is_vol_having_active_task(
"*%s" % volume_3par):
msg = 'source volume: %s / %s is having some active task ' \
'running on array' % (src_vol_name, volume_3par)
LOG.debug(msg)
response = json.dumps({u"Err": msg})
return response


# Check if this is an old volume type. If yes, add is_snap flag to it
if 'is_snap' not in vol:
Expand Down Expand Up @@ -677,6 +680,7 @@ def _create_snapshot(self, src_vol_name, schedName, snapshot_name,
'display_description': 'snapshot of volume %s'
% src_vol_name}
undo_steps = []
bkend_snap_name = ""
try:
bkend_snap_name = self._hpeplugin_driver.create_snapshot(
snapshot)
Expand Down Expand Up @@ -714,9 +718,12 @@ def _create_snapshot(self, src_vol_name, schedName, snapshot_name,
vol['snapshots'].append(db_snapshot)
snap_vol['snap_metadata'] = db_snapshot
snap_vol['backend'] = current_backend
snap_vol['3par_vol_name'] = bkend_snap_name

try:
self._create_snapshot_record(snap_vol, snapshot_name, undo_steps)
self._create_snapshot_record(snap_vol,
snapshot_name,
undo_steps)

# For now just track volume to uuid mapping internally
# TODO: Save volume name and uuid mapping in etcd as well
Expand Down Expand Up @@ -853,14 +860,17 @@ def _clone_volume(self, clone_name, src_vol, size, cpg,
False, cpg, snap_cpg, False,
current_backend)
try:
self.__clone_volume__(src_vol, clone_vol, undo_steps)
bkend_clone_name = self.__clone_volume__(src_vol,
clone_vol,
undo_steps)
self._apply_volume_specs(clone_vol, undo_steps)
# For now just track volume to uuid mapping internally
# TODO: Save volume name and uuid mapping in etcd as well
# This will make get_vol_byname more efficient
clone_vol['fsOwner'] = src_vol.get('fsOwner')
clone_vol['fsMode'] = src_vol.get('fsMode')
clone_vol['backend'] = src_vol.get('backend')
clone_vol['3par_vol_name'] = bkend_clone_name
self._etcd.save_vol(clone_vol)

except Exception as ex:
Expand Down Expand Up @@ -940,6 +950,14 @@ def _get_snapshot_response(self, snapinfo, snapname):
if 'snap_schedule' in metadata:
snap_detail['snap_schedule'] = metadata['snap_schedule']

LOG.info('_get_snapshot_response: adding 3par vol info')

if '3par_vol_name' in snapinfo:
snap_detail['3par_vol_name'] = snapinfo.get('3par_vol_name')
else:
snap_detail['3par_vol_name'] = utils.get_3par_name(snapinfo['id'],
True)

snapshot['Status'].update({'snap_detail': snap_detail})

response = json.dumps({u"Err": err, u"Volume": snapshot})
Expand Down Expand Up @@ -1076,6 +1094,15 @@ def get_volume_snap_details(self, volname, snapname, qualified_name):
'mount_conflict_delay')
vol_detail['cpg'] = volinfo.get('cpg')
vol_detail['snap_cpg'] = volinfo.get('snap_cpg')

LOG.info(' get_volume_snap_details : adding 3par vol info')
if '3par_vol_name' in volinfo:
vol_detail['3par_vol_name'] = volinfo['3par_vol_name']
else:
vol_detail['3par_vol_name'] = \
utils.get_3par_name(volinfo['id'],
False)

if volinfo.get('rcg_info'):
vol_detail['secondary_cpg'] = \
self.tgt_bkend_config.hpe3par_cpg[0]
Expand Down
47 changes: 14 additions & 33 deletions test/clonevolume_tester.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ def setup_mock_objects(self):

mock_3parclient = self.mock_objects['mock_3parclient']
mock_3parclient.copyVolume.return_value = {'taskid': data.TASK_ID}
mock_3parclient.isOnlinePhysicalCopy.return_value = False
mock_3parclient.getCPG.return_value = {}


Expand All @@ -44,6 +45,7 @@ def setup_mock_objects(self):

mock_3parclient = self.mock_objects['mock_3parclient']
mock_3parclient.copyVolume.return_value = {'taskid': data.TASK_ID}
mock_3parclient.isOnlinePhysicalCopy.return_value = False
mock_3parclient.getCPG.return_value = {}

def check_response(self, resp):
Expand All @@ -64,7 +66,6 @@ def check_response(self, resp):
mock_3parclient = self.mock_objects['mock_3parclient']
mock_3parclient.createVolume.assert_called()
mock_3parclient.copyVolume.assert_called()
mock_3parclient.getTask.assert_called()
mock_3parclient.modifyVolume.assert_called()

def get_request_params(self):
Expand All @@ -80,42 +81,11 @@ def setup_mock_objects(self):

mock_3parclient = self.mock_objects['mock_3parclient']
mock_3parclient.copyVolume.return_value = {'taskid': data.TASK_ID}
mock_3parclient.isOnlinePhysicalCopy.return_value = False
mock_3parclient.getCPG.return_value = {}
mock_3parclient.getTask.return_value = {'status': data.TASK_DONE}


# Make copyVolume operation fail
class TestCloneOfflineCopyFails(CloneVolumeUnitTest):
def check_response(self, resp):
# Match error substring with returned error string
err_received = resp['Err']
err_expected = 'copy volume task failed: create_cloned_volume'
self._test_case.assertIn(err_expected, err_received)

# Check following 3PAR APIs were invoked
mock_3parclient = self.mock_objects['mock_3parclient']
mock_3parclient.createVolume.assert_called()
mock_3parclient.copyVolume.assert_called()
mock_3parclient.getTask.assert_called()

def get_request_params(self):
return {"Name": "clone-vol-001",
"Opts": {"cloneOf": data.VOLUME_NAME,
# Difference in size of source and cloned volume
# triggers offline copy. Src size is 2.
"size": 20}}

def setup_mock_objects(self):
mock_etcd = self.mock_objects['mock_etcd']
mock_etcd.get_vol_byname.return_value = data.volume

mock_3parclient = self.mock_objects['mock_3parclient']
mock_3parclient.getCPG.return_value = {}
mock_3parclient.copyVolume.return_value = {'taskid': data.TASK_ID}
# TASK_FAILED simulates failure of copyVolume() operation
mock_3parclient.getTask.return_value = {'status': data.TASK_FAILED}


class TestCloneInvalidSourceVolume(CloneVolumeUnitTest):
def check_response(self, resp):
expected_msg = "source volume: %s does not exist" % data.VOLUME_NAME
Expand Down Expand Up @@ -147,6 +117,8 @@ def setup_mock_objects(self):
mock_etcd = self.mock_objects['mock_etcd']
# Source volume that is to be cloned
mock_etcd.get_vol_byname.return_value = data.volume
mock_3parclient = self.mock_objects['mock_3parclient']
mock_3parclient.isOnlinePhysicalCopy.return_value = False

def check_response(self, resp):
expected_msg = "clone volume size 1 is less than source volume size 2"
Expand Down Expand Up @@ -174,6 +146,7 @@ def setup_mock_objects(self):

mock_3parclient = self.mock_objects['mock_3parclient']
mock_3parclient.copyVolume.return_value = {'taskid': data.TASK_ID}
mock_3parclient.isOnlinePhysicalCopy.return_value = False
mock_3parclient.getCPG.return_value = {}


Expand All @@ -198,6 +171,7 @@ def setup_mock_objects(self):

mock_3parclient = self.mock_objects['mock_3parclient']
mock_3parclient.copyVolume.return_value = {'taskid': data.TASK_ID}
mock_3parclient.isOnlinePhysicalCopy.return_value = False
mock_3parclient.getCPG.return_value = {}


Expand All @@ -220,6 +194,7 @@ def setup_mock_objects(self):

mock_3parclient = self.mock_objects['mock_3parclient']
mock_3parclient.copyVolume.return_value = {'taskid': data.TASK_ID}
mock_3parclient.isOnlinePhysicalCopy.return_value = False
mock_3parclient.getCPG.return_value = {}


Expand Down Expand Up @@ -251,6 +226,7 @@ def setup_mock_objects(self):
mock_3parclient = self.mock_objects['mock_3parclient']
mock_3parclient.copyVolume.return_value = {'taskid': data.TASK_ID}
mock_3parclient.getCPG.return_value = {}
mock_3parclient.isOnlinePhysicalCopy.return_value = False
# Make addVolumeToVolumeSet fail by throwing exception
mock_3parclient.addVolumeToVolumeSet.side_effect = \
[exceptions.HTTPNotFound('fake')]
Expand Down Expand Up @@ -286,6 +262,7 @@ def setup_mock_objects(self):

mock_3parclient = self.mock_objects['mock_3parclient']
mock_3parclient.copyVolume.return_value = {'taskid': data.TASK_ID}
mock_3parclient.isOnlinePhysicalCopy.return_value = False
mock_3parclient.getCPG.return_value = {}


Expand Down Expand Up @@ -315,6 +292,7 @@ def setup_mock_objects(self):
mock_3parclient = self.mock_objects['mock_3parclient']
mock_3parclient.copyVolume.return_value = {'taskid': data.TASK_ID}
mock_3parclient.getCPG.return_value = {}
mock_3parclient.isOnlinePhysicalCopy.return_value = False
# Make addVolumeToVolumeSet fail by throwing exception
mock_3parclient.modifyVolumeSet.side_effect = [
exceptions.HTTPInternalServerError("Internal server error")
Expand Down Expand Up @@ -350,6 +328,7 @@ def setup_mock_objects(self):

mock_3parclient = self.mock_objects['mock_3parclient']
mock_3parclient.copyVolume.return_value = {'taskid': data.TASK_ID}
mock_3parclient.isOnlinePhysicalCopy.return_value = False
mock_3parclient.getCPG.return_value = {}


Expand Down Expand Up @@ -381,6 +360,7 @@ def setup_mock_objects(self):
mock_3parclient.copyVolume.return_value = {'taskid': data.TASK_ID}
mock_3parclient.getCPG.return_value = {}
mock_3parclient.getVolumeMetaData.return_value = {'value': True}
mock_3parclient.isOnlinePhysicalCopy.return_value = False
mock_3parclient.getTask.return_value = {'status': data.TASK_DONE}


Expand Down Expand Up @@ -411,5 +391,6 @@ def setup_mock_objects(self):
'revision': 0}
mock_3parclient.copyVolume.return_value = {'taskid': data.TASK_ID}
mock_3parclient.getCPG.return_value = {}
mock_3parclient.isOnlinePhysicalCopy.return_value = False
mock_3parclient.getStorageSystemInfo.return_value = \
{'licenseInfo': {'licenses': [{'name': 'Compression'}]}}
6 changes: 6 additions & 0 deletions test/createsnapshot_tester.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ def setup_mock_objects(self):
copy.deepcopy(data.volume),
None
]
mock_3parclient = self.mock_objects['mock_3parclient']
mock_3parclient.isOnlinePhysicalCopy.return_value = False

def check_response(self, resp):
self._test_case.assertEqual(resp, {u"Err": ''})
Expand All @@ -52,6 +54,8 @@ def setup_mock_objects(self):
None,
copy.deepcopy(data.volume)
]
mock_3parclient = self.mock_objects['mock_3parclient']
mock_3parclient.isOnlinePhysicalCopy.return_value = False

def check_response(self, resp):
self._test_case.assertEqual(resp, {u"Err": ''})
Expand Down Expand Up @@ -124,6 +128,8 @@ def setup_mock_objects(self):
]
mock_etcd.save_vol.side_effect = \
[hpe_exc.HPEPluginSaveFailed(obj='snap-001')]
mock_3parclient = self.mock_objects['mock_3parclient']
mock_3parclient.isOnlinePhysicalCopy.return_value = False

def check_response(self, resp):
expected = "ETCD data save failed: snap-001"
Expand Down
1 change: 1 addition & 0 deletions test/fake_3par_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
SNAPSHOT_ID3 = 'f5d9e226-2995-4d66-a5bd-3e373f4ff772'
SNAPSHOT_NAME3 = 'snapshot-3'
VOLUME_3PAR_NAME = 'dcv-0DM4qZEVSKON-DXN-NwVpw'
SNAPSHOT_3PAR_NAME1 = 'dcs-0DM4qZEVSKON-DXN-NwVpw'
SNAPSHOT_3PAR_NAME = 'dcs-L4I73ONuTci9Fd4ceij-MQ'
TARGET_IQN = 'iqn.2000-05.com.3pardata:21810002ac00383d'
TARGET_LUN = 90
Expand Down
3 changes: 3 additions & 0 deletions test/getvolume_tester.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ def check_response(self, resp):
u'vvset_name': u'vvk_vvset'
},
u'volume_detail': {
u'3par_vol_name': data.VOLUME_3PAR_NAME,
u'compression': None,
u'flash_cache': None,
u'fsMode': None,
Expand Down Expand Up @@ -94,6 +95,7 @@ def check_response(self, resp):
u'Devicename': u'',
u'Status': {
u'volume_detail': {
u'3par_vol_name': data.VOLUME_3PAR_NAME,
u'compression': None,
u'flash_cache': None,
u'provisioning': u'dedup',
Expand Down Expand Up @@ -151,6 +153,7 @@ def setup_mock_objects(self):

def check_response(self, resp):
snap_detail = {
u'3par_vol_name': data.SNAPSHOT_3PAR_NAME,
u'compression': None,
u'is_snap': True,
u'parent_id': data.VOLUME_ID,
Expand Down
5 changes: 0 additions & 5 deletions test/test_hpe_plugin_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,11 +218,6 @@ def test_clone_offline_copy(self):
test = clonevolume_tester.TestCloneOfflineCopy()
test.run_test(self)

@tc_banner_decorator
def test_clone_offline_copy_fails(self):
test = clonevolume_tester.TestCloneOfflineCopyFails()
test.run_test(self)

@tc_banner_decorator
def test_clone_invalid_source_volume(self):
test = clonevolume_tester.TestCloneInvalidSourceVolume()
Expand Down

0 comments on commit b1d1c9e

Please sign in to comment.