VirtualBox

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

Last change on this file since 79323 was 79323, checked in by vboxsync, 5 years ago

Main: bugref:6598: Fixed testcase crashed during VM deleting

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

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