VirtualBox

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

Last change on this file since 75378 was 75378, checked in by vboxsync, 6 years ago

Main: bugref:6598: Fixed pylint notices

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