VirtualBox

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

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

doc/manual,Main,Frontends: API changes in preparation for full VM encryption, guarded by VBOX_WITH_FULL_VM_ENCRYPTION (disabled by default) and returning a not supported error for now, bugref:9955 [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.4 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# $Id: tdStorageBenchmark1.py 94662 2022-04-21 08:52:41Z vboxsync $
4
5"""
6VirtualBox Validation Kit - Storage benchmark.
7"""
8
9__copyright__ = \
10"""
11Copyright (C) 2012-2022 Oracle Corporation
12
13This file is part of VirtualBox Open Source Edition (OSE), as
14available from http://www.virtualbox.org. This file is free software;
15you can redistribute it and/or modify it under the terms of the GNU
16General Public License (GPL) as published by the Free Software
17Foundation, in version 2 as it comes in the "COPYING" file of the
18VirtualBox OSE distribution. VirtualBox OSE is distributed in the
19hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
20
21The contents of this file may alternatively be used under the terms
22of the Common Development and Distribution License Version 1.0
23(CDDL) only, as it comes in the "COPYING.CDDL" file of the
24VirtualBox OSE distribution, in which case the provisions of the
25CDDL are applicable instead of those of the GPL.
26
27You may elect to license modified versions of this file under the
28terms and conditions of either the GPL or the CDDL or both.
29"""
30__version__ = "$Revision: 94662 $"
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', 'VirtIoScsi'];
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 = ['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 elif sStorageCtrl == 'VirtIoScsi':
954 eStorageCtrl = vboxcon.StorageControllerType_VirtioSCSI;
955
956 return eStorageCtrl;
957
958 def getStorageDriverFromEnum(self, eStorageCtrl, fHardDisk):
959 """
960 Returns the appropriate driver name for the given storage controller
961 and a flag whether the driver has the generic SCSI driver attached.
962 """
963 if eStorageCtrl == vboxcon.StorageControllerType_IntelAhci:
964 if fHardDisk:
965 return ('ahci', False);
966 return ('ahci', True);
967 if eStorageCtrl == vboxcon.StorageControllerType_PIIX4:
968 return ('piix3ide', False);
969 if eStorageCtrl == vboxcon.StorageControllerType_LsiLogicSas:
970 return ('lsilogicsas', True);
971 if eStorageCtrl == vboxcon.StorageControllerType_LsiLogic:
972 return ('lsilogicscsi', True);
973 if eStorageCtrl == vboxcon.StorageControllerType_BusLogic:
974 return ('buslogic', True);
975 if eStorageCtrl == vboxcon.StorageControllerType_NVMe:
976 return ('nvme', False);
977 if eStorageCtrl == vboxcon.StorageControllerType_VirtioSCSI:
978 return ('virtio-scsi', True);
979
980 return ('<invalid>', False);
981
982 def isTestCfgSupported(self, asTestCfg):
983 """
984 Returns whether a specific test config is supported.
985 """
986
987 # Check whether the disk variant is supported by the selected format.
988 asVariants = self.getDiskFormatVariantsForTesting(asTestCfg[self.kiDiskFmt], [ asTestCfg[self.kiDiskVar] ]);
989 if not asVariants:
990 return False;
991
992 # For iSCSI check whether we have targets configured.
993 if asTestCfg[self.kiDiskFmt] == 'iSCSI' and not self.asIscsiTargets:
994 return False;
995
996 # Check for virt mode, CPU count and selected VM.
997 if asTestCfg[self.kiVirtMode] == 'raw' \
998 and ( asTestCfg[self.kiCpuCount] > 1 \
999 or asTestCfg[self.kiVmName] == 'tst-storage' \
1000 or not self.fTestRawMode):
1001 return False;
1002
1003 # IDE does not support the no host I/O cache setting
1004 if asTestCfg[self.kiHostIoCache] == 'no-hostiocache' \
1005 and asTestCfg[self.kiStorageCtrl] == 'IDE':
1006 return False;
1007
1008 return True;
1009
1010 def fnFormatCpuString(self, cCpus):
1011 """
1012 Formats the CPU count to be readable.
1013 """
1014 if cCpus == 1:
1015 return '1 cpu';
1016 return '%u cpus' % (cCpus);
1017
1018 def fnFormatVirtMode(self, sVirtMode):
1019 """
1020 Formats the virtualization mode to be a little less cryptic for use in test
1021 descriptions.
1022 """
1023 return self.kdVirtModeDescs[sVirtMode];
1024
1025 def fnFormatHostIoCache(self, sHostIoCache):
1026 """
1027 Formats the host I/O cache mode to be a little less cryptic for use in test
1028 descriptions.
1029 """
1030 return self.kdHostIoCacheDescs[sHostIoCache];
1031
1032 def testBenchmark(self, sTargetOs, sBenchmark, sMountpoint, oExecutor, dTestSet, \
1033 cMsTimeout = 3600000):
1034 """
1035 Runs the given benchmark on the test host.
1036 """
1037
1038 dTestSet['FilePath'] = sMountpoint;
1039 dTestSet['TargetOs'] = sTargetOs;
1040
1041 oTst = None;
1042 if sBenchmark == 'iozone':
1043 oTst = IozoneTest(oExecutor, dTestSet);
1044 elif sBenchmark == 'fio':
1045 oTst = FioTest(oExecutor, dTestSet); # pylint: disable=redefined-variable-type
1046 elif sBenchmark == 'ioperf':
1047 oTst = IoPerfTest(oExecutor, dTestSet); # pylint: disable=redefined-variable-type
1048
1049 if oTst is not None:
1050 fRc = oTst.prepare();
1051 if fRc:
1052 fRc = oTst.run(cMsTimeout);
1053 if fRc:
1054 if self.fReportBenchmarkResults:
1055 fRc = oTst.reportResult();
1056 else:
1057 reporter.testFailure('Running the testcase failed');
1058 reporter.addLogString(oTst.getErrorReport(), sBenchmark + '.log',
1059 'log/release/client', 'Benchmark raw output');
1060 else:
1061 reporter.testFailure('Preparing the testcase failed');
1062
1063 oTst.cleanup();
1064
1065 return fRc;
1066
1067 def createHd(self, oSession, sDiskFormat, sDiskVariant, iDiffLvl, oHdParent, \
1068 sDiskPath, cbDisk):
1069 """
1070 Creates a new disk with the given parameters returning the medium object
1071 on success.
1072 """
1073
1074 oHd = None;
1075 if sDiskFormat == "iSCSI" and iDiffLvl == 0:
1076 listNames = [];
1077 listValues = [];
1078 listValues = self.asIscsiTargets[0].split('|');
1079 listNames.append('TargetAddress');
1080 listNames.append('TargetName');
1081 listNames.append('LUN');
1082
1083 if self.fpApiVer >= 5.0:
1084 oHd = oSession.oVBox.createMedium(sDiskFormat, sDiskPath, vboxcon.AccessMode_ReadWrite, \
1085 vboxcon.DeviceType_HardDisk);
1086 else:
1087 oHd = oSession.oVBox.createHardDisk(sDiskFormat, sDiskPath);
1088 oHd.type = vboxcon.MediumType_Normal;
1089 oHd.setProperties(listNames, listValues);
1090 else:
1091 if iDiffLvl == 0:
1092 tMediumVariant = self.convDiskToMediumVariant(sDiskVariant);
1093 oHd = oSession.createBaseHd(sDiskPath + '/base.img', sDiskFormat, cbDisk, \
1094 cMsTimeout = 3600 * 1000, tMediumVariant = tMediumVariant);
1095 else:
1096 sDiskPath = sDiskPath + '/diff_%u.img' % (iDiffLvl);
1097 oHd = oSession.createDiffHd(oHdParent, sDiskPath, None);
1098
1099 if oHd is not None and iDiffLvl == 0 and self.fEncryptDisk:
1100 try:
1101 oIProgress = oHd.changeEncryption('', self.sEncryptAlgo, self.sEncryptPw, self.ksPwId);
1102 oProgress = vboxwrappers.ProgressWrapper(oIProgress, self.oVBoxMgr, self, 'Encrypting "%s"' % (sDiskPath,));
1103 oProgress.wait(60*60000); # Wait for up to one hour, fixed disks take longer to encrypt.
1104 if oProgress.logResult() is False:
1105 raise base.GenError('Encrypting disk "%s" failed' % (sDiskPath, ));
1106 except:
1107 reporter.errorXcpt('changeEncryption("%s","%s","%s") failed on "%s"' \
1108 % ('', self.sEncryptAlgo, self.sEncryptPw, oSession.sName) );
1109 self.oVBox.deleteHdByMedium(oHd);
1110 oHd = None;
1111 else:
1112 reporter.log('Encrypted "%s"' % (sDiskPath,));
1113
1114 return oHd;
1115
1116 def startVmAndConnect(self, sVmName):
1117 """
1118 Our own implementation of startVmAndConnectToTxsViaTcp to make it possible
1119 to add passwords to a running VM when encryption is used.
1120 """
1121 oSession = self.startVmByName(sVmName);
1122 if oSession is not None:
1123 # Add password to the session in case encryption is used.
1124 fRc = True;
1125 if self.fEncryptDisk:
1126 try:
1127 if self.fpApiVer >= 7.0:
1128 oSession.o.console.addEncryptionPassword(self.ksPwId, self.sEncryptPw, False);
1129 else:
1130 oSession.o.console.addDiskEncryptionPassword(self.ksPwId, self.sEncryptPw, False);
1131 except:
1132 reporter.logXcpt();
1133 fRc = False;
1134
1135 # Connect to TXS.
1136 if fRc:
1137 reporter.log2('startVmAndConnect: Started(/prepared) "%s", connecting to TXS ...' % (sVmName,));
1138 (fRc, oTxsSession) = self.txsDoConnectViaTcp(oSession, 15*60000, fNatForwardingForTxs = True);
1139 if fRc is True:
1140 if fRc is True:
1141 # Success!
1142 return (oSession, oTxsSession);
1143 else:
1144 reporter.error('startVmAndConnect: txsDoConnectViaTcp failed');
1145 # If something went wrong while waiting for TXS to be started - take VM screenshot before terminate it
1146
1147 self.terminateVmBySession(oSession);
1148
1149 return (None, None);
1150
1151 def testOneCfg(self, sVmName, eStorageController, sHostIoCache, sDiskFormat, # pylint: disable=too-many-arguments,too-many-locals,too-many-statements
1152 sDiskVariant, sDiskPath, cCpus, sIoTest, sVirtMode, sTestSet):
1153 """
1154 Runs the specified VM thru test #1.
1155
1156 Returns a success indicator on the general test execution. This is not
1157 the actual test result.
1158 """
1159 oVM = self.getVmByName(sVmName);
1160
1161 dTestSet = self.kdTestSets.get(sTestSet);
1162 cbDisk = dTestSet.get('DiskSizeGb') * 1024*1024*1024;
1163 fHwVirt = sVirtMode != 'raw';
1164 fNestedPaging = sVirtMode == 'hwvirt-np';
1165
1166 fRc = True;
1167 if sDiskFormat == 'iSCSI':
1168 sDiskPath = self.asIscsiTargets[0];
1169 elif self.fUseScratch:
1170 sDiskPath = self.sScratchPath;
1171 else:
1172 # If requested recreate the storage space to start with a clean config
1173 # for benchmarks
1174 if self.fRecreateStorCfg:
1175 sMountPoint = self.prepareStorage(self.oStorCfg, self.fUseRamDisk, 2 * cbDisk);
1176 if sMountPoint is not None:
1177 # Create a directory where every normal user can write to.
1178 self.oStorCfg.mkDirOnVolume(sMountPoint, 'test', 0o777);
1179 sDiskPath = sMountPoint + '/test';
1180 else:
1181 fRc = False;
1182 reporter.testFailure('Failed to prepare storage for VM');
1183
1184 if not fRc:
1185 return fRc;
1186
1187 lstDisks = []; # List of disks we have to delete afterwards.
1188
1189 for iDiffLvl in range(self.cDiffLvls + 1):
1190 sIoLogFile = None;
1191
1192 if iDiffLvl == 0:
1193 reporter.testStart('Base');
1194 else:
1195 reporter.testStart('Diff %u' % (iDiffLvl));
1196
1197 # Reconfigure the VM
1198 oSession = self.openSession(oVM);
1199 if oSession is not None:
1200 #
1201 # Disable audio controller which shares the interrupt line with the BusLogic controller and is suspected to cause
1202 # rare test failures because the device initialization fails.
1203 #
1204 fRc = oSession.setupAudio(vboxcon.AudioControllerType_AC97, False);
1205 # Attach HD
1206 fRc = fRc and oSession.ensureControllerAttached(self.controllerTypeToName(eStorageController));
1207 fRc = fRc and oSession.setStorageControllerType(eStorageController,
1208 self.controllerTypeToName(eStorageController));
1209
1210 if sHostIoCache == 'hostiocache':
1211 fRc = fRc and oSession.setStorageControllerHostIoCache(self.controllerTypeToName(eStorageController), True);
1212 elif sHostIoCache == 'no-hostiocache':
1213 fRc = fRc and oSession.setStorageControllerHostIoCache(self.controllerTypeToName(eStorageController), False);
1214
1215 iDevice = 0;
1216 if eStorageController in (vboxcon.StorageControllerType_PIIX3, vboxcon.StorageControllerType_PIIX4,):
1217 iDevice = 1; # Master is for the OS.
1218
1219 oHdParent = None;
1220 if iDiffLvl > 0:
1221 oHdParent = lstDisks[0];
1222 oHd = self.createHd(oSession, sDiskFormat, sDiskVariant, iDiffLvl, oHdParent, sDiskPath, cbDisk);
1223 if oHd is not None:
1224 lstDisks.insert(0, oHd);
1225 try:
1226 if oSession.fpApiVer >= 4.0:
1227 oSession.o.machine.attachDevice(self.controllerTypeToName(eStorageController),
1228 0, iDevice, vboxcon.DeviceType_HardDisk, oHd);
1229 else:
1230 oSession.o.machine.attachDevice(self.controllerTypeToName(eStorageController),
1231 0, iDevice, vboxcon.DeviceType_HardDisk, oHd.id);
1232 except:
1233 reporter.errorXcpt('attachDevice("%s",%s,%s,HardDisk,"%s") failed on "%s"' \
1234 % (self.controllerTypeToName(eStorageController), 1, 0, oHd.id, oSession.sName) );
1235 fRc = False;
1236 else:
1237 reporter.log('attached "%s" to %s' % (sDiskPath, oSession.sName));
1238 else:
1239 fRc = False;
1240
1241 # Set up the I/O logging config if enabled
1242 if fRc and self.fIoLog:
1243 try:
1244 oSession.o.machine.setExtraData('VBoxInternal2/EnableDiskIntegrityDriver', '1');
1245
1246 iLun = 0;
1247 if eStorageController in (vboxcon.StorageControllerType_PIIX3, vboxcon.StorageControllerType_PIIX4,):
1248 iLun = 1
1249 sDrv, fDrvScsi = self.getStorageDriverFromEnum(eStorageController, True);
1250 if fDrvScsi:
1251 sCfgmPath = 'VBoxInternal/Devices/%s/0/LUN#%u/AttachedDriver/Config' % (sDrv, iLun);
1252 else:
1253 sCfgmPath = 'VBoxInternal/Devices/%s/0/LUN#%u/Config' % (sDrv, iLun);
1254
1255 sIoLogFile = '%s/%s.iolog' % (self.sIoLogPath, sDrv);
1256 print(sCfgmPath);
1257 print(sIoLogFile);
1258 oSession.o.machine.setExtraData('%s/IoLog' % (sCfgmPath,), sIoLogFile);
1259 except:
1260 reporter.logXcpt();
1261
1262 fRc = fRc and oSession.enableVirtEx(fHwVirt);
1263 fRc = fRc and oSession.enableNestedPaging(fNestedPaging);
1264 fRc = fRc and oSession.setCpuCount(cCpus);
1265 fRc = fRc and oSession.saveSettings();
1266 fRc = oSession.close() and fRc and True; # pychecker hack.
1267 oSession = None;
1268 else:
1269 fRc = False;
1270
1271 # Start up.
1272 if fRc is True:
1273 self.logVmInfo(oVM);
1274 oSession, oTxsSession = self.startVmAndConnect(sVmName);
1275 if oSession is not None:
1276 self.addTask(oTxsSession);
1277
1278 # Fudge factor - Allow the guest to finish starting up.
1279 self.sleep(5);
1280
1281 # Prepare the storage on the guest
1282 lstBinaryPaths = ['/bin', '/sbin', '/usr/bin', '/usr/sbin' ];
1283 oExecVm = remoteexecutor.RemoteExecutor(oTxsSession, lstBinaryPaths, '${SCRATCH}');
1284 fRc = self.mountValidationKitIso(oExecVm);
1285 if fRc:
1286 oGstDiskCfg = storagecfg.DiskCfg('linux', storagecfg.g_ksDiskCfgList,
1287 self.getGuestDisk(oSession, oTxsSession, eStorageController));
1288 oStorCfgVm = storagecfg.StorageCfg(oExecVm, oGstDiskCfg);
1289
1290 iTry = 0;
1291 while iTry < 3:
1292 sMountPoint = self.prepareStorage(oStorCfgVm);
1293 if sMountPoint is not None:
1294 reporter.log('Prepared storage on %s try' % (iTry + 1,));
1295 break;
1296 iTry = iTry + 1;
1297 self.sleep(5);
1298
1299 if sMountPoint is not None:
1300 # 3 hours max (Benchmark and QED takes a lot of time)
1301 self.testBenchmark('linux', sIoTest, sMountPoint, oExecVm, dTestSet, cMsTimeout = 3 * 3600 * 1000);
1302 self.cleanupStorage(oStorCfgVm);
1303 else:
1304 reporter.testFailure('Failed to prepare storage for the guest benchmark');
1305
1306 # cleanup.
1307 self.removeTask(oTxsSession);
1308 self.terminateVmBySession(oSession);
1309
1310 # Add the I/O log if it exists and the test failed
1311 if reporter.testErrorCount() > 0 \
1312 and sIoLogFile is not None \
1313 and os.path.exists(sIoLogFile):
1314 reporter.addLogFile(sIoLogFile, 'misc/other', 'I/O log');
1315 os.remove(sIoLogFile);
1316 else:
1317 reporter.testFailure('Failed to mount validation kit ISO');
1318
1319 else:
1320 fRc = False;
1321
1322 # Remove disk
1323 oSession = self.openSession(oVM);
1324 if oSession is not None:
1325 try:
1326 oSession.o.machine.detachDevice(self.controllerTypeToName(eStorageController), 0, iDevice);
1327
1328 # Remove storage controller if it is not an IDE controller.
1329 if eStorageController not in (vboxcon.StorageControllerType_PIIX3, vboxcon.StorageControllerType_PIIX4,):
1330 oSession.o.machine.removeStorageController(self.controllerTypeToName(eStorageController));
1331
1332 oSession.saveSettings();
1333 oSession.saveSettings();
1334 oSession.close();
1335 oSession = None;
1336 except:
1337 reporter.errorXcpt('failed to detach/delete disk %s from storage controller' % (sDiskPath));
1338 else:
1339 fRc = False;
1340
1341 reporter.testDone();
1342
1343 # Delete all disks
1344 for oHd in lstDisks:
1345 self.oVBox.deleteHdByMedium(oHd);
1346
1347 # Cleanup storage area
1348 if sDiskFormat != 'iSCSI' and not self.fUseScratch and self.fRecreateStorCfg:
1349 self.cleanupStorage(self.oStorCfg);
1350
1351 return fRc;
1352
1353 def testStorage(self, sDiskPath = None):
1354 """
1355 Runs the storage testcase through the selected configurations
1356 """
1357
1358 aasTestCfgs = [];
1359 aasTestCfgs.insert(self.kiVmName, self.asTestVMs);
1360 aasTestCfgs.insert(self.kiStorageCtrl, self.asStorageCtrls);
1361 aasTestCfgs.insert(self.kiHostIoCache, (self.asHostIoCache, True, self.fnFormatHostIoCache));
1362 aasTestCfgs.insert(self.kiDiskFmt, self.asDiskFormats);
1363 aasTestCfgs.insert(self.kiDiskVar, self.asDiskVariants);
1364 aasTestCfgs.insert(self.kiCpuCount, (self.acCpus, True, self.fnFormatCpuString));
1365 aasTestCfgs.insert(self.kiVirtMode, (self.asVirtModes, True, self.fnFormatVirtMode));
1366 aasTestCfgs.insert(self.kiTestSet, self.asTestSets);
1367 aasTestCfgs.insert(self.kiIoTest, (self.asTests, False, None));
1368
1369 aasTestsBlacklist = [];
1370 aasTestsBlacklist.append(['tst-storage', 'BusLogic']); # 64bit Linux is broken with BusLogic
1371
1372 oTstCfgMgr = StorTestCfgMgr(aasTestCfgs, aasTestsBlacklist, self.isTestCfgSupported);
1373
1374 fRc = True;
1375 asTestCfg = oTstCfgMgr.getCurrentTestCfg();
1376 while asTestCfg:
1377 fRc = self.testOneCfg(asTestCfg[self.kiVmName], self.getStorageCtrlFromName(asTestCfg[self.kiStorageCtrl]), \
1378 asTestCfg[self.kiHostIoCache], asTestCfg[self.kiDiskFmt], asTestCfg[self.kiDiskVar],
1379 sDiskPath, asTestCfg[self.kiCpuCount], asTestCfg[self.kiIoTest], \
1380 asTestCfg[self.kiVirtMode], asTestCfg[self.kiTestSet]) and fRc and True; # pychecker hack.
1381
1382 asTestCfg = oTstCfgMgr.getNextTestCfg();
1383
1384 return fRc;
1385
1386 def test1(self):
1387 """
1388 Executes test #1.
1389 """
1390
1391 fRc = True;
1392 tupTstCfg = self.kdStorageCfgs.get(socket.getfqdn().lower());
1393 if tupTstCfg is None:
1394 tupTstCfg = self.kdStorageCfgs.get(socket.gethostname().lower());
1395
1396 # Test the host first if requested
1397 if tupTstCfg is not None or self.fUseScratch:
1398 self.fTestRawMode = tupTstCfg[0];
1399 oDiskCfg = tupTstCfg[1];
1400 lstBinaryPaths = ['/bin', '/sbin', '/usr/bin', '/usr/sbin', \
1401 '/opt/csw/bin', '/usr/ccs/bin', '/usr/sfw/bin'];
1402 oExecutor = remoteexecutor.RemoteExecutor(None, lstBinaryPaths, self.sScratchPath);
1403 if not self.fUseScratch:
1404 self.oStorCfg = storagecfg.StorageCfg(oExecutor, oDiskCfg);
1405
1406 # Try to cleanup any leftovers from a previous run first.
1407 fRc = self.oStorCfg.cleanupLeftovers();
1408 if not fRc:
1409 reporter.error('Failed to cleanup any leftovers from a previous run');
1410
1411 if self.fTestHost:
1412 reporter.testStart('Host');
1413 if self.fUseScratch:
1414 sMountPoint = self.sScratchPath;
1415 else:
1416 sMountPoint = self.prepareStorage(self.oStorCfg);
1417 if sMountPoint is not None:
1418 for sIoTest in self.asTests:
1419 for sTestSet in self.asTestSets:
1420 reporter.testStart(sTestSet);
1421 dTestSet = self.kdTestSets.get(sTestSet);
1422 self.testBenchmark(utils.getHostOs(), sIoTest, sMountPoint, oExecutor, dTestSet);
1423 reporter.testDone();
1424 self.cleanupStorage(self.oStorCfg);
1425 else:
1426 reporter.testFailure('Failed to prepare host storage');
1427 fRc = False;
1428 reporter.testDone();
1429 else:
1430 # Create the storage space first if it is not done before every test.
1431 sMountPoint = None;
1432 if self.fUseScratch:
1433 sMountPoint = self.sScratchPath;
1434 elif not self.fRecreateStorCfg:
1435 reporter.testStart('Create host storage');
1436 sMountPoint = self.prepareStorage(self.oStorCfg);
1437 if sMountPoint is None:
1438 reporter.testFailure('Failed to prepare host storage');
1439 fRc = False;
1440 self.oStorCfg.mkDirOnVolume(sMountPoint, 'test', 0o777);
1441 sMountPoint = sMountPoint + '/test';
1442 reporter.testDone();
1443
1444 if fRc:
1445 # Run the storage tests.
1446 if not self.testStorage(sMountPoint):
1447 fRc = False;
1448
1449 if not self.fRecreateStorCfg and not self.fUseScratch:
1450 self.cleanupStorage(self.oStorCfg);
1451 else:
1452 reporter.testFailure('Could not get disk configuration for host: %s' % (socket.getfqdn().lower()));
1453 fRc = False;
1454
1455 return fRc;
1456
1457if __name__ == '__main__':
1458 sys.exit(tdStorageBenchmark().main(sys.argv));
1459
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