Skip to content

Commit c0a7ff3

Browse files
committed
WIP: support vdi_revert on fileSR
Signed-off-by: Antoine Bartuccio <antoine.bartuccio@vates.tech>
1 parent 1f39b32 commit c0a7ff3

File tree

3 files changed

+157
-43
lines changed

3 files changed

+157
-43
lines changed

drivers/FileSR.py

Lines changed: 138 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@
1616
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1717
#
1818
# FileSR: local-file storage repository
19+
from contextlib import contextmanager
1920

20-
from sm_typing import Dict, Optional, List, override
21+
from sm_typing import Dict, Optional, List, override, Tuple, Union
2122

2223
import SR
2324
import VDI
@@ -41,11 +42,12 @@
4142
from constants import CBTLOG_TAG
4243

4344
geneology: Dict[str, List[str]] = {}
44-
CAPABILITIES = ["SR_PROBE", "SR_UPDATE", \
45-
"VDI_CREATE", "VDI_DELETE", "VDI_ATTACH", "VDI_DETACH", \
45+
CAPABILITIES = ["SR_PROBE", "SR_UPDATE",
46+
"VDI_CREATE", "VDI_DELETE", "VDI_ATTACH", "VDI_DETACH",
4647
"VDI_CLONE", "VDI_SNAPSHOT", "VDI_RESIZE", "VDI_MIRROR",
4748
"VDI_GENERATE_CONFIG", "ATOMIC_PAUSE", "VDI_CONFIG_CBT",
48-
"VDI_ACTIVATE", "VDI_DEACTIVATE", "THIN_PROVISIONING"]
49+
"VDI_ACTIVATE", "VDI_DEACTIVATE", "THIN_PROVISIONING",
50+
"VDI_REVERT"]
4951

5052
CONFIGURATION = [
5153
['location', 'local directory path (required)'],
@@ -68,7 +70,8 @@
6870
OPS_EXCLUSIVE = [
6971
"sr_create", "sr_delete", "sr_probe", "sr_attach", "sr_detach",
7072
"sr_scan", "vdi_init", "vdi_create", "vdi_delete", "vdi_attach",
71-
"vdi_detach", "vdi_resize_online", "vdi_snapshot", "vdi_clone"]
73+
"vdi_detach", "vdi_resize_online", "vdi_snapshot", "vdi_clone",
74+
"vdi_revert"]
7275

7376
DRIVER_CONFIG = {"ATTACH_FROM_CONFIG_WITH_TAPDISK": True}
7477

@@ -447,7 +450,7 @@ class FileVDI(VDI.VDI):
447450
PARAM_QCOW2: VdiType.QCOW2
448451
}
449452

450-
def _find_path_with_retries(self, vdi_uuid, maxretry=5, period=2.0):
453+
def _get_path_and_type(self, vdi_uuid, maxretry=5, period=2.0) -> Tuple[Optional[str], Optional[str]]:
451454
raw_path = os.path.join(self.sr.path, "%s.%s" % \
452455
(vdi_uuid, self.PARAM_RAW))
453456
vhd_path = os.path.join(self.sr.path, "%s.%s" % \
@@ -456,39 +459,43 @@ def _find_path_with_retries(self, vdi_uuid, maxretry=5, period=2.0):
456459
(vdi_uuid, self.PARAM_QCOW2))
457460
cbt_path = os.path.join(self.sr.path, "%s.%s" %
458461
(vdi_uuid, CBTLOG_TAG))
459-
found = False
460462
tries = 0
461-
while tries < maxretry and not found:
463+
while tries < maxretry:
462464
tries += 1
463465
if util.ioretry(lambda: util.pathexists(vhd_path)):
464-
self.vdi_type = VdiType.VHD
465-
self.path = vhd_path
466-
found = True
467-
elif util.ioretry(lambda: util.pathexists(qcow2_path)):
468-
self.vdi_type = VdiType.QCOW2
469-
self.path = qcow2_path
470-
found = True
471-
elif util.ioretry(lambda: util.pathexists(raw_path)):
472-
self.vdi_type = VdiType.RAW
473-
self.path = raw_path
474-
self.hidden = False
475-
found = True
476-
elif util.ioretry(lambda: util.pathexists(cbt_path)):
477-
self.vdi_type = VdiType.CBTLOG
478-
self.path = cbt_path
479-
self.hidden = False
480-
found = True
481-
482-
if found:
483-
try:
484-
self.cowutil = getCowUtil(self.vdi_type)
485-
except:
486-
pass
487-
else:
488-
util.SMlog("VDI %s not found, retry %s of %s" % (vdi_uuid, tries, maxretry))
489-
time.sleep(period)
466+
return vhd_path, VdiType.VHD
467+
468+
if util.ioretry(lambda: util.pathexists(qcow2_path)):
469+
return qcow2_path, VdiType.QCOW2
470+
471+
if util.ioretry(lambda: util.pathexists(raw_path)):
472+
return raw_path, VdiType.RAW
473+
474+
if util.ioretry(lambda: util.pathexists(cbt_path)):
475+
return cbt_path, VdiType.CBTLOG
476+
477+
util.SMlog("VDI %s not found, retry %s of %s" % (vdi_uuid, tries, maxretry))
478+
time.sleep(period)
479+
480+
return None, None
490481

