VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/tests/storage/tdStorageBenchmark1.py@ 68703

Last change on this file since 68703 was 68703, checked in by vboxsync, 8 years ago

ValidationKit/tdStorageBenchmark: Add option to test with encryption configured

  • Property svn:eol-style set to LF
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 55.2 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# $Id: tdStorageBenchmark1.py 68703 2017-09-07 17:57:15Z vboxsync $
4
5"""
6VirtualBox Validation Kit - Storage benchmark.
7"""
8
9__copyright__ = \
10"""
11Copyright (C) 2012-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: 68703 $"
31
32
33# Standard Python imports.
34import os;
35import socket;
36import sys;
37import StringIO;
38
39# Only the main script needs to modify the path.
40try: __file__
41except: __file__ = sys.argv[0];
42g_ksValidationKitDir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))));
43sys.path.append(g_ksValidationKitDir);
44
45# Validation Kit imports.
46from common import constants;
47from common import utils;
48from testdriver import reporter;
49from testdriver import base;
50from testdriver import vbox;
51from testdriver import vboxcon;
52from testdriver import vboxwrappers;
53
54import remoteexecutor;
55import storagecfg;
56
57def _ControllerTypeToName(eControllerType):
58 """ Translate a controller type to a name. """
59 if eControllerType == vboxcon.StorageControllerType_PIIX3 or eControllerType == vboxcon.StorageControllerType_PIIX4:
60 sType = "IDE Controller";
61 elif eControllerType == vboxcon.StorageControllerType_IntelAhci:
62 sType = "SATA Controller";
63 elif eControllerType == vboxcon.StorageControllerType_LsiLogicSas:
64 sType = "SAS Controller";
65 elif eControllerType == vboxcon.StorageControllerType_LsiLogic or eControllerType == vboxcon.StorageControllerType_BusLogic:
66 sType = "SCSI Controller";
67 elif eControllerType == vboxcon.StorageControllerType_NVMe:
68 sType = "NVMe Controller";
69 else:
70 sType = "Storage Controller";
71 return sType;
72
73class FioTest(object):
74 """
75 Flexible I/O tester testcase.
76 """
77
78 kdHostIoEngine = {
79 'solaris': ('solarisaio', False),
80 'linux': ('libaio', True)
81 };
82
83 def __init__(self, oExecutor, dCfg = None):
84 self.oExecutor = oExecutor;
85 self.sCfgFileId = None;
86 self.dCfg = dCfg;
87 self.sError = None;
88 self.sResult = None;
89
90 def prepare(self, cMsTimeout = 30000):
91 """ Prepares the testcase """
92
93 sTargetOs = self.dCfg.get('TargetOs', 'linux');
94 sIoEngine, fDirectIo = self.kdHostIoEngine.get(sTargetOs);
95 if sIoEngine is None:
96 return False;
97
98 cfgBuf = StringIO.StringIO();
99 cfgBuf.write('[global]\n');
100 cfgBuf.write('bs=' + self.dCfg.get('RecordSize', '4k') + '\n');
101 cfgBuf.write('ioengine=' + sIoEngine + '\n');
102 cfgBuf.write('iodepth=' + self.dCfg.get('QueueDepth', '32') + '\n');
103 cfgBuf.write('size=' + self.dCfg.get('TestsetSize', '2g') + '\n');
104 if fDirectIo:
105 cfgBuf.write('direct=1\n');
106 else:
107 cfgBuf.write('direct=0\n');
108 cfgBuf.write('directory=' + self.dCfg.get('FilePath', '/mnt') + '\n');
109 cfgBuf.write('filename=fio.test.file');
110
111 cfgBuf.write('[seq-write]\n');
112 cfgBuf.write('rw=write\n');
113 cfgBuf.write('stonewall\n');
114
115 cfgBuf.write('[rand-write]\n');
116 cfgBuf.write('rw=randwrite\n');
117 cfgBuf.write('stonewall\n');
118
119 cfgBuf.write('[seq-read]\n');
120 cfgBuf.write('rw=read\n');
121 cfgBuf.write('stonewall\n');
122
123 cfgBuf.write('[rand-read]\n');
124 cfgBuf.write('rw=randread\n');
125 cfgBuf.write('stonewall\n');
126
127 self.sCfgFileId = self.oExecutor.copyString(cfgBuf.getvalue(), 'aio-test', cMsTimeout);
128 return self.sCfgFileId is not None;
129
130 def run(self, cMsTimeout = 30000):
131 """ Runs the testcase """
132 _ = cMsTimeout
133 fRc, sOutput, sError = self.oExecutor.execBinary('fio', (self.sCfgFileId,), cMsTimeout = cMsTimeout);
134 if fRc:
135 self.sResult = sOutput;
136 else:
137 self.sError = ('Binary: fio\n' +
138 '\nOutput:\n\n' +
139 sOutput +
140 '\nError:\n\n' +
141 sError);
142 return fRc;
143
144 def cleanup(self):
145 """ Cleans up any leftovers from the testcase. """
146
147 def reportResult(self):
148 """
149 Reports the test results to the test manager.
150 """
151 return True;
152
153 def getErrorReport(self):
154 """
155 Returns the error report in case the testcase failed.
156 """
157 return self.sError;
158
159class IozoneTest(object):
160 """
161 I/O zone testcase.
162 """
163 def __init__(self, oExecutor, dCfg = None):
164 self.oExecutor = oExecutor;
165 self.sResult = None;
166 self.sError = None;
167 self.lstTests = [ ('initial writers', 'FirstWrite'),
168 ('rewriters', 'Rewrite'),
169 ('re-readers', 'ReRead'),
170 ('stride readers', 'StrideRead'),
171 ('reverse readers', 'ReverseRead'),
172 ('random readers', 'RandomRead'),
173 ('mixed workload', 'MixedWorkload'),
174 ('random writers', 'RandomWrite'),
175 ('pwrite writers', 'PWrite'),
176 ('pread readers', 'PRead'),
177 ('fwriters', 'FWrite'),
178 ('freaders', 'FRead'),
179 ('readers', 'FirstRead')];
180 self.sRecordSize = dCfg.get('RecordSize', '4k');
181 self.sTestsetSize = dCfg.get('TestsetSize', '2g');
182 self.sQueueDepth = dCfg.get('QueueDepth', '32');
183 self.sFilePath = dCfg.get('FilePath', '/mnt/iozone');
184 self.fDirectIo = True;
185
186 sTargetOs = dCfg.get('TargetOs');
187 if sTargetOs == 'solaris':
188 self.fDirectIo = False;
189
190 def prepare(self, cMsTimeout = 30000):
191 """ Prepares the testcase """
192 _ = cMsTimeout;
193 return True; # Nothing to do.
194
195 def run(self, cMsTimeout = 30000):
196 """ Runs the testcase """
197 tupArgs = ('-r', self.sRecordSize, '-s', self.sTestsetSize, \
198 '-t', '1', '-T', '-F', self.sFilePath + '/iozone.tmp');
199 if self.fDirectIo:
200 tupArgs += ('-I',);
201 fRc, sOutput, sError = self.oExecutor.execBinary('iozone', tupArgs, cMsTimeout = cMsTimeout);
202 if fRc:
203 self.sResult = sOutput;
204 else:
205 self.sError = ('Binary: iozone\n' +
206 '\nOutput:\n\n' +
207 sOutput +
208 '\nError:\n\n' +
209 sError);
210
211 _ = cMsTimeout;
212 return fRc;
213
214 def cleanup(self):
215 """ Cleans up any leftovers from the testcase. """
216 return True;
217
218 def reportResult(self):
219 """
220 Reports the test results to the test manager.
221 """
222
223 fRc = True;
224 if self.sResult is not None:
225 try:
226 asLines = self.sResult.splitlines();
227 for sLine in asLines:
228 sLine = sLine.strip();
229 if sLine.startswith('Children') is True:
230 # Extract the value
231 idxValue = sLine.rfind('=');
232 if idxValue == -1:
233 raise Exception('IozoneTest: Invalid state');
234
235 idxValue += 1;
236 while sLine[idxValue] == ' ':
237 idxValue += 1;
238
239 # Get the reported value, cut off after the decimal point
240 # it is not supported by the testmanager yet and is not really
241 # relevant anyway.
242 idxValueEnd = idxValue;
243 while sLine[idxValueEnd].isdigit():
244 idxValueEnd += 1;
245
246 for sNeedle, sTestVal in self.lstTests:
247 if sLine.rfind(sNeedle) != -1:
248 reporter.testValue(sTestVal, sLine[idxValue:idxValueEnd],
249 constants.valueunit.g_asNames[constants.valueunit.KILOBYTES_PER_SEC]);
250 break;
251 except:
252 fRc = False;
253 else:
254 fRc = False;
255
256 return fRc;
257
258 def getErrorReport(self):
259 """
260 Returns the error report in case the testcase failed.
261 """
262 return self.sError;
263
264class StorTestCfgMgr(object):
265 """
266 Manages the different testcases.
267 """
268
269 def __init__(self, aasTestLvls, aasTestsBlacklist, fnIsCfgSupported = None):
270 self.aasTestsBlacklist = aasTestsBlacklist;
271 self.at3TestLvls = [];
272 self.iTestLvl = 0;
273 self.fnIsCfgSupported = fnIsCfgSupported;
274 for asTestLvl in aasTestLvls:
275 if isinstance(asTestLvl, tuple):
276 asTestLvl, fnTestFmt = asTestLvl;
277 self.at3TestLvls.append((0, fnTestFmt, asTestLvl));
278 else:
279 self.at3TestLvls.append((0, None, asTestLvl));
280
281 self.at3TestLvls.reverse();
282
283 # Get the first non blacklisted test.
284 asTestCfg = self.getCurrentTestCfg();
285 while asTestCfg and self.isTestCfgBlacklisted(asTestCfg):
286 asTestCfg = self.advanceTestCfg();
287
288 iLvl = 0;
289 for sCfg in asTestCfg:
290 reporter.testStart('%s' % (self.getTestIdString(sCfg, iLvl)));
291 iLvl += 1;
292
293 def __del__(self):
294 # Make sure the tests are marked as done.
295 while self.iTestLvl < len(self.at3TestLvls):
296 reporter.testDone();
297 self.iTestLvl += 1;
298
299 def getTestIdString(self, oCfg, iLvl):
300 """
301 Returns a potentially formatted string for the test name.
302 """
303
304 # The order of the test levels is reversed so get the level starting
305 # from the end.
306 _, fnTestFmt, _ = self.at3TestLvls[len(self.at3TestLvls) - 1 - iLvl];
307 if fnTestFmt is not None:
308 return fnTestFmt(oCfg);
309 return oCfg;
310
311 def isTestCfgBlacklisted(self, asTestCfg):
312 """
313 Returns whether the given test config is black listed.
314 """
315 fBlacklisted = False;
316
317 for asTestBlacklist in self.aasTestsBlacklist:
318 iLvl = 0;
319 fBlacklisted = True;
320 while iLvl < len(asTestBlacklist) and iLvl < len(asTestCfg):
321 if asTestBlacklist[iLvl] != asTestCfg[iLvl] and asTestBlacklist[iLvl] != '*':
322 fBlacklisted = False;
323 break;
324
325 iLvl += 1;
326
327 if not fBlacklisted and self.fnIsCfgSupported is not None:
328 fBlacklisted = not self.fnIsCfgSupported(asTestCfg);
329
330 return fBlacklisted;
331
332 def advanceTestCfg(self):
333 """
334 Advances to the next test config and returns it as an
335 array of strings or an empty config if there is no test left anymore.
336 """
337 iTestCfg, fnTestFmt, asTestCfg = self.at3TestLvls[self.iTestLvl];
338 iTestCfg += 1;
339 self.at3TestLvls[self.iTestLvl] = (iTestCfg, fnTestFmt, asTestCfg);
340 while iTestCfg == len(asTestCfg) and self.iTestLvl < len(self.at3TestLvls):
341 self.at3TestLvls[self.iTestLvl] = (0, fnTestFmt, asTestCfg);
342 self.iTestLvl += 1;
343 if self.iTestLvl < len(self.at3TestLvls):
344 iTestCfg, fnTestFmt, asTestCfg = self.at3TestLvls[self.iTestLvl];
345 iTestCfg += 1;
346 self.at3TestLvls[self.iTestLvl] = (iTestCfg, fnTestFmt, asTestCfg);
347 if iTestCfg < len(asTestCfg):
348 self.iTestLvl = 0;
349 break;
350 else:
351 break; # We reached the end of our tests.
352
353 return self.getCurrentTestCfg();
354
355 def getCurrentTestCfg(self):
356 """
357 Returns the current not black listed test config as an array of strings.
358 """
359 asTestCfg = [];
360
361 if self.iTestLvl < len(self.at3TestLvls):
362 for t3TestLvl in self.at3TestLvls:
363 iTestCfg, _, asTestLvl = t3TestLvl;
364 asTestCfg.append(asTestLvl[iTestCfg]);
365
366 asTestCfg.reverse()
367
368 return asTestCfg;
369
370 def getNextTestCfg(self, fSkippedLast = False):
371 """
372 Returns the next not blacklisted test config or an empty list if
373 there is no test left.
374 """
375 asTestCfgCur = self.getCurrentTestCfg();
376
377 asTestCfg = self.advanceTestCfg();
378 while asTestCfg and self.isTestCfgBlacklisted(asTestCfg):
379 asTestCfg = self.advanceTestCfg();
380
381 # Compare the current and next config and close the approriate test
382 # categories.
383 reporter.testDone(fSkippedLast);
384 if asTestCfg:
385 idxSame = 0;
386 while asTestCfgCur[idxSame] == asTestCfg[idxSame]:
387 idxSame += 1;
388
389 for i in range(idxSame, len(asTestCfg) - 1):
390 reporter.testDone();
391
392 for i in range(idxSame, len(asTestCfg)):
393 reporter.testStart('%s' % (self.getTestIdString(asTestCfg[i], i)));
394
395 else:
396 # No more tests, mark all tests as done
397 for i in range(0, len(asTestCfgCur) - 1):
398 reporter.testDone();
399
400 return asTestCfg;
401
402class tdStorageBenchmark(vbox.TestDriver): # pylint: disable=R0902
403 """
404 Storage benchmark.
405 """
406
407 # Global storage configs for the testbox
408 kdStorageCfgs = {
409 'testboxstor1.de.oracle.com': r'c[3-9]t\dd0\Z',
410 'adaris': [ '/dev/sda' ]
411 };
412
413 # Available test sets.
414 kdTestSets = {
415 # Mostly for developing and debugging the testcase.
416 'Fast': {
417 'RecordSize': '64k',
418 'TestsetSize': '100m',
419 'QueueDepth': '32',
420 'DiskSizeGb': 2
421 },
422 # For quick functionality tests where benchmark results are not required.
423 'Functionality': {
424 'RecordSize': '64k',
425 'TestsetSize': '2g',
426 'QueueDepth': '32',
427 'DiskSizeGb': 10
428 },
429 # For benchmarking the I/O stack.
430 'Benchmark': {
431 'RecordSize': '64k',
432 'TestsetSize': '20g',
433 'QueueDepth': '32',
434 'DiskSizeGb': 30
435 },
436 # For stress testing which takes a lot of time.
437 'Stress': {
438 'RecordSize': '64k',
439 'TestsetSize': '2t',
440 'QueueDepth': '32',
441 'DiskSizeGb': 10000
442 },
443 };
444
445 # Dictionary mapping the virtualization mode mnemonics to a little less cryptic
446 # strings used in test descriptions.
447 kdVirtModeDescs = {
448 'raw' : 'Raw-mode',
449 'hwvirt' : 'HwVirt',
450 'hwvirt-np' : 'NestedPaging'
451 };
452
453 kdHostIoCacheDescs = {
454 'default' : 'HostCacheDef',
455 'hostiocache' : 'HostCacheOn',
456 'no-hostiocache' : 'HostCacheOff'
457 };
458
459 # Password ID for encryption.
460 ksPwId = 'EncPwId';
461
462 # Array indexes for the test configs.
463 kiVmName = 0;
464 kiStorageCtrl = 1;
465 kiHostIoCache = 2;
466 kiDiskFmt = 3;
467 kiDiskVar = 4;
468 kiCpuCount = 5;
469 kiVirtMode = 6;
470 kiIoTest = 7;
471 kiTestSet = 8;
472
473 def __init__(self):
474 vbox.TestDriver.__init__(self);
475 self.asRsrcs = None;
476 self.asTestVMsDef = ['tst-storage', 'tst-storage32'];
477 self.asTestVMs = self.asTestVMsDef;
478 self.asSkipVMs = [];
479 self.asVirtModesDef = ['hwvirt', 'hwvirt-np', 'raw',]
480 self.asVirtModes = self.asVirtModesDef;
481 self.acCpusDef = [1, 2];
482 self.acCpus = self.acCpusDef;
483 self.asStorageCtrlsDef = ['AHCI', 'IDE', 'LsiLogicSAS', 'LsiLogic', 'BusLogic', 'NVMe'];
484 self.asStorageCtrls = self.asStorageCtrlsDef;
485 self.asHostIoCacheDef = ['default', 'hostiocache', 'no-hostiocache'];
486 self.asHostIoCache = self.asHostIoCacheDef;
487 self.asDiskFormatsDef = ['VDI', 'VMDK', 'VHD', 'QED', 'Parallels', 'QCOW', 'iSCSI'];
488 self.asDiskFormats = self.asDiskFormatsDef;
489 self.asDiskVariantsDef = ['Dynamic', 'Fixed', 'DynamicSplit2G', 'FixedSplit2G', 'Network'];
490 self.asDiskVariants = self.asDiskVariantsDef;
491 self.asTestsDef = ['iozone', 'fio'];
492 self.asTests = self.asTestsDef;
493 self.asTestSetsDef = ['Fast', 'Functionality', 'Benchmark', 'Stress'];
494 self.asTestSets = self.asTestSetsDef;
495 self.asIscsiTargetsDef = [ ]; # @todo: Configure one target for basic iSCSI testing
496 self.asIscsiTargets = self.asIscsiTargetsDef;
497 self.cDiffLvlsDef = 0;
498 self.cDiffLvls = self.cDiffLvlsDef;
499 self.fTestHost = False;
500 self.fUseScratch = False;
501 self.fRecreateStorCfg = True;
502 self.fReportBenchmarkResults = True;
503 self.oStorCfg = None;
504 self.sIoLogPathDef = self.sScratchPath;
505 self.sIoLogPath = self.sIoLogPathDef;
506 self.fIoLog = False;
507 self.fUseRamDiskDef = False;
508 self.fUseRamDisk = self.fUseRamDiskDef;
509 self.fEncryptDiskDef = False;
510 self.fEncryptDisk = self.fEncryptDiskDef;
511 self.sEncryptPwDef = 'TestTestTest';
512 self.sEncryptPw = self.sEncryptPwDef;
513 self.sEncryptAlgoDef = 'AES-XTS256-PLAIN64';
514 self.sEncryptAlgo = self.sEncryptAlgoDef;
515
516 #
517 # Overridden methods.
518 #
519 def showUsage(self):
520 rc = vbox.TestDriver.showUsage(self);
521 reporter.log('');
522 reporter.log('tdStorageBenchmark1 Options:');
523 reporter.log(' --virt-modes <m1[:m2[:]]');
524 reporter.log(' Default: %s' % (':'.join(self.asVirtModesDef)));
525 reporter.log(' --cpu-counts <c1[:c2[:]]');
526 reporter.log(' Default: %s' % (':'.join(str(c) for c in self.acCpusDef)));
527 reporter.log(' --storage-ctrls <type1[:type2[:...]]>');
528 reporter.log(' Default: %s' % (':'.join(self.asStorageCtrlsDef)));
529 reporter.log(' --host-io-cache <setting1[:setting2[:...]]>');
530 reporter.log(' Default: %s' % (':'.join(self.asHostIoCacheDef)));
531 reporter.log(' --disk-formats <type1[:type2[:...]]>');
532 reporter.log(' Default: %s' % (':'.join(self.asDiskFormatsDef)));
533 reporter.log(' --disk-variants <variant1[:variant2[:...]]>');
534 reporter.log(' Default: %s' % (':'.join(self.asDiskVariantsDef)));
535 reporter.log(' --iscsi-targets <target1[:target2[:...]]>');
536 reporter.log(' Default: %s' % (':'.join(self.asIscsiTargetsDef)));
537 reporter.log(' --tests <test1[:test2[:...]]>');
538 reporter.log(' Default: %s' % (':'.join(self.asTestsDef)));
539 reporter.log(' --test-sets <set1[:set2[:...]]>');
540 reporter.log(' Default: %s' % (':'.join(self.asTestSetsDef)));
541 reporter.log(' --diff-levels <number of diffs>');
542 reporter.log(' Default: %s' % (self.cDiffLvlsDef));
543 reporter.log(' --test-vms <vm1[:vm2[:...]]>');
544 reporter.log(' Test the specified VMs in the given order. Use this to change');
545 reporter.log(' the execution order or limit the choice of VMs');
546 reporter.log(' Default: %s (all)' % (':'.join(self.asTestVMsDef)));
547 reporter.log(' --skip-vms <vm1[:vm2[:...]]>');
548 reporter.log(' Skip the specified VMs when testing.');
549 reporter.log(' --test-host');
550 reporter.log(' Do all configured tests on the host first and report the results');
551 reporter.log(' to get a baseline');
552 reporter.log(' --use-scratch');
553 reporter.log(' Use the scratch directory for testing instead of setting up');
554 reporter.log(' fresh volumes on dedicated disks (for development)');
555 reporter.log(' --always-wipe-storage-cfg');
556 reporter.log(' Recreate the host storage config before each test');
557 reporter.log(' --dont-wipe-storage-cfg');
558 reporter.log(' Don\'t recreate the host storage config before each test');
559 reporter.log(' --report-benchmark-results');
560 reporter.log(' Report all benchmark results');
561 reporter.log(' --dont-report-benchmark-results');
562 reporter.log(' Don\'t report any benchmark results');
563 reporter.log(' --io-log-path <path>');
564 reporter.log(' Default: %s' % (self.sIoLogPathDef));
565 reporter.log(' --enable-io-log');
566 reporter.log(' Whether to enable I/O logging for each test');
567 reporter.log(' --use-ramdisk');
568 reporter.log(' Default: %s' % (self.fUseRamDiskDef));
569 reporter.log(' --encrypt-disk');
570 reporter.log(' Default: %s' % (self.fEncryptDiskDef));
571 reporter.log(' --encrypt-password');
572 reporter.log(' Default: %s' % (self.sEncryptPwDef));
573 reporter.log(' --encrypt-algorithm');
574 reporter.log(' Default: %s' % (self.sEncryptAlgoDef));
575 return rc;
576
577 def parseOption(self, asArgs, iArg): # pylint: disable=R0912,R0915
578 if asArgs[iArg] == '--virt-modes':
579 iArg += 1;
580 if iArg >= len(asArgs): raise base.InvalidOption('The "--virt-modes" takes a colon separated list of modes');
581 self.asVirtModes = asArgs[iArg].split(':');
582 for s in self.asVirtModes:
583 if s not in self.asVirtModesDef:
584 raise base.InvalidOption('The "--virt-modes" value "%s" is not valid; valid values are: %s' \
585 % (s, ' '.join(self.asVirtModesDef)));
586 elif asArgs[iArg] == '--cpu-counts':
587 iArg += 1;
588 if iArg >= len(asArgs): raise base.InvalidOption('The "--cpu-counts" takes a colon separated list of cpu counts');
589 self.acCpus = [];
590 for s in asArgs[iArg].split(':'):
591 try: c = int(s);
592 except: raise base.InvalidOption('The "--cpu-counts" value "%s" is not an integer' % (s,));
593 if c <= 0: raise base.InvalidOption('The "--cpu-counts" value "%s" is zero or negative' % (s,));
594 self.acCpus.append(c);
595 elif asArgs[iArg] == '--storage-ctrls':
596 iArg += 1;
597 if iArg >= len(asArgs):
598 raise base.InvalidOption('The "--storage-ctrls" takes a colon separated list of Storage controller types');
599 self.asStorageCtrls = asArgs[iArg].split(':');
600 elif asArgs[iArg] == '--host-io-cache':
601 iArg += 1;
602 if iArg >= len(asArgs):
603 raise base.InvalidOption('The "--host-io-cache" takes a colon separated list of I/O cache settings');
604 self.asHostIoCache = asArgs[iArg].split(':');
605 elif asArgs[iArg] == '--disk-formats':
606 iArg += 1;
607 if iArg >= len(asArgs): raise base.InvalidOption('The "--disk-formats" takes a colon separated list of disk formats');
608 self.asDiskFormats = asArgs[iArg].split(':');
609 elif asArgs[iArg] == '--disk-variants':
610 iArg += 1;
611 if iArg >= len(asArgs):
612 raise base.InvalidOption('The "--disk-variants" takes a colon separated list of disk variants');
613 self.asDiskVariants = asArgs[iArg].split(':');
614 elif asArgs[iArg] == '--iscsi-targets':
615 iArg += 1;
616 if iArg >= len(asArgs):
617 raise base.InvalidOption('The "--iscsi-targets" takes a colon separated list of iscsi targets');
618 self.asIscsiTargets = asArgs[iArg].split(':');
619 elif asArgs[iArg] == '--tests':
620 iArg += 1;
621 if iArg >= len(asArgs): raise base.InvalidOption('The "--tests" takes a colon separated list of tests to run');
622 self.asTests = asArgs[iArg].split(':');
623 elif asArgs[iArg] == '--test-sets':
624 iArg += 1;
625 if iArg >= len(asArgs): raise base.InvalidOption('The "--test-sets" takes a colon separated list of test sets');
626 self.asTestSets = asArgs[iArg].split(':');
627 elif asArgs[iArg] == '--diff-levels':
628 iArg += 1;
629 if iArg >= len(asArgs): raise base.InvalidOption('The "--diff-levels" takes an integer');
630 try: self.cDiffLvls = int(asArgs[iArg]);
631 except: raise base.InvalidOption('The "--diff-levels" value "%s" is not an integer' % (asArgs[iArg],));
632 elif asArgs[iArg] == '--test-vms':
633 iArg += 1;
634 if iArg >= len(asArgs): raise base.InvalidOption('The "--test-vms" takes colon separated list');
635 self.asTestVMs = asArgs[iArg].split(':');
636 for s in self.asTestVMs:
637 if s not in self.asTestVMsDef:
638 raise base.InvalidOption('The "--test-vms" value "%s" is not valid; valid values are: %s' \
639 % (s, ' '.join(self.asTestVMsDef)));
640 elif asArgs[iArg] == '--skip-vms':
641 iArg += 1;
642 if iArg >= len(asArgs): raise base.InvalidOption('The "--skip-vms" takes colon separated list');
643 self.asSkipVMs = asArgs[iArg].split(':');
644 for s in self.asSkipVMs:
645 if s not in self.asTestVMsDef:
646 reporter.log('warning: The "--test-vms" value "%s" does not specify any of our test VMs.' % (s));
647 elif asArgs[iArg] == '--test-host':
648 self.fTestHost = True;
649 elif asArgs[iArg] == '--use-scratch':
650 self.fUseScratch = True;
651 elif asArgs[iArg] == '--always-wipe-storage-cfg':
652 self.fRecreateStorCfg = True;
653 elif asArgs[iArg] == '--dont-wipe-storage-cfg':
654 self.fRecreateStorCfg = False;
655 elif asArgs[iArg] == '--report-benchmark-results':
656 self.fReportBenchmarkResults = True;
657 elif asArgs[iArg] == '--dont-report-benchmark-results':
658 self.fReportBenchmarkResults = False;
659 elif asArgs[iArg] == '--io-log-path':
660 iArg += 1;
661 if iArg >= len(asArgs): raise base.InvalidOption('The "--io-log-path" takes a path argument');
662 self.sIoLogPath = asArgs[iArg];
663 elif asArgs[iArg] == '--enable-io-log':
664 self.fIoLog = True;
665 elif asArgs[iArg] == '--use-ramdisk':
666 self.fUseRamDisk = True;
667 elif asArgs[iArg] == '--encrypt-disk':
668 self.fEncryptDisk = True;
669 elif asArgs[iArg] == '--encrypt-password':
670 iArg += 1;
671 if iArg >= len(asArgs): raise base.InvalidOption('The "--encrypt-password" takes a string');
672 self.sEncryptPw = asArgs[iArg];
673 elif asArgs[iArg] == '--encrypt-algorithm':
674 iArg += 1;
675 if iArg >= len(asArgs): raise base.InvalidOption('The "--encrypt-algorithm" takes a string');
676 self.sEncryptAlgo = asArgs[iArg];
677 else:
678 return vbox.TestDriver.parseOption(self, asArgs, iArg);
679 return iArg + 1;
680
681 def completeOptions(self):
682 # Remove skipped VMs from the test list.
683 for sVM in self.asSkipVMs:
684 try: self.asTestVMs.remove(sVM);
685 except: pass;
686
687 return vbox.TestDriver.completeOptions(self);
688
689 def getResourceSet(self):
690 # Construct the resource list the first time it's queried.
691 if self.asRsrcs is None:
692 self.asRsrcs = [];
693 if 'tst-storage' in self.asTestVMs:
694 self.asRsrcs.append('5.0/storage/tst-storage.vdi');
695 if 'tst-storage32' in self.asTestVMs:
696 self.asRsrcs.append('5.0/storage/tst-storage32.vdi');
697
698 return self.asRsrcs;
699
700 def actionConfig(self):
701
702 # Make sure vboxapi has been imported so we can use the constants.
703 if not self.importVBoxApi():
704 return False;
705
706 #
707 # Configure the VMs we're going to use.
708 #
709
710 # Linux VMs
711 if 'tst-storage' in self.asTestVMs:
712 oVM = self.createTestVM('tst-storage', 1, '5.0/storage/tst-storage.vdi', sKind = 'ArchLinux_64', fIoApic = True, \
713 eNic0AttachType = vboxcon.NetworkAttachmentType_NAT, \
714 eNic0Type = vboxcon.NetworkAdapterType_Am79C973);
715 if oVM is None:
716 return False;
717
718 if 'tst-storage32' in self.asTestVMs:
719 oVM = self.createTestVM('tst-storage32', 1, '5.0/storage/tst-storage32.vdi', sKind = 'ArchLinux', fIoApic = True, \
720 eNic0AttachType = vboxcon.NetworkAttachmentType_NAT, \
721 eNic0Type = vboxcon.NetworkAdapterType_Am79C973);
722 if oVM is None:
723 return False;
724
725 return True;
726
727 def actionExecute(self):
728 """
729 Execute the testcase.
730 """
731 fRc = self.test1();
732 return fRc;
733
734
735 #
736 # Test execution helpers.
737 #
738
739 def prepareStorage(self, oStorCfg, fRamDisk = False, cbPool = None):
740 """
741 Prepares the host storage for disk images or direct testing on the host.
742 """
743 # Create a basic pool with the default configuration.
744 sMountPoint = None;
745 fRc, sPoolId = oStorCfg.createStoragePool(cbPool = cbPool, fRamDisk = fRamDisk);
746 if fRc:
747 fRc, sMountPoint = oStorCfg.createVolume(sPoolId);
748 if not fRc:
749 sMountPoint = None;
750 oStorCfg.cleanup();
751
752 return sMountPoint;
753
754 def cleanupStorage(self, oStorCfg):
755 """
756 Cleans up any created storage space for a test.
757 """
758 return oStorCfg.cleanup();
759
760 def getGuestDisk(self, oSession, oTxsSession, eStorageController):
761 """
762 Gets the path of the disk in the guest to use for testing.
763 """
764 lstDisks = None;
765
766 # The naming scheme for NVMe is different and we don't have
767 # to query the guest for unformatted disks here because the disk with the OS
768 # is not attached to a NVMe controller.
769 if eStorageController == vboxcon.StorageControllerType_NVMe:
770 lstDisks = [ '/dev/nvme0n1' ];
771 else:
772 # Find a unformatted disk (no partition).
773 # @todo: This is a hack because LIST and STAT are not yet implemented
774 # in TXS (get to this eventually)
775 lstBlkDev = [ '/dev/sda', '/dev/sdb' ];
776 for sBlkDev in lstBlkDev:
777 fRc = oTxsSession.syncExec('/usr/bin/ls', ('ls', sBlkDev + '1'));
778 if not fRc:
779 lstDisks = [ sBlkDev ];
780 break;
781
782 _ = oSession;
783 return lstDisks;
784
785 def getDiskFormatVariantsForTesting(self, sDiskFmt, asVariants):
786 """
787 Returns a list of disk variants for testing supported by the given
788 disk format and selected for testing.
789 """
790 lstDskFmts = self.oVBoxMgr.getArray(self.oVBox.systemProperties, 'mediumFormats');
791 for oDskFmt in lstDskFmts:
792 if oDskFmt.id == sDiskFmt:
793 lstDskVariants = [];
794 lstCaps = self.oVBoxMgr.getArray(oDskFmt, 'capabilities');
795
796 if vboxcon.MediumFormatCapabilities_CreateDynamic in lstCaps \
797 and 'Dynamic' in asVariants:
798 lstDskVariants.append('Dynamic');
799
800 if vboxcon.MediumFormatCapabilities_CreateFixed in lstCaps \
801 and 'Fixed' in asVariants:
802 lstDskVariants.append('Fixed');
803
804 if vboxcon.MediumFormatCapabilities_CreateSplit2G in lstCaps \
805 and vboxcon.MediumFormatCapabilities_CreateDynamic in lstCaps \
806 and 'DynamicSplit2G' in asVariants:
807 lstDskVariants.append('DynamicSplit2G');
808
809 if vboxcon.MediumFormatCapabilities_CreateSplit2G in lstCaps \
810 and vboxcon.MediumFormatCapabilities_CreateFixed in lstCaps \
811 and 'FixedSplit2G' in asVariants:
812 lstDskVariants.append('FixedSplit2G');
813
814 if vboxcon.MediumFormatCapabilities_TcpNetworking in lstCaps \
815 and 'Network' in asVariants:
816 lstDskVariants.append('Network'); # Solely for iSCSI to get a non empty list
817
818 return lstDskVariants;
819
820 return [];
821
822 def convDiskToMediumVariant(self, sDiskVariant):
823 """
824 Returns a tuple of medium variant flags matching the given disk variant.
825 """
826 tMediumVariant = None;
827 if sDiskVariant == 'Dynamic':
828 tMediumVariant = (vboxcon.MediumVariant_Standard, );
829 elif sDiskVariant == 'Fixed':
830 tMediumVariant = (vboxcon.MediumVariant_Fixed, );
831 elif sDiskVariant == 'DynamicSplit2G':
832 tMediumVariant = (vboxcon.MediumVariant_Standard, vboxcon.MediumVariant_VmdkSplit2G);
833 elif sDiskVariant == 'FixedSplit2G':
834 tMediumVariant = (vboxcon.MediumVariant_Fixed, vboxcon.MediumVariant_VmdkSplit2G);
835
836 return tMediumVariant;
837
838 def getStorageCtrlFromName(self, sStorageCtrl):
839 """
840 Resolves the storage controller string to the matching constant.
841 """
842 eStorageCtrl = None;
843
844 if sStorageCtrl == 'AHCI':
845 eStorageCtrl = vboxcon.StorageControllerType_IntelAhci;
846 elif sStorageCtrl == 'IDE':
847 eStorageCtrl = vboxcon.StorageControllerType_PIIX4;
848 elif sStorageCtrl == 'LsiLogicSAS':
849 eStorageCtrl = vboxcon.StorageControllerType_LsiLogicSas;
850 elif sStorageCtrl == 'LsiLogic':
851 eStorageCtrl = vboxcon.StorageControllerType_LsiLogic;
852 elif sStorageCtrl == 'BusLogic':
853 eStorageCtrl = vboxcon.StorageControllerType_BusLogic;
854 elif sStorageCtrl == 'NVMe':
855 eStorageCtrl = vboxcon.StorageControllerType_NVMe;
856
857 return eStorageCtrl;
858
859 def getStorageDriverFromEnum(self, eStorageCtrl, fHardDisk):
860 """
861 Returns the appropriate driver name for the given storage controller
862 and a flag whether the driver has the generic SCSI driver attached.
863 """
864 if eStorageCtrl == vboxcon.StorageControllerType_IntelAhci:
865 if fHardDisk:
866 return ('ahci', False);
867 return ('ahci', True);
868 if eStorageCtrl == vboxcon.StorageControllerType_PIIX4:
869 return ('piix3ide', False);
870 if eStorageCtrl == vboxcon.StorageControllerType_LsiLogicSas:
871 return ('lsilogicsas', True);
872 if eStorageCtrl == vboxcon.StorageControllerType_LsiLogic:
873 return ('lsilogicscsi', True);
874 if eStorageCtrl == vboxcon.StorageControllerType_BusLogic:
875 return ('buslogic', True);
876 if eStorageCtrl == vboxcon.StorageControllerType_NVMe:
877 return ('nvme', False);
878
879 return ('<invalid>', False);
880
881 def isTestCfgSupported(self, asTestCfg):
882 """
883 Returns whether a specific test config is supported.
884 """
885
886 # Check whether the disk variant is supported by the selected format.
887 asVariants = self.getDiskFormatVariantsForTesting(asTestCfg[self.kiDiskFmt], [ asTestCfg[self.kiDiskVar] ]);
888 if not asVariants:
889 return False;
890
891 # For iSCSI check whether we have targets configured.
892 if asTestCfg[self.kiDiskFmt] == 'iSCSI' and not self.asIscsiTargets:
893 return False;
894
895 # Check for virt mode, CPU count and selected VM.
896 if asTestCfg[self.kiVirtMode] == 'raw' \
897 and (asTestCfg[self.kiCpuCount] > 1 or asTestCfg[self.kiVmName] == 'tst-storage'):
898 return False;
899
900 # IDE does not support the no host I/O cache setting
901 if asTestCfg[self.kiHostIoCache] == 'no-hostiocache' \
902 and asTestCfg[self.kiStorageCtrl] == 'IDE':
903 return False;
904
905 return True;
906
907 def fnFormatCpuString(self, cCpus):
908 """
909 Formats the CPU count to be readable.
910 """
911 if cCpus == 1:
912 return '1 cpu';
913 return '%u cpus' % (cCpus);
914
915 def fnFormatVirtMode(self, sVirtMode):
916 """
917 Formats the virtualization mode to be a little less cryptic for use in test
918 descriptions.
919 """
920 return self.kdVirtModeDescs[sVirtMode];
921
922 def fnFormatHostIoCache(self, sHostIoCache):
923 """
924 Formats the host I/O cache mode to be a little less cryptic for use in test
925 descriptions.
926 """
927 return self.kdHostIoCacheDescs[sHostIoCache];
928
929 def testBenchmark(self, sTargetOs, sBenchmark, sMountpoint, oExecutor, dTestSet, \
930 cMsTimeout = 3600000):
931 """
932 Runs the given benchmark on the test host.
933 """
934
935 dTestSet['FilePath'] = sMountpoint;
936 dTestSet['TargetOs'] = sTargetOs;
937
938 oTst = None;
939 if sBenchmark == 'iozone':
940 oTst = IozoneTest(oExecutor, dTestSet);
941 elif sBenchmark == 'fio':
942 oTst = FioTest(oExecutor, dTestSet); # pylint: disable=R0204
943
944 if oTst is not None:
945 fRc = oTst.prepare();
946 if fRc:
947 fRc = oTst.run(cMsTimeout);
948 if fRc:
949 if self.fReportBenchmarkResults:
950 fRc = oTst.reportResult();
951 else:
952 reporter.testFailure('Running the testcase failed');
953 reporter.addLogString(oTst.getErrorReport(), sBenchmark + '.log',
954 'log/release/client', 'Benchmark raw output');
955 else:
956 reporter.testFailure('Preparing the testcase failed');
957
958 oTst.cleanup();
959
960 return fRc;
961
962 def createHd(self, oSession, sDiskFormat, sDiskVariant, iDiffLvl, oHdParent, \
963 sDiskPath, cbDisk):
964 """
965 Creates a new disk with the given parameters returning the medium object
966 on success.
967 """
968
969 oHd = None;
970 if sDiskFormat == "iSCSI" and iDiffLvl == 0:
971 listNames = [];
972 listValues = [];
973 listValues = self.asIscsiTargets[0].split('|');
974 listNames.append('TargetAddress');
975 listNames.append('TargetName');
976 listNames.append('LUN');
977
978 if self.fpApiVer >= 5.0:
979 oHd = oSession.oVBox.createMedium(sDiskFormat, sDiskPath, vboxcon.AccessMode_ReadWrite, \
980 vboxcon.DeviceType_HardDisk);
981 else:
982 oHd = oSession.oVBox.createHardDisk(sDiskFormat, sDiskPath);
983 oHd.type = vboxcon.MediumType_Normal;
984 oHd.setProperties(listNames, listValues);
985 else:
986 if iDiffLvl == 0:
987 tMediumVariant = self.convDiskToMediumVariant(sDiskVariant);
988 oHd = oSession.createBaseHd(sDiskPath + '/base.disk', sDiskFormat, cbDisk, \
989 cMsTimeout = 3600 * 1000, tMediumVariant = tMediumVariant);
990 else:
991 sDiskPath = sDiskPath + '/diff_%u.disk' % (iDiffLvl);
992 oHd = oSession.createDiffHd(oHdParent, sDiskPath, None);
993
994 if oHd is not None and iDiffLvl == 0 and self.fEncryptDisk:
995 try:
996 oIProgress = oHd.changeEncryption('', self.sEncryptAlgo, self.sEncryptPw, self.ksPwId);
997 oProgress = vboxwrappers.ProgressWrapper(oIProgress, self.oVBoxMgr, self, 'Encrypting "%s"' % (sDiskPath,));
998 oProgress.wait();
999 if oProgress.logResult() is False:
1000 raise base.GenError('Encrypting disk "%s" failed' % (sDiskPath, ));
1001 except:
1002 reporter.errorXcpt('changeEncryption("%s","%s","%s") failed on "%s"' \
1003 % ('', self.sEncryptAlgo, self.sEncryptPw, oSession.sName) );
1004 self.oVBox.deleteHdByMedium(oHd);
1005 oHd = None;
1006 else:
1007 reporter.log('Encrypted "%s"' % (sDiskPath,));
1008
1009 return oHd;
1010
1011 def startVmAndConnect(self, sVmName):
1012 """
1013 Our own implementation of startVmAndConnectToTxsViaTcp to make it possible
1014 to add passwords to a running VM when encryption is used.
1015 """
1016 oSession = self.startVmByName(sVmName);
1017 if oSession is not None:
1018 # Add password to the session in case encryption is used.
1019 fRc = True;
1020 if self.fEncryptDisk:
1021 try:
1022 oSession.o.console.addDiskEncryptionPassword(self.ksPwId, self.sEncryptPw, False);
1023 except:
1024 reporter.logXcpt();
1025 fRc = False;
1026
1027 # Connect to TXS.
1028 if fRc:
1029 reporter.log2('startVmAndConnect: Started(/prepared) "%s", connecting to TXS ...' % (sVmName,));
1030 (fRc, oTxsSession) = self.txsDoConnectViaTcp(oSession, 15*60000, fNatForwardingForTxs = True);
1031 if fRc is True:
1032 if fRc is True:
1033 # Success!
1034 return (oSession, oTxsSession);
1035 else:
1036 reporter.error('startVmAndConnect: txsDoConnectViaTcp failed');
1037 # If something went wrong while waiting for TXS to be started - take VM screenshot before terminate it
1038
1039 self.terminateVmBySession(oSession);
1040
1041 return (None, None);
1042
1043 def testOneCfg(self, sVmName, eStorageController, sHostIoCache, sDiskFormat, # pylint: disable=R0913,R0914,R0915
1044 sDiskVariant, sDiskPath, cCpus, sIoTest, sVirtMode, sTestSet):
1045 """
1046 Runs the specified VM thru test #1.
1047
1048 Returns a success indicator on the general test execution. This is not
1049 the actual test result.
1050 """
1051 oVM = self.getVmByName(sVmName);
1052
1053 dTestSet = self.kdTestSets.get(sTestSet);
1054 cbDisk = dTestSet.get('DiskSizeGb') * 1024*1024*1024;
1055 fHwVirt = sVirtMode != 'raw';
1056 fNestedPaging = sVirtMode == 'hwvirt-np';
1057
1058 fRc = True;
1059 if sDiskFormat == 'iSCSI':
1060 sDiskPath = self.asIscsiTargets[0];
1061 elif self.fUseScratch:
1062 sDiskPath = self.sScratchPath;
1063 else:
1064 # If requested recreate the storage space to start with a clean config
1065 # for benchmarks
1066 if self.fRecreateStorCfg:
1067 sMountPoint = self.prepareStorage(self.oStorCfg, self.fUseRamDisk, 2 * cbDisk);
1068 if sMountPoint is not None:
1069 # Create a directory where every normal user can write to.
1070 self.oStorCfg.mkDirOnVolume(sMountPoint, 'test', 0777);
1071 sDiskPath = sMountPoint + '/test';
1072 else:
1073 fRc = False;
1074 reporter.testFailure('Failed to prepare storage for VM');
1075
1076 if not fRc:
1077 return fRc;
1078
1079 lstDisks = []; # List of disks we have to delete afterwards.
1080
1081 for iDiffLvl in range(self.cDiffLvls + 1):
1082 sIoLogFile = None;
1083
1084 if iDiffLvl == 0:
1085 reporter.testStart('Base');
1086 else:
1087 reporter.testStart('Diff %u' % (iDiffLvl));
1088
1089 # Reconfigure the VM
1090 oSession = self.openSession(oVM);
1091 if oSession is not None:
1092 # Attach HD
1093 fRc = oSession.ensureControllerAttached(_ControllerTypeToName(eStorageController));
1094 fRc = fRc and oSession.setStorageControllerType(eStorageController, _ControllerTypeToName(eStorageController));
1095
1096 if sHostIoCache == 'hostiocache':
1097 fRc = fRc and oSession.setStorageControllerHostIoCache(_ControllerTypeToName(eStorageController), True);
1098 elif sHostIoCache == 'no-hostiocache':
1099 fRc = fRc and oSession.setStorageControllerHostIoCache(_ControllerTypeToName(eStorageController), False);
1100
1101 iDevice = 0;
1102 if eStorageController == vboxcon.StorageControllerType_PIIX3 or \
1103 eStorageController == vboxcon.StorageControllerType_PIIX4:
1104 iDevice = 1; # Master is for the OS.
1105
1106 oHdParent = None;
1107 if iDiffLvl > 0:
1108 oHdParent = lstDisks[0];
1109 oHd = self.createHd(oSession, sDiskFormat, sDiskVariant, iDiffLvl, oHdParent, sDiskPath, cbDisk);
1110 if oHd is not None:
1111 lstDisks.insert(0, oHd);
1112 try:
1113 if oSession.fpApiVer >= 4.0:
1114 oSession.o.machine.attachDevice(_ControllerTypeToName(eStorageController), \
1115 0, iDevice, vboxcon.DeviceType_HardDisk, oHd);
1116 else:
1117 oSession.o.machine.attachDevice(_ControllerTypeToName(eStorageController), \
1118 0, iDevice, vboxcon.DeviceType_HardDisk, oHd.id);
1119 except:
1120 reporter.errorXcpt('attachDevice("%s",%s,%s,HardDisk,"%s") failed on "%s"' \
1121 % (_ControllerTypeToName(eStorageController), 1, 0, oHd.id, oSession.sName) );
1122 fRc = False;
1123 else:
1124 reporter.log('attached "%s" to %s' % (sDiskPath, oSession.sName));
1125 else:
1126 fRc = False;
1127
1128 # Set up the I/O logging config if enabled
1129 if fRc and self.fIoLog:
1130 try:
1131 oSession.o.machine.setExtraData('VBoxInternal2/EnableDiskIntegrityDriver', '1');
1132
1133 iLun = 0;
1134 if eStorageController == vboxcon.StorageControllerType_PIIX3 or \
1135 eStorageController == vboxcon.StorageControllerType_PIIX4:
1136 iLun = 1
1137 sDrv, fDrvScsi = self.getStorageDriverFromEnum(eStorageController, True);
1138 if fDrvScsi:
1139 sCfgmPath = 'VBoxInternal/Devices/%s/0/LUN#%u/AttachedDriver/Config' % (sDrv, iLun);
1140 else:
1141 sCfgmPath = 'VBoxInternal/Devices/%s/0/LUN#%u/Config' % (sDrv, iLun);
1142
1143 sIoLogFile = '%s/%s.iolog' % (self.sIoLogPath, sDrv);
1144 print sCfgmPath;
1145 print sIoLogFile;
1146 oSession.o.machine.setExtraData('%s/IoLog' % (sCfgmPath,), sIoLogFile);
1147 except:
1148 reporter.logXcpt();
1149
1150 fRc = fRc and oSession.enableVirtEx(fHwVirt);
1151 fRc = fRc and oSession.enableNestedPaging(fNestedPaging);
1152 fRc = fRc and oSession.setCpuCount(cCpus);
1153 fRc = fRc and oSession.saveSettings();
1154 fRc = oSession.close() and fRc and True; # pychecker hack.
1155 oSession = None;
1156 else:
1157 fRc = False;
1158
1159 # Start up.
1160 if fRc is True:
1161 self.logVmInfo(oVM);
1162 oSession, oTxsSession = self.startVmAndConnect(sVmName);
1163 if oSession is not None:
1164 self.addTask(oTxsSession);
1165
1166 # Fudge factor - Allow the guest to finish starting up.
1167 self.sleep(5);
1168
1169 # Prepare the storage on the guest
1170 lstBinaryPaths = ['/bin', '/sbin', '/usr/bin', '/usr/sbin' ];
1171 oExecVm = remoteexecutor.RemoteExecutor(oTxsSession, lstBinaryPaths, '${SCRATCH}');
1172 oStorCfgVm = storagecfg.StorageCfg(oExecVm, 'linux', self.getGuestDisk(oSession, oTxsSession, \
1173 eStorageController));
1174
1175 sMountPoint = self.prepareStorage(oStorCfgVm);
1176 if sMountPoint is not None:
1177 self.testBenchmark('linux', sIoTest, sMountPoint, oExecVm, dTestSet, \
1178 cMsTimeout = 3 * 3600 * 1000); # 3 hours max (Benchmark and QED takes a lot of time)
1179 self.cleanupStorage(oStorCfgVm);
1180 else:
1181 reporter.testFailure('Failed to prepare storage for the guest benchmark');
1182
1183 # cleanup.
1184 self.removeTask(oTxsSession);
1185 self.terminateVmBySession(oSession);
1186
1187 # Add the I/O log if it exists and the test failed
1188 if reporter.testErrorCount() > 0 \
1189 and sIoLogFile is not None \
1190 and os.path.exists(sIoLogFile):
1191 reporter.addLogFile(sIoLogFile, 'misc/other', 'I/O log');
1192 os.remove(sIoLogFile);
1193
1194 else:
1195 fRc = False;
1196
1197 # Remove disk
1198 oSession = self.openSession(oVM);
1199 if oSession is not None:
1200 try:
1201 oSession.o.machine.detachDevice(_ControllerTypeToName(eStorageController), 0, iDevice);
1202
1203 # Remove storage controller if it is not an IDE controller.
1204 if eStorageController is not vboxcon.StorageControllerType_PIIX3 \
1205 and eStorageController is not vboxcon.StorageControllerType_PIIX4:
1206 oSession.o.machine.removeStorageController(_ControllerTypeToName(eStorageController));
1207
1208 oSession.saveSettings();
1209 oSession.saveSettings();
1210 oSession.close();
1211 oSession = None;
1212 except:
1213 reporter.errorXcpt('failed to detach/delete disk %s from storage controller' % (sDiskPath));
1214 else:
1215 fRc = False;
1216
1217 reporter.testDone();
1218
1219 # Delete all disks
1220 for oHd in lstDisks:
1221 self.oVBox.deleteHdByMedium(oHd);
1222
1223 # Cleanup storage area
1224 if sDiskFormat != 'iSCSI' and not self.fUseScratch and self.fRecreateStorCfg:
1225 self.cleanupStorage(self.oStorCfg);
1226
1227 return fRc;
1228
1229 def testStorage(self, sDiskPath = None):
1230 """
1231 Runs the storage testcase through the selected configurations
1232 """
1233
1234 aasTestCfgs = [];
1235 aasTestCfgs.insert(self.kiVmName, self.asTestVMs);
1236 aasTestCfgs.insert(self.kiStorageCtrl, self.asStorageCtrls);
1237 aasTestCfgs.insert(self.kiHostIoCache, (self.asHostIoCache, self.fnFormatHostIoCache));
1238 aasTestCfgs.insert(self.kiDiskFmt, self.asDiskFormats);
1239 aasTestCfgs.insert(self.kiDiskVar, self.asDiskVariants);
1240 aasTestCfgs.insert(self.kiCpuCount, (self.acCpus, self.fnFormatCpuString));
1241 aasTestCfgs.insert(self.kiVirtMode, (self.asVirtModes, self.fnFormatVirtMode));
1242 aasTestCfgs.insert(self.kiIoTest, self.asTests);
1243 aasTestCfgs.insert(self.kiTestSet, self.asTestSets);
1244
1245 aasTestsBlacklist = [];
1246 aasTestsBlacklist.append(['tst-storage', 'BusLogic']); # 64bit Linux is broken with BusLogic
1247
1248 oTstCfgMgr = StorTestCfgMgr(aasTestCfgs, aasTestsBlacklist, self.isTestCfgSupported);
1249
1250 fRc = True;
1251 asTestCfg = oTstCfgMgr.getCurrentTestCfg();
1252 while asTestCfg:
1253 fRc = self.testOneCfg(asTestCfg[self.kiVmName], self.getStorageCtrlFromName(asTestCfg[self.kiStorageCtrl]), \
1254 asTestCfg[self.kiHostIoCache], asTestCfg[self.kiDiskFmt], asTestCfg[self.kiDiskVar],
1255 sDiskPath, asTestCfg[self.kiCpuCount], asTestCfg[self.kiIoTest], \
1256 asTestCfg[self.kiVirtMode], asTestCfg[self.kiTestSet]) and fRc and True; # pychecker hack.
1257
1258 asTestCfg = oTstCfgMgr.getNextTestCfg();
1259
1260 return fRc;
1261
1262 def test1(self):
1263 """
1264 Executes test #1.
1265 """
1266
1267 fRc = True;
1268 oDiskCfg = self.kdStorageCfgs.get(socket.gethostname().lower());
1269
1270 # Test the host first if requested
1271 if oDiskCfg is not None or self.fUseScratch:
1272 lstBinaryPaths = ['/bin', '/sbin', '/usr/bin', '/usr/sbin', \
1273 '/opt/csw/bin', '/usr/ccs/bin', '/usr/sfw/bin'];
1274 oExecutor = remoteexecutor.RemoteExecutor(None, lstBinaryPaths, self.sScratchPath);
1275 if not self.fUseScratch:
1276 self.oStorCfg = storagecfg.StorageCfg(oExecutor, utils.getHostOs(), oDiskCfg);
1277
1278 # Try to cleanup any leftovers from a previous run first.
1279 fRc = self.oStorCfg.cleanupLeftovers();
1280 if not fRc:
1281 reporter.error('Failed to cleanup any leftovers from a previous run');
1282
1283 if self.fTestHost:
1284 reporter.testStart('Host');
1285 if self.fUseScratch:
1286 sMountPoint = self.sScratchPath;
1287 else:
1288 sMountPoint = self.prepareStorage(self.oStorCfg);
1289 if sMountPoint is not None:
1290 for sIoTest in self.asTests:
1291 reporter.testStart(sIoTest);
1292 for sTestSet in self.asTestSets:
1293 reporter.testStart(sTestSet);
1294 dTestSet = self.kdTestSets.get(sTestSet);
1295 self.testBenchmark(utils.getHostOs(), sIoTest, sMountPoint, oExecutor, dTestSet);
1296 reporter.testDone();
1297 reporter.testDone();
1298 self.cleanupStorage(self.oStorCfg);
1299 else:
1300 reporter.testFailure('Failed to prepare host storage');
1301 fRc = False;
1302 reporter.testDone();
1303 else:
1304 # Create the storage space first if it is not done before every test.
1305 sMountPoint = None;
1306 if self.fUseScratch:
1307 sMountPoint = self.sScratchPath;
1308 elif not self.fRecreateStorCfg:
1309 reporter.testStart('Create host storage');
1310 sMountPoint = self.prepareStorage(self.oStorCfg);
1311 if sMountPoint is None:
1312 reporter.testFailure('Failed to prepare host storage');
1313 fRc = False;
1314 self.oStorCfg.mkDirOnVolume(sMountPoint, 'test', 0777);
1315 sMountPoint = sMountPoint + '/test';
1316 reporter.testDone();
1317
1318 if fRc:
1319 # Run the storage tests.
1320 if not self.testStorage(sMountPoint):
1321 fRc = False;
1322
1323 if not self.fRecreateStorCfg and not self.fUseScratch:
1324 self.cleanupStorage(self.oStorCfg);
1325 else:
1326 fRc = False;
1327
1328 return fRc;
1329
1330if __name__ == '__main__':
1331 sys.exit(tdStorageBenchmark().main(sys.argv));
1332
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