VirtualBox

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

Last change on this file since 80245 was 80245, checked in by vboxsync, 5 years ago

ValidationKit/tdStoragebenchmark1: Fixes for the newly integrated IoPerf test which trips the test manager because the sub test nesting gets too deep [pylint fix]

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