def delete_snapshot(self, snapshot): """Delete snapshot of existing volume. :param snapshot: snapshot reference """ sname = jcom.sname(snapshot.id) LOG.debug('deleating snapshot %s.', sname) snapshots = None try: snapshots = self.ra.get_snapshots(sname) except jexc.JDSSResourceNotFoundException: LOG.debug('physical volume %s dne, it was already ' 'deleted.', sname) return except jexc.JDSSException as jerr: raise exception.VolumeBackendAPIException(jerr) snapshots = self._clean_garbage_snapshots(sname, snapshots) if len(snapshots) > 0: self._hide_object(sname) else: self._gc_delete(sname)
def test_delete_snapshot_has_clone(self): jdssd, ctx = self.get_driver(CONFIG_OK) sname = jcom.sname(UUID_2) snap = fake_snapshot.fake_snapshot_obj(ctx, id=UUID_2) jdssd.ra.get_snapshots.return_value = SNAPSHOTS_EMPTY patches = [ mock.patch.object(jdssd, "_clean_garbage_snapshots", return_value=SNAPSHOTS_CLONE), mock.patch.object(jdssd, "_clone_object", return_value=None), mock.patch.object(jdssd, "_hide_object", return_value=None), mock.patch.object(jdssd, "_gc_delete", return_value=None) ] self.start_patches(patches) jdssd.create_snapshot(snap) jdssd.delete_snapshot(snap) jdssd._gc_delete.assert_not_called() jdssd._hide_object.assert_called_once_with(sname) jdssd._clean_garbage_snapshots.assert_called_once_with( sname, SNAPSHOTS_EMPTY) self.stop_patches(patches)
def create_volume_from_snapshot(self, volume, snapshot): """Create a volume from a snapshot. If volume_type extra specs includes 'replication: <is> True' the driver needs to create a volume replica (secondary), and setup replication between the newly created volume and the secondary volume. """ LOG.debug('create volume %(vol)s from snapshot %(snap)s', { 'vol': volume.id, 'snap': snapshot.id }) cvname = jcom.vname(volume.id) sname = jcom.sname(snapshot.id) self._clone_object(sname, cvname) clone_size = 0 try: clone_size = int(self.ra.get_lun(cvname)['volsize']) except jexc.JDSSException as jerr: self._delete_back_recursively(sname, cvname) raise exception.VolumeBackendAPIException( _("Fail in cloning snapshot %(snap)s to %(clone)s.") % { 'snap': snapshot.id, 'clone': volume.id }) from jerr try: if clone_size < o_units.Gi * int(volume.size): self.extend_volume(volume, int(volume.size)) except exception.VolumeBackendAPIException: # If volume can't be set to a proper size make sure to clean it # before failing try: self._delete_back_recursively(cvname, cvname) except exception.VolumeBackendAPIException as err: msg = ("Hidden snapshot %s of volume %s " "have to be removed manualy, " "as automatic removal failed: %s") LOG.warning(msg, cvname, sname, err) raise provider_location = self._get_provider_location(volume.id) provider_auth = self._get_provider_auth() ret = {} if provider_auth is not None: ret['provider_auth'] = provider_auth ret['provider_location'] = provider_location return ret
def test_delete_back_recursively_res_active(self): jdssd, ctx = self.get_driver(CONFIG_OK) opvname = jcom.vname(UUID_1) opsname = jcom.sname(UUID_2) jdssd._delete_back_recursively(opvname, opsname) jdssd.ra.delete_snapshot.assert_called_once_with( opvname, opsname, recursively_children=True, recursively_dependents=True, force_umount=True)
def test_delete_back_recursively_hidden_have_snapshots(self): jdssd, ctx = self.get_driver(CONFIG_OK) opvname = jcom.hidden(UUID_1) opsname = jcom.sname(UUID_2) jdssd.ra.get_snapshots.return_value = SNAPSHOTS_RECURSIVE_1.copy() jdssd._delete_back_recursively(opvname, opsname) jdssd.ra.delete_snapshot.assert_called_once_with( opvname, opsname, recursively_children=True, recursively_dependents=True, force_umount=True)
def test_clone_object_dne(self): jdssd, ctx = self.get_driver(CONFIG_OK) calls = [] origin = jcom.vname(UUID_1) clone = jcom.vname(UUID_2) calls.append(mock.call(origin, clone)) jdssd.ra.create_snapshot.side_effect = ( jexc.JDSSResourceNotFoundException(res=origin)) self.assertRaises(exception.VolumeNotFound, jdssd._clone_object, origin, clone) origin = jcom.sname(UUID_1) calls.append(mock.call(origin, clone)) self.assertRaises(exception.SnapshotNotFound, jdssd._clone_object, origin, clone) jdssd.ra.create_snapshot.assert_has_calls(calls)
def test_create_snapshot(self): jdssd, ctx = self.get_driver(CONFIG_OK) vname = jcom.vname(UUID_1) sname = jcom.sname(UUID_2) snap = fake_snapshot.fake_snapshot_obj(ctx, id=UUID_2) snap.volume_id = UUID_1 patches = [ mock.patch.object(jdssd, "_clone_object", return_value=None) ] self.start_patches(patches) jdssd.create_snapshot(snap) jdssd._clone_object.assert_called_once_with(vname, sname) self.stop_patches(patches)
def create_snapshot(self, snapshot): """Create snapshot of existing volume. :param snapshot: snapshot reference """ LOG.debug('create snapshot %(snap)s for volume %(vol)s', { 'snap': snapshot.id, 'vol': snapshot.volume_id}) vname = jcom.vname(snapshot.volume_id) sname = jcom.sname(snapshot.id) self._clone_object(vname, sname) try: self.ra.make_readonly_lun(sname) except jexc.JDSSException as err: # Name of snapshot should be the same as a name of volume # that is going to be created from it self._delete_back_recursively(vname, sname) raise exception.VolumeBackendAPIException(err)
def revert_to_snapshot(self, context, volume, snapshot): """Revert volume to snapshot. Note: the revert process should not change the volume's current size, that means if the driver shrank the volume during the process, it should extend the volume internally. """ vname = jcom.vname(volume.id) sname = jcom.sname(snapshot.id) LOG.debug('reverting %(vname)s to %(sname)s', { "vname": vname, "sname": sname }) vsize = None try: vsize = self.ra.get_lun(vname).get('volsize') except jexc.JDSSResourceNotFoundException as jerr: raise exception.VolumeNotFound(volume_id=volume.id) from jerr except jexc.JDSSException as jerr: raise exception.VolumeBackendAPIException(jerr) from jerr if vsize is None: raise exception.VolumeDriverException( _("unable to identify volume size")) try: self.ra.rollback_volume_to_snapshot(vname, sname) except jexc.JDSSException as jerr: raise exception.VolumeBackendAPIException(jerr.message) from jerr try: rvsize = self.ra.get_lun(vname).get('volsize') if rvsize != vsize: self.ra.extend_lun(vname, vsize) except jexc.JDSSResourceNotFoundException as jerr: raise exception.VolumeNotFound(volume_id=volume.id) from jerr except jexc.JDSSException as jerr: raise exception.VolumeBackendAPIException(jerr) from jerr
def test_delete_back_recursively_single_snapshot(self): jdssd, ctx = self.get_driver(CONFIG_OK) opvname = jcom.hidden(UUID_2) opsname = jcom.sname(UUID_3) jdssd.ra.get_snapshots.side_effect = [ SNAPSHOTS_RECURSIVE_CHAIN_1.copy(), SNAPSHOTS_RECURSIVE_CHAIN_2.copy() ] origin = "Pool-0/{vorig}@{sorig}".format(vorig=jcom.vname(UUID_1), sorig=jcom.vname(UUID_2)) get_lun_resp = { 'origin': origin, 'vscan': None, 'full_name': 'Pool-0/' + jcom.hidden(UUID_2), 'userrefs': None, 'primarycache': 'all', 'logbias': 'latency', 'creation': '1591543140', 'sync': 'always', 'is_clone': True, 'dedup': 'off', 'sharenfs': None, 'receive_resume_token': None, 'volsize': '1073741824' } jdssd.ra.get_lun.return_value = get_lun_resp jdssd._delete_back_recursively(opvname, opsname) jdssd.ra.delete_snapshot.assert_called_once_with( jcom.vname(UUID_1), jcom.vname(UUID_2), recursively_children=True, recursively_dependents=True, force_umount=True) get_snapshots_expected = [mock.call(opvname)] jdssd.ra.get_snapshots.assert_has_calls(get_snapshots_expected)
def test_create_volume_from_snapshot_extend(self): jdssd, ctx = self.get_driver(CONFIG_OK) origin_sname = jcom.sname(UUID_1) clone_vname = jcom.vname(UUID_2) orig_snap = fake_snapshot.fake_snapshot_obj(ctx) orig_snap.id = UUID_1 clone_vol = fake_volume.fake_volume_obj(ctx) clone_vol.id = UUID_2 clone_vol.size = 2 host = CONFIG_OK["san_hosts"][0] port = CONFIG_OK["target_port"] target_name = CONFIG_OK["target_prefix"] + UUID_2 location = '{host}:{port},1 {name} 0'.format(host=host, port=port, name=target_name) cred_format = (r"CHAP [0-9,a-z,A-Z]{{{name_len}}} " "[0-9,a-z,A-Z]{{{pass_len}}}").format( name_len=8, pass_len=CONFIG_OK['chap_password_len']) patches = [ mock.patch.object(jdssd, "_clone_object", return_value=None), mock.patch.object(jdssd, "extend_volume", return_value=None), mock.patch.object(jdssd, "_get_provider_location", return_value=location), mock.patch.object(jdssd, "_get_provider_auth", return_value=cred_format) ] jdssd.ra.get_lun.return_value = { 'vscan': None, 'full_name': 'Pool-0/' + UUID_2, 'userrefs': None, 'primarycache': 'all', 'logbias': 'latency', 'creation': '1591543140', 'sync': 'always', 'is_clone': False, 'dedup': 'off', 'sharenfs': None, 'receive_resume_token': None, 'volsize': '1073741824' } self.start_patches(patches) ret = jdssd.create_volume_from_snapshot(clone_vol, orig_snap) jdssd.extend_volume.assert_called_once_with(clone_vol, clone_vol.size) jdssd._clone_object.assert_called_once_with(origin_sname, clone_vname) self.stop_patches(patches) jdssd.ra.get_lun.assert_called_once_with(jcom.vname(clone_vol.id)) self.assertEqual(location, ret['provider_location']) self.assertEqual(cred_format, ret['provider_auth'])
'jovian_recovery_delay': 60, 'jovian_user': '******', 'jovian_password': '******', 'jovian_ignore_tpath': [], 'target_port': 3260, 'jovian_pool': 'Pool-0', 'target_prefix': 'iqn.2020-04.com.open-e.cinder:', 'chap_password_len': 12, 'san_thin_provision': False, 'volume_backend_name': 'JovianDSS', 'reserved_percentage': 10, 'jovian_block_size': '128K' } SNAPSHOTS_CASCADE_1 = [{ "name": jcom.sname(UUID_1), "clones": "Pool-0/" + jcom.sname(UUID_1) }, { "name": jcom.sname(UUID_2), "clones": "Pool-0/" + jcom.sname(UUID_2) }, { "name": jcom.sname(UUID_3), "clones": "Pool-0/" + jcom.sname(UUID_3) }] SNAPSHOTS_CASCADE_2 = [{ "name": jcom.sname(UUID_1), "clones": "Pool-0/" + jcom.sname(UUID_1) }, { "name": jcom.vname(UUID_2), "clones": "Pool-0/" + jcom.vname(UUID_2)