491-
return found
482+
def _find_path_with_retries(self, vdi_uuid, maxretry=5, period=2.0) -> bool:
483+
path, vdi_type = self._get_path_and_type(vdi_uuid, maxretry, period)
484+
if not path or not vdi_type:
485+
return False
486+
487+
self.path = path
488+
self.vdi_type = vdi_type
489+
490+
if vdi_type in [VdiType.RAW, VdiType.CBTLOG]:
491+
self.hidden = False
492+
493+
try:
494+
self.cowutil = getCowUtil(self.vdi_type)
495+
except:
496+
pass
497+
498+
return True
492499

493500
@override
494501
def load(self, vdi_uuid) -> None:
@@ -739,6 +746,93 @@ def resize(self, sr_uuid, vdi_uuid, size) -> str:
739746
def clone(self, sr_uuid, vdi_uuid) -> str:
740747
return self._do_snapshot(sr_uuid, vdi_uuid, VDI.SNAPSHOT_DOUBLE)
741748

749+
@contextmanager
750+
def _tap_pause(self, secondary=None):
751+
if not blktap2.VDI.tap_pause(self.session, self.sr.uuid, self.uuid):
752+
raise util.SMException(f"Could not pause disk {self.uuid} on sr {self.sr.uuid}")
753+
try:
754+
yield
755+
finally:
756+
blktap2.VDI.tap_unpause(self.session, self.sr.uuid, self.uuid, secondary)
757+
758+
759+
@override
760+
def revert(self, sr_uuid, src_uuid, dest_uuid):
761+
util.SMlog("---------------------------------------------------------------->")
762+
util.SMlog(f"in: {src_uuid} - {self.uuid}")
763+
764+
if self.label == "base copy":
765+
raise xs_errors.XenError(f"{self.uuid} is a base copy.")
766+
767+
dest = VDI.VDI.from_uuid(self.sr.session, dest_uuid)
768+
util.SMlog(f"out: {dest_uuid} - {dest.uuid}")
769+
770+
if self.vdi_type != dest.vdi_type:
771+
raise xs_errors.XenError(f"{self.uuid} and {dest.uuid} has incompatible types {self.vdi_type} != {dest.vdi_type}")
772+
773+
774+
if not self._checkpath(self.path):
775+
raise xs_errors.XenError(f"Could not find {self.path}")
776+
777+
if not dest._checkpath(dest.path):
778+
raise xs_errors.XenError(f"Could not find {dest.path}")
779+
780+
if self.parent != dest.parent:
781+
raise xs_errors.XenError("Not implemented yet")
782+
783+
self._ensure_not_max_depth()
784+
785+
dest_tmp_uuid = util.gen_uuid() # Will be replaced by dest.uuid at the end
786+
dest_tmp_path = os.path.join(dest.sr.path, "%s%s" % (dest_tmp_uuid, VDI_TYPE_TO_EXTENSION[dest.vdi_type]))
787+
788+
# snapshot = self._do_snapshot(sr_uuid, src_uuid, VDI.SNAPSHOT_SINGLE)
789+
# util.SMlog(snapshot)
790+
src_parent_path, _ = self._get_path_and_type(self.parent)
791+
if not src_parent_path:
792+
raise xs_errors.XenError(f"Could not find parent of {self.uuid}")
793+
794+
795+
with self._tap_pause(), dest._tap_pause():
796+
# try:
797+
util.fistpoint.activate_custom_fn(
798+
"FileSR_fail_snap1",
799+
self.__fist_enospace)
800+
util.ioretry(lambda: self._snap(dest_tmp_path, src_parent_path, False))
801+
self.cowutil.setHidden(dest_tmp_path, True)
802+
803+
if self.parent != dest.parent:
804+
pass # Do more operation
805+
806+
image_info = VdiType.isCowImage(self.vdi_type)
807+
util.SMlog(f"J'ai écrittttttttttttt iciciiiiiii {dest_tmp_path}")
808+
self._rename(dest_tmp_path, dest.path)
809+
util.SMlog(f"J'ai renoméééééé iciciiiiiii {dest.path}")
810+
811+
image_info = dest.cowutil.getInfo(dest.path, FileVDI.extractUuid)
812+
dest.utilisation = image_info.sizePhys
813+
dest.size = image_info.sizeVirt
814+
dest.hidden = False
815+
dest.parent = image_info.parentUuid
816+
817+
dest.cowutil.setHidden(dest.path, False)
818+
dest._db_update()
819+
820+
return dest.get_params()
821+
822+
823+
# except util.CommandException as inst:
824+
# # TODO: cleanup
825+
# # XXX: it might be too late if the base disk has been marked as deleted!
826+
# # self._clonecleanup(src, dst, newsrc)
827+
# # util.end_log_entry(self.sr.path, self.path, ["error"])
828+
# # raise xs_errors.XenError('VDIClone',
829+
# # opterr='VDI clone failed error %d' % inst.code)
830+
# pass
831+
832+
util.SMlog("<---------------------------------------------------------------")
833+
raise xs_errors.XenError('Heloiastrnie')
834+
835+
742836
@override
743837
def compose(self, sr_uuid, vdi1, vdi2) -> None:
744838
if not VdiType.isCowImage(self.vdi_type):
@@ -812,6 +906,14 @@ def _create_new_parent(self, src, newsrc):
812906
def __fist_enospace(self):
813907
raise util.CommandException(28, "cowutil snapshot", reason="No space")
814908

909+
def _ensure_not_max_depth(self):
910+
depth = self.cowutil.getDepth(self.path)
911+
if depth == -1:
912+
raise xs_errors.XenError('VDIUnavailable', \
913+
opterr='failed to get image depth')
914+
elif depth >= self.cowutil.getMaxChainLength():
915+
raise xs_errors.XenError('SnapshotChainTooLong')
916+
815917
def _snapshot(self, snap_type, cbtlog=None, cbt_consistency=None, is_mirror_destination=False):
816918
util.SMlog("FileVDI._snapshot for %s (type %s)" % (self.uuid, snap_type))
817919

@@ -831,12 +933,7 @@ def _snapshot(self, snap_type, cbtlog=None, cbt_consistency=None, is_mirror_dest
831933
if self.hidden:
832934
raise xs_errors.XenError('VDIClone', opterr='hidden VDI')
833935

834-
depth = self.cowutil.getDepth(self.path)
835-
if depth == -1:
836-
raise xs_errors.XenError('VDIUnavailable', \
837-
opterr='failed to get image depth')
838-
elif depth >= self.cowutil.getMaxChainLength():
839-
raise xs_errors.XenError('SnapshotChainTooLong')
936+
self._ensure_not_max_depth()
840937

841938
newuuid = util.gen_uuid()
842939
src = self.path

drivers/SRCommand.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
"vdi_activate", "vdi_deactivate", "vdi_attach_from_config", "vdi_detach_from_config",
3737
"vdi_generate_config", "vdi_compose", "vdi_epoch_begin",
3838
"vdi_epoch_end", "vdi_enable_cbt", "vdi_disable_cbt", "vdi_data_destroy",
39-
"vdi_list_changed_blocks"]
39+
"vdi_list_changed_blocks", "vdi_revert"]
4040

4141
# don't log the commands that spam the log file too much
4242
NO_LOGGING = {
@@ -56,7 +56,8 @@
5656
"vdi_resize": "VDIResize",
5757
"vdi_resize_online": "VDIResize",
5858
"vdi_snapshot": "VDISnapshot",
59-
"vdi_clone": "VDIClone"
59+
"vdi_clone": "VDIClone",
60+
"vdi_revert": "VDIRevert",
6061
}
6162

6263

@@ -269,6 +270,13 @@ def _run(self, sr, target):
269270
elif self.cmd == 'vdi_clone':
270271
return target.clone(self.params['sr_uuid'], self.vdi_uuid)
271272

273+
elif self.cmd == 'vdi_revert':
274+
return target.revert(
275+
self.params['sr_uuid'],
276+
self.vdi_uuid,
277+
sr.session.xenapi.VDI.get_record(self.params['args'][0])["uuid"],
278+
)
279+
272280
elif self.cmd == 'vdi_resize':
273281
return target.resize(self.params['sr_uuid'], self.vdi_uuid, int(self.params['args'][0]))
274282

drivers/VDI.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,15 @@ def resize(self, sr_uuid, vdi_uuid, size) -> str:
249249
"""
250250
raise xs_errors.XenError('Unimplemented')
251251

252+
def revert(self, sr_uuid, vdi_uuid, target_uuid):
253+
"""Replaces the contents of the target_uuid VDI with the contents of the vdi_uuid
254+
without changing the identitity of the target (i.e. name-label, uuid and location
255+
are guaranteed to remain the same)..
256+
257+
This operation IS idempotent and the vdi pointed by vdi_uuid is preserved.
258+
"""
259+
raise xs_errors.XenError('Unimplemented')
260+
252261
def resize_cbt(self, sr_uuid, vdi_uuid, size):
253262
"""Resize the given VDI to size <size> MB. Size can
254263
be any valid disk size greater than [or smaller than]

0 commit comments

Comments
 (0)