VirtualBox

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

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

scm --update-copyright-year

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