VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/tests/storage/remoteexecutor.py@ 79663

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

ValitdationKit/tdStorageBenchmark1: Adjust for python

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.6 KB
Line 
1# -*- coding: utf-8 -*-
2# $Id: remoteexecutor.py 79663 2019-07-10 08:41:29Z vboxsync $
3
4"""
5VirtualBox Validation Kit - Storage benchmark, test execution helpers.
6"""
7
8__copyright__ = \
9"""
10Copyright (C) 2016-2019 Oracle Corporation
11
12This file is part of VirtualBox Open Source Edition (OSE), as
13available from http://www.virtualbox.org. This file is free software;
14you can redistribute it and/or modify it under the terms of the GNU
15General Public License (GPL) as published by the Free Software
16Foundation, in version 2 as it comes in the "COPYING" file of the
17VirtualBox OSE distribution. VirtualBox OSE is distributed in the
18hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
19
20The contents of this file may alternatively be used under the terms
21of the Common Development and Distribution License Version 1.0
22(CDDL) only, as it comes in the "COPYING.CDDL" file of the
23VirtualBox OSE distribution, in which case the provisions of the
24CDDL are applicable instead of those of the GPL.
25
26You may elect to license modified versions of this file under the
27terms and conditions of either the GPL or the CDDL or both.
28"""
29__version__ = "$Revision: 79663 $"
30
31
32# Standard Python imports.
33import array;
34import os;
35import shutil;
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
41import subprocess;
42
43# Validation Kit imports.
44from common import utils;
45from testdriver import reporter;
46
47
48
49class StdInOutBuffer(object):
50 """ Standard input output buffer """
51
52 def __init__(self, sInput = None):
53 self.sInput = StringIO();
54 if sInput is not None:
55 self.sInput.write(self._toString(sInput));
56 self.sInput.seek(0);
57 self.sOutput = '';
58
59 def _toString(self, sText):
60 """
61 Converts any possible array to
62 a string.
63 """
64 if isinstance(sText, array.array):
65 try:
66 return str(sText.tostring()); # tostring() returns bytes with python3.
67 except:
68 pass;
69 elif isinstance(sText, bytes):
70 return sText.decode('utf-8');
71
72 return sText;
73
74 def read(self, cb):
75 """file.read"""
76 return self.sInput.read(cb);
77
78 def write(self, sText):
79 """file.write"""
80 self.sOutput += self._toString(sText);
81 return None;
82
83 def getOutput(self):
84 """
85 Returns the output of the buffer.
86 """
87 return self.sOutput;
88
89 def close(self):
90 """ file.close """
91 return;
92
93class RemoteExecutor(object):
94 """
95 Helper for executing tests remotely through TXS or locally
96 """
97
98 def __init__(self, oTxsSession = None, asBinaryPaths = None, sScratchPath = None):
99 self.oTxsSession = oTxsSession;
100 self.asPaths = asBinaryPaths;
101 self.sScratchPath = sScratchPath;
102 if self.asPaths is None:
103 self.asPaths = [ ];
104
105 def _isFile(self, sFile):
106 """
107 Checks whether a file exists.
108 """
109 if self.oTxsSession is not None:
110 return self.oTxsSession.syncIsFile(sFile);
111 return os.path.isfile(sFile);
112
113 def _getBinaryPath(self, sBinary):
114 """
115 Returns the complete path of the given binary if found
116 from the configured search path or None if not found.
117 """
118 for sPath in self.asPaths:
119 sFile = sPath + '/' + sBinary;
120 if self._isFile(sFile):
121 return sFile;
122 return None;
123
124 def _sudoExecuteSync(self, asArgs, sInput):
125 """
126 Executes a sudo child process synchronously.
127 Returns a tuple [True, 0] if the process executed successfully
128 and returned 0, otherwise [False, rc] is returned.
129 """
130 reporter.log('Executing [sudo]: %s' % (asArgs, ));
131 reporter.flushall();
132 fRc = True;
133 sOutput = '';
134 sError = '';
135 try:
136 oProcess = utils.sudoProcessPopen(asArgs, stdout=subprocess.PIPE, stdin=subprocess.PIPE,
137 stderr=subprocess.PIPE, shell = False, close_fds = False);
138
139 sOutput, sError = oProcess.communicate(sInput);
140 iExitCode = oProcess.poll();
141
142 if iExitCode != 0:
143 fRc = False;
144 except:
145 reporter.errorXcpt();
146 fRc = False;
147 reporter.log('Exit code [sudo]: %s (%s)' % (fRc, asArgs));
148 return (fRc, str(sOutput), str(sError));
149
150 def _execLocallyOrThroughTxs(self, sExec, asArgs, sInput, cMsTimeout):
151 """
152 Executes the given program locally or through TXS based on the
153 current config.
154 """
155 fRc = False;
156 sOutput = None;
157 if self.oTxsSession is not None:
158 reporter.log('Executing [remote]: %s %s %s' % (sExec, asArgs, sInput));
159 reporter.flushall();
160 oStdOut = StdInOutBuffer();
161 oStdErr = StdInOutBuffer();
162 oStdIn = None;
163 if sInput is not None:
164 oStdIn = StdInOutBuffer(sInput);
165 else:
166 oStdIn = '/dev/null'; # pylint: disable=redefined-variable-type
167 fRc = self.oTxsSession.syncExecEx(sExec, (sExec,) + asArgs,
168 oStdIn = oStdIn, oStdOut = oStdOut,
169 oStdErr = oStdErr, cMsTimeout = cMsTimeout);
170 sOutput = oStdOut.getOutput();
171 sError = oStdErr.getOutput();
172 if fRc is False:
173 reporter.log('Exit code [remote]: %s (stdout: %s stderr: %s)' % (fRc, sOutput, sError));
174 else:
175 reporter.log('Exit code [remote]: %s' % (fRc,));
176 else:
177 fRc, sOutput, sError = self._sudoExecuteSync([sExec, ] + list(asArgs), sInput);
178 return (fRc, sOutput, sError);
179
180 def execBinary(self, sExec, asArgs, sInput = None, cMsTimeout = 3600000):
181 """
182 Executes the given binary with the given arguments
183 providing some optional input through stdin and
184 returning whether the process exited successfully and the output
185 in a string.
186 """
187
188 fRc = True;
189 sOutput = None;
190 sError = None;
191 sBinary = self._getBinaryPath(sExec);
192 if sBinary is not None:
193 fRc, sOutput, sError = self._execLocallyOrThroughTxs(sBinary, asArgs, sInput, cMsTimeout);
194 else:
195 fRc = False;
196 return (fRc, sOutput, sError);
197
198 def execBinaryNoStdOut(self, sExec, asArgs, sInput = None):
199 """
200 Executes the given binary with the given arguments
201 providing some optional input through stdin and
202 returning whether the process exited successfully.
203 """
204 fRc, _, _ = self.execBinary(sExec, asArgs, sInput);
205 return fRc;
206
207 def copyFile(self, sLocalFile, sFilename, cMsTimeout = 30000):
208 """
209 Copies the local file to the remote destination
210 if configured
211
212 Returns a file ID which can be used as an input parameter
213 to execBinary() resolving to the real filepath on the remote side
214 or locally.
215 """
216 sFileId = None;
217 if self.oTxsSession is not None:
218 sFileId = '${SCRATCH}/' + sFilename;
219 fRc = self.oTxsSession.syncUploadFile(sLocalFile, sFileId, cMsTimeout);
220 if not fRc:
221 sFileId = None;
222 else:
223 sFileId = self.sScratchPath + '/' + sFilename;
224 try:
225 shutil.copy(sLocalFile, sFileId);
226 except:
227 sFileId = None;
228
229 return sFileId;
230
231 def copyString(self, sContent, sFilename, cMsTimeout = 30000):
232 """
233 Creates a file remotely or locally with the given content.
234
235 Returns a file ID which can be used as an input parameter
236 to execBinary() resolving to the real filepath on the remote side
237 or locally.
238 """
239 sFileId = None;
240 if self.oTxsSession is not None:
241 sFileId = '${SCRATCH}/' + sFilename;
242 fRc = self.oTxsSession.syncUploadString(sContent, sFileId, cMsTimeout);
243 if not fRc:
244 sFileId = None;
245 else:
246 sFileId = self.sScratchPath + '/' + sFilename;
247 try:
248 oFile = open(sFileId, 'wb');
249 oFile.write(sContent);
250 oFile.close();
251 except:
252 sFileId = None;
253
254 return sFileId;
255
256 def mkDir(self, sDir, fMode = 0o700, cMsTimeout = 30000):
257 """
258 Creates a new directory at the given location.
259 """
260 fRc = True;
261 if self.oTxsSession is not None:
262 fRc = self.oTxsSession.syncMkDir(sDir, fMode, cMsTimeout);
263 else:
264 fRc = self.execBinaryNoStdOut('mkdir', ('-m', format(fMode, 'o'), sDir));
265
266 return fRc;
267
268 def rmDir(self, sDir, cMsTimeout = 30000):
269 """
270 Removes the given directory.
271 """
272 fRc = True;
273 if self.oTxsSession is not None:
274 fRc = self.oTxsSession.syncRmDir(sDir, cMsTimeout);
275 else:
276 fRc = self.execBinaryNoStdOut('rmdir', (sDir,));
277
278 return fRc;
279
280 def rmTree(self, sDir, cMsTimeout = 30000):
281 """
282 Recursively removes all files and sub directories including the given directory.
283 """
284 fRc = True;
285 if self.oTxsSession is not None:
286 fRc = self.oTxsSession.syncRmTree(sDir, cMsTimeout);
287 else:
288 try:
289 shutil.rmtree(sDir, ignore_errors=True);
290 except:
291 fRc = False;
292
293 return fRc;
294
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette