VirtualBox

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

Last change on this file was 106061, checked in by vboxsync, 2 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to LF
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 15.5 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# $Id: tdStorageSnapshotMerging1.py 106061 2024-09-16 14:03:52Z vboxsync $
4
5"""
6VirtualBox Validation Kit - Storage snapshotting and merging testcase.
7"""
8
9__copyright__ = \
10"""
11Copyright (C) 2013-2024 Oracle and/or its affiliates.
12
13This file is part of VirtualBox base platform packages, as
14available from https://www.virtualbox.org.
15
16This program is free software; you can redistribute it and/or
17modify it under the terms of the GNU General Public License
18as published by the Free Software Foundation, in version 3 of the
19License.
20
21This program is distributed in the hope that it will be useful, but
22WITHOUT ANY WARRANTY; without even the implied warranty of
23MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24General Public License for more details.
25
26You should have received a copy of the GNU General Public License
27along with this program; if not, see <https://www.gnu.org/licenses>.
28
29The contents of this file may alternatively be used under the terms
30of the Common Development and Distribution License Version 1.0
31(CDDL), a copy of it is provided in the "COPYING.CDDL" file included
32in the VirtualBox distribution, in which case the provisions of the
33CDDL are applicable instead of those of the GPL.
34
35You may elect to license modified versions of this file under the
36terms and conditions of either the GPL or the CDDL or both.
37
38SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
39"""
40__version__ = "$Revision: 106061 $"
41
42
43# Standard Python imports.
44import os;
45import sys;
46
47# Only the main script needs to modify the path.
48try: __file__ # pylint: disable=used-before-assignment
49except: __file__ = sys.argv[0];
50g_ksValidationKitDir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))));
51sys.path.append(g_ksValidationKitDir);
52
53# Validation Kit imports.
54from common import utils;
55from testdriver import reporter;
56from testdriver import base;
57from testdriver import vbox;
58from testdriver import vboxcon;
59from testdriver import vboxwrappers;
60
61# Python 3 hacks:
62if sys.version_info[0] >= 3:
63 long = int; # pylint: disable=redefined-builtin,invalid-name
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'];
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 = long(0x7a417cbb);
287
288 if fFmtDynamic:
289 sOrigWithDiffHd = '5.3/storage/mergeMedium/t-resized.vdi';
290 uOrigCrc = long(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 cMsTimeout = 15 * 60 * 1000); # 15 min
313 #if oSession.createBaseHd can't create disk because it exists, oHd will point to some stub object anyway
314 fRc = fRc and oHd is not None and (oHd.logicalSize == oOrigBaseHd.logicalSize);
315 fRc = fRc and self.cloneMedium(oOrigBaseHd, oHd);
316
317 fRc = fRc and oSession.ensureControllerAttached(sController);
318 fRc = fRc and oSession.setStorageControllerType(eStorageController, sController);
319 fRc = fRc and oSession.saveSettings();
320 fRc = fRc and oSession.attachHd(sHddPath, sController, iPort = 0, fImmutable=False, fForceResource=False)
321
322 if fRc:
323 oSession.takeSnapshot('Base snapshot');
324 oSnapshot = oSession.findSnapshot('Base snapshot');
325
326 if oSnapshot is not None:
327 oSnapshotMedium = self.getSnapshotMedium(oSnapshot, sController);
328 fRc = oSnapshotMedium is not None;
329
330 if fFmtDynamic:
331 fRc = fRc and self.resizeMedium(oSnapshotMedium, oOrigWithDiffHd.logicalSize);
332 fRc = fRc and self.cloneMedium(oOrigWithDiffHd, oSnapshotMedium);
333 fRc = fRc and oSession.deleteSnapshot(oSnapshot.id, cMsTimeout = 120 * 1000);
334
335 if fRc:
336 # disk for result test by checksum
337 sResFilePath = os.path.join(self.oVBox.oTstDrv.sScratchPath, 't_res.vmdk');
338 sResFilePathRaw = os.path.join(self.oVBox.oTstDrv.sScratchPath, 't_res-flat.vmdk');
339 oResHd = oSession.createBaseHd(sResFilePath, sFmt='VMDK', cb=oOrigWithDiffHd.logicalSize,
340 tMediumVariant = (vboxcon.MediumVariant_Fixed, ),
341 cMsTimeout = 15 * 60 * 1000); # 15 min
342 fRc = oResHd is not None;
343 fRc = fRc and self.cloneMedium(oHd, oResHd);
344
345 uResCrc32 = long(0);
346 if fRc:
347 uResCrc32 = long(utils.calcCrc32OfFile(sResFilePathRaw));
348 if uResCrc32 == uOrigCrc:
349 reporter.log('Snapshot merged successfully. Crc32 is correct');
350 fRc = True;
351 else:
352 reporter.error('Snapshot merging failed. Crc32 is invalid');
353 fRc = False;
354
355 self.oVBox.deleteHdByMedium(oResHd);
356
357 if oSession is not None:
358 if oHd is not None:
359 oSession.detachHd(sController, iPort = 0, iDevice = 0);
360
361 oSession.saveSettings(fClose = True);
362 if oHd is not None:
363 self.oVBox.deleteHdByMedium(oHd);
364
365 self.deleteVM(oVM);
366 return fRc;
367
368 def test1(self):
369 """
370 Executes test #1 thru the various configurations.
371 """
372 if not self.importVBoxApi():
373 return False;
374
375 sVmName = 'testvm';
376 reporter.testStart(sVmName);
377
378 aoDskFmts = self.oVBoxMgr.getArray(self.oVBox.systemProperties, 'mediumFormats')
379 if aoDskFmts is None or not aoDskFmts:
380 return False;
381
382 fRc = True;
383 for sStorageCtrl in self.asStorageCtrls:
384 reporter.testStart(sStorageCtrl);
385 if sStorageCtrl == 'AHCI':
386 eStorageCtrl = vboxcon.StorageControllerType_IntelAhci;
387 elif sStorageCtrl == 'IDE':
388 eStorageCtrl = vboxcon.StorageControllerType_PIIX4;
389 elif sStorageCtrl == 'LsiLogicSAS':
390 eStorageCtrl = vboxcon.StorageControllerType_LsiLogicSas;
391 elif sStorageCtrl == 'LsiLogic':
392 eStorageCtrl = vboxcon.StorageControllerType_LsiLogic;
393 elif sStorageCtrl == 'BusLogic':
394 eStorageCtrl = vboxcon.StorageControllerType_BusLogic;
395 else:
396 eStorageCtrl = None;
397
398 for oDskFmt in aoDskFmts:
399 if oDskFmt.id in self.asDiskFormats:
400 reporter.testStart('%s' % (oDskFmt.id));
401 fRc = self.test1OneCfg(eStorageCtrl, oDskFmt);
402 reporter.testDone();
403 if not fRc:
404 break;
405
406 reporter.testDone();
407 if not fRc:
408 break;
409
410 reporter.testDone();
411 return fRc;
412
413if __name__ == '__main__':
414 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