VirtualBox

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

Last change on this file since 79608 was 79608, checked in by vboxsync, 6 years ago

ValidationKit/tdStorageBenchmark1: getfqdn() returns only testboxstor2 instead of testboxstor2.de.oracle.com

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