VirtualBox

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

Last change on this file since 94124 was 94124, checked in by vboxsync, 3 years ago

ValKit/utils.py,tests: Move crc32_of_file to common/utils.py as calcCrc32OfFile, no point in having two copies of it. pylint fixes.

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