VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/tests/storage/tdStorageSnapshotMerging1.py@ 75373

Last change on this file since 75373 was 75373, checked in by vboxsync, 7 years ago

Main: bugref:6598: Added ability to merge mediums with different sizes in the offline mode

  • Property svn:eol-style set to LF
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 15.8 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# $Id: tdStorageSnapshotMerging1.py 75373 2018-11-09 18:12:30Z vboxsync $
4
5"""
6VirtualBox Validation Kit - Storage snapshotting and merging testcase.
7"""
8
9__copyright__ = \
10"""
11Copyright (C) 2013-2017 Oracle Corporation
12
13This file is part of VirtualBox Open Source Edition (OSE), as
14available from http://www.virtualbox.org. This file is free software;
15you can redistribute it and/or modify it under the terms of the GNU
16General Public License (GPL) as published by the Free Software
17Foundation, in version 2 as it comes in the "COPYING" file of the
18VirtualBox OSE distribution. VirtualBox OSE is distributed in the
19hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
20
21The contents of this file may alternatively be used under the terms
22of the Common Development and Distribution License Version 1.0
23(CDDL) only, as it comes in the "COPYING.CDDL" file of the
24VirtualBox OSE distribution, in which case the provisions of the
25CDDL are applicable instead of those of the GPL.
26
27You may elect to license modified versions of this file under the
28terms and conditions of either the GPL or the CDDL or both.
29"""
30__version__ = "$Revision: 75373 $"
31
32# Standard Python imports.
33import os;
34import sys;
35import uuid;
36import zlib;
37
38# Only the main script needs to modify the path.
39try: __file__
40except: __file__ = sys.argv[0];
41g_ksValidationKitDir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))));
42sys.path.append(g_ksValidationKitDir);
43
44# Validation Kit imports.
45from testdriver import reporter;
46from testdriver import base;
47from testdriver import vbox;
48from testdriver import vboxcon;
49from testdriver import vboxwrappers;
50
51def _ControllerTypeToName(eControllerType):
52 """ Translate a controller type to a name. """
53 if eControllerType == vboxcon.StorageControllerType_PIIX3 or eControllerType == vboxcon.StorageControllerType_PIIX4:
54 sType = "IDE Controller";
55 elif eControllerType == vboxcon.StorageControllerType_IntelAhci:
56 sType = "SATA Controller";
57 elif eControllerType == vboxcon.StorageControllerType_LsiLogicSas:
58 sType = "SAS Controller";
59 elif eControllerType == vboxcon.StorageControllerType_LsiLogic or eControllerType == vboxcon.StorageControllerType_BusLogic:
60 sType = "SCSI Controller";
61 else:
62 sType = "Storage Controller";
63 return sType;
64
65def crc32_of_file(filepath):
66 fileobj = open(filepath,'rb');
67 current = 0;
68
69 while True:
70 buf = fileobj.read(1024 * 1024);
71 if not buf:
72 break
73 current = zlib.crc32(buf, current);
74
75 fileobj.close();
76 return current % 2**32;
77
78class tdStorageSnapshot(vbox.TestDriver): # pylint: disable=R0902
79 """
80 Storage benchmark.
81 """
82 def __init__(self):
83 vbox.TestDriver.__init__(self);
84 self.asRsrcs = None;
85 self.oGuestToGuestVM = None;
86 self.oGuestToGuestSess = None;
87 self.oGuestToGuestTxs = None;
88 self.asStorageCtrlsDef = ['AHCI', 'IDE', 'LsiLogicSAS', 'LsiLogic', 'BusLogic'];
89 self.asStorageCtrls = self.asStorageCtrlsDef;
90 #self.asDiskFormatsDef = ['VDI', 'VMDK', 'VHD', 'QED', 'Parallels', 'QCOW', 'iSCSI'];
91 self.asDiskFormatsDef = ['VDI', 'VMDK', 'VHD'];
92 self.asDiskFormats = self.asDiskFormatsDef;
93 self.sRndData = os.urandom(100*1024*1024);
94
95 #
96 # Overridden methods.
97 #
98 def showUsage(self):
99 rc = vbox.TestDriver.showUsage(self);
100 reporter.log('');
101 reporter.log('tdStorageSnapshot1 Options:');
102 reporter.log(' --storage-ctrls <type1[:type2[:...]]>');
103 reporter.log(' Default: %s' % (':'.join(self.asStorageCtrls)));
104 reporter.log(' --disk-formats <type1[:type2[:...]]>');
105 reporter.log(' Default: %s' % (':'.join(self.asDiskFormats)));
106 return rc;
107
108 def parseOption(self, asArgs, iArg): # pylint: disable=R0912,R0915
109 if asArgs[iArg] == '--storage-ctrls':
110 iArg += 1;
111 if iArg >= len(asArgs):
112 raise base.InvalidOption('The "--storage-ctrls" takes a colon separated list of Storage controller types');
113 self.asStorageCtrls = asArgs[iArg].split(':');
114 elif asArgs[iArg] == '--disk-formats':
115 iArg += 1;
116 if iArg >= len(asArgs): raise base.InvalidOption('The "--disk-formats" takes a colon separated list of disk formats');
117 self.asDiskFormats = asArgs[iArg].split(':');
118 else:
119 return vbox.TestDriver.parseOption(self, asArgs, iArg);
120 return iArg + 1;
121
122 def getResourceSet(self):
123 # Construct the resource list the first time it's queried.
124 if self.asRsrcs is None:
125 self.asRsrcs = ['5.3/storage/mergeMedium/t-orig.vdi', '5.3/storage/mergeMedium/t-fixed.vdi', '5.3/storage/mergeMedium/t-resized.vdi'];
126 return self.asRsrcs;
127
128 def actionExecute(self):
129 """
130 Execute the testcase.
131 """
132 fRc = self.test1();
133 return fRc;
134
135 def resizeMedium(self, oMedium, cbNewSize):
136 if oMedium.deviceType is not vboxcon.DeviceType_HardDisk:
137 return False;
138
139 if oMedium.type is not vboxcon.MediumType_Normal:
140 return False;
141
142 #currently only VDI can be resizable. Medium variant is not checked, because testcase creates disks itself
143 oMediumFormat = oMedium.mediumFormat;
144 if oMediumFormat.id != 'VDI':
145 return False;
146
147 cbCurrSize = oMedium.logicalSize;
148 # currently reduce is not supported
149 if cbNewSize < cbCurrSize:
150 return False;
151
152 try:
153 oProgressCom = oMedium.resize(cbNewSize);
154 oProgress = vboxwrappers.ProgressWrapper(oProgressCom, self.oVBoxMgr, self.oVBox.oTstDrv, 'Resize medium %s' % (oMedium.name));
155 oProgress.wait(cMsTimeout = 60 * 1000);
156 oProgress.logResult();
157 except:
158 reporter.logXcpt('IMedium::resize failed on %s' % (oMedium.name));
159 return False;
160
161 return True;
162
163 def getMedium(self, oVM, sController):
164 oMediumAttachments = oVM.getMediumAttachmentsOfController(sController);
165
166 for oAttachment in oMediumAttachments:
167 oMedium = oAttachment.medium;
168 if oMedium.deviceType is not vboxcon.DeviceType_HardDisk:
169 continue;
170 if oMedium.type is not vboxcon.MediumType_Normal:
171 continue;
172 return oMedium;
173
174 return None;
175
176 def getSnapshotMedium(self, oSnapshot, sController):
177 oVM = oSnapshot.machine;
178 oMedium = self.getMedium(oVM, sController);
179
180 for oChildMedium in oMedium.children:
181 for uSnapshotId in oChildMedium.getSnapshotIds(oVM.id):
182 if uSnapshotId == oVM.id:
183 return oChildMedium;
184
185 return None;
186
187 def openMedium(self, sHd, fImmutable = False):
188 """
189 Opens medium in readonly mode.
190 Returns Medium object on success and None on failure. Error information is logged.
191 """
192 sFullName = self.oVBox.oTstDrv.getFullResourceName(sHd);
193 try:
194 oHd = self.oVBox.findHardDisk(sFullName);
195 except:
196 try:
197 if self.fpApiVer >= 4.1:
198 oHd = self.oVBox.openMedium(sFullName, vboxcon.DeviceType_HardDisk, vboxcon.AccessMode_ReadOnly, False);
199 elif self.fpApiVer >= 4.0:
200 oHd = self.oVBox.openMedium(sFullName, vboxcon.DeviceType_HardDisk, vboxcon.AccessMode_ReadOnly);
201 else:
202 oHd = self.oVBox.openHardDisk(sFullName, vboxcon.AccessMode_ReadOnly, False, "", False, "");
203
204 except:
205 reporter.errorXcpt('failed to open hd "%s"' % (sFullName));
206 return False;
207
208 try:
209 if fImmutable:
210 oHd.type = vboxcon.MediumType_Immutable;
211 else:
212 oHd.type = vboxcon.MediumType_Normal;
213
214 except:
215 if fImmutable:
216 reporter.errorXcpt('failed to set hd "%s" immutable' % (sHd));
217 else:
218 reporter.errorXcpt('failed to set hd "%s" normal' % (sHd));
219
220 return None;
221
222 return oHd;
223
224 def cloneMedium(self, oSrcHd, oTgtHd):
225 """
226 Clones medium into target medium.
227 """
228 try:
229 oProgressCom = oSrcHd.cloneTo(oTgtHd, (vboxcon.MediumVariant_Standard, ), None);
230 oProgress = vboxwrappers.ProgressWrapper(oProgressCom, self.oVBoxMgr, self.oVBox.oTstDrv, 'clone base disk %s to %s' % (oSrcHd.name, oTgtHd.name));
231 oProgress.wait(cMsTimeout = 60 * 1000);
232 oProgress.logResult();
233 except:
234 reporter.errorXcpt('failed to clone medium %s to %s' % (oSrcHd.name, oTgtHd.name));
235 return False;
236
237 return True;
238
239 def deleteVM(self, oVM):
240 try:
241 oVM.unregister(vboxcon.CleanupMode_DetachAllReturnNone);
242 except:
243 reporter.logXcpt();
244 pass;
245
246 if self.fpApiVer >= 4.0:
247 try:
248 if self.fpApiVer >= 4.3:
249 oProgress = oVM.deleteConfig([]);
250 else:
251 oProgress = oVM.delete(None);
252 self.waitOnProgress(oProgress);
253
254 except:
255 reporter.logXcpt();
256
257 else:
258 try: oVM.deleteSettings();
259 except: reporter.logXcpt();
260
261 return None;
262
263 #
264 # Test execution helpers.
265 #
266
267 def test1OneCfg(self, eStorageController, oDskFmt):
268 """
269 Runs the specified VM thru test #1.
270
271 Returns a success indicator on the general test execution. This is not
272 the actual test result.
273 """
274
275 (asExts, aTypes) = oDskFmt.describeFileExtensions()
276 for i in range(0, len(asExts)): #pylint: disable=consider-using-enumerate
277 if aTypes[i] is vboxcon.DeviceType_HardDisk:
278 sExt = '.' + asExts[i]
279 break
280
281 if sExt is None:
282 return False;
283
284 oOrigBaseHd = self.openMedium('5.3/storage/mergeMedium/t-orig.vdi');
285 if oOrigBaseHd is None:
286 return False;
287
288 #currently only VDI can be resizable. Medium variant is not checked, because testcase creates disks itself
289 fFmtDynamic = oDskFmt.id == 'VDI';
290 sOrigWithDiffHd = '5.3/storage/mergeMedium/t-fixed.vdi'
291 uOrigCrc = 0x7a417cbb;
292
293 if fFmtDynamic:
294 sOrigWithDiffHd = '5.3/storage/mergeMedium/t-resized.vdi';
295 uOrigCrc = 0xa8f5daa3;
296
297 oOrigWithDiffHd = self.openMedium(sOrigWithDiffHd);
298 if oOrigWithDiffHd is None:
299 return False;
300
301 oVM = self.createTestVM('testvm', 1, None);
302 if oVM is None:
303 return False;
304
305 sController = _ControllerTypeToName(eStorageController);
306
307 # Reconfigure the VM
308 oSession = self.openSession(oVM);
309 if oSession is None:
310 return False;
311 # Attach HD
312
313 fRc = True;
314 sFile = 't-base' + sExt;
315 sHddPath = os.path.join(self.oVBox.oTstDrv.sScratchPath, sFile);
316 oHd = oSession.createBaseHd(sHddPath, sFmt=oDskFmt.id, cb=oOrigBaseHd.logicalSize);
317 #if oSession.createBaseHd can't create disk because it exists, oHd will point to some stub object anyway
318 fRc = fRc and oHd is not None and oHd.logicalSize == oOrigBaseHd.logicalSize;
319 fRc = fRc and self.cloneMedium(oOrigBaseHd, oHd);
320
321 fRc = fRc and oSession.ensureControllerAttached(sController);
322 fRc = fRc and oSession.setStorageControllerType(eStorageController, sController);
323 fRc = fRc and oSession.saveSettings();
324 fRc = fRc and oSession.attachHd(sHddPath, sController, iPort = 0, fImmutable=False, fForceResource=False)
325
326 if fRc:
327 oSession.takeSnapshot('Base snapshot');
328 oSnapshot = oSession.findSnapshot('Base snapshot');
329
330 if oSnapshot is not None:
331 oSnapshotMedium = self.getSnapshotMedium(oSnapshot, sController);
332 fRc = oSnapshotMedium is not None;
333
334 if fFmtDynamic:
335 fRc = fRc and self.resizeMedium(oSnapshotMedium, oOrigWithDiffHd.logicalSize);
336 fRc = fRc and self.cloneMedium(oOrigWithDiffHd, oSnapshotMedium);
337 fRc = fRc and oSession.deleteSnapshot(oSnapshot.id, cMsTimeout = 120 * 1000);
338
339 if fRc:
340 # disk for result test by checksum
341 sResFilePath = os.path.join(self.oVBox.oTstDrv.sScratchPath, 't_res.vmdk');
342 sResFilePathRaw = os.path.join(self.oVBox.oTstDrv.sScratchPath, 't_res-flat.vmdk');
343 oResHd = oSession.createBaseHd(sResFilePath, sFmt='VMDK', cb=oOrigWithDiffHd.logicalSize, tMediumVariant = (vboxcon.MediumVariant_Fixed, ));
344 fRc = oResHd is not None;
345 fRc = fRc and self.cloneMedium(oHd, oResHd);
346
347 uResCrc32 = 0;
348 if fRc:
349 uResCrc32 = crc32_of_file(sResFilePathRaw);
350 if uResCrc32 == uOrigCrc:
351 reporter.log('Snapshot merged successfully. Data of the result medium are correspond to data of the original medium');
352 fRc = True;
353 else:
354 reporter.error('Snapshot merging failed. Data of the result medium not correspond to data of the original medium');
355 fRc = False;
356
357 self.oVBox.deleteHdByMedium(oResHd);
358
359 if oSession is not None:
360 if oHd is not None:
361 oSession.detachHd(sController, iPort = 0, iDevice = 0);
362
363 oSession.saveSettings(fClose = True);
364 if oHd is not None:
365 self.oVBox.deleteHdByMedium(oHd);
366
367 self.deleteVM(oVM);
368 return fRc;
369
370 def test1(self):
371 """
372 Executes test #1 thru the various configurations.
373 """
374 if not self.importVBoxApi():
375 return False;
376
377 sVmName = 'testvm';
378 reporter.testStart(sVmName);
379
380 aoDskFmts = self.oVBoxMgr.getArray(self.oVBox.systemProperties, 'mediumFormats')
381 if aoDskFmts is None or len(aoDskFmts) < 1:
382 return False;
383
384 fRc = True;
385 for sStorageCtrl in self.asStorageCtrls:
386 reporter.testStart(sStorageCtrl);
387 if sStorageCtrl == 'AHCI':
388 eStorageCtrl = vboxcon.StorageControllerType_IntelAhci;
389 elif sStorageCtrl == 'IDE':
390 eStorageCtrl = vboxcon.StorageControllerType_PIIX4;
391 elif sStorageCtrl == 'LsiLogicSAS':
392 eStorageCtrl = vboxcon.StorageControllerType_LsiLogicSas;
393 elif sStorageCtrl == 'LsiLogic':
394 eStorageCtrl = vboxcon.StorageControllerType_LsiLogic;
395 elif sStorageCtrl == 'BusLogic':
396 eStorageCtrl = vboxcon.StorageControllerType_BusLogic;
397 else:
398 eStorageCtrl = None;
399
400 for oDskFmt in aoDskFmts:
401 if (oDskFmt.id in self.asDiskFormats):
402 reporter.testStart('%s' % (oDskFmt.id));
403 fRc = self.test1OneCfg(eStorageCtrl, oDskFmt);
404 reporter.testDone();
405 if not fRc:
406 break;
407
408 reporter.testDone();
409 if not fRc:
410 break;
411
412 reporter.testDone();
413 return fRc;
414
415if __name__ == '__main__':
416 sys.exit(tdStorageSnapshot().main(sys.argv));
417
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette