VirtualBox

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

Last change on this file since 98763 was 98763, checked in by vboxsync, 23 months ago

ValidationKit/{IoPerf,tdStorageBenchmark}: Don't report statistics of the IoPerf tool if requested in the testcase, some functionality tests would produce too many values for the maximum limit configured on the testmanager

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