VirtualBox

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

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

ValKit,++: Pylint 2.3.1 adjustments.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.0 KB
Line 
1# -*- coding: utf-8 -*-
2# $Id: remoteexecutor.py 79092 2019-06-11 15:26:40Z 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: 79092 $"
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 sText.tostring();
67 except:
68 pass;
69 else:
70 return sText;
71
72 def read(self, cb):
73 """file.read"""
74 return self.sInput.read(cb);
75
76 def write(self, sText):
77 """file.write"""
78 self.sOutput += self._toString(sText);
79 return None;
80
81 def getOutput(self):
82 """
83 Returns the output of the buffer.
84 """
85 return self.sOutput;
86
87 def close(self):
88 """ file.close """
89 return;
90
91class RemoteExecutor(object):
92 """
93 Helper for executing tests remotely through TXS or locally
94 """
95
96 def __init__(self, oTxsSession = None, asBinaryPaths = None, sScratchPath = None):
97 self.oTxsSession = oTxsSession;
98 self.asPaths = asBinaryPaths;
99 self.sScratchPath = sScratchPath;
100 if self.asPaths is None:
101 self.asPaths = [ ];
102
103 def _isFile(self, sFile):
104 """
105 Checks whether a file exists.
106 """
107 if self.oTxsSession is not None:
108 return self.oTxsSession.syncIsFile(sFile);
109 return os.path.isfile(sFile);
110
111 def _getBinaryPath(self, sBinary):
112 """
113 Returns the complete path of the given binary if found
114 from the configured search path or None if not found.
115 """
116 for sPath in self.asPaths:
117 sFile = sPath + '/' + sBinary;
118 if self._isFile(sFile):
119 return sFile;
120 return None;
121
122 def _sudoExecuteSync(self, asArgs, sInput):
123 """
124 Executes a sudo child process synchronously.
125 Returns a tuple [True, 0] if the process executed successfully
126 and returned 0, otherwise [False, rc] is returned.
127 """
128 reporter.log('Executing [sudo]: %s' % (asArgs, ));
129 reporter.flushall();
130 fRc = True;
131 sOutput = '';
132 sError = '';
133 try:
134 oProcess = utils.sudoProcessPopen(asArgs, stdout=subprocess.PIPE, stdin=subprocess.PIPE,
135 stderr=subprocess.PIPE, shell = False, close_fds = False);
136
137 sOutput, sError = oProcess.communicate(sInput);
138 iExitCode = oProcess.poll();
139
140 if iExitCode != 0:
141 fRc = False;
142 except:
143 reporter.errorXcpt();
144 fRc = False;
145 reporter.log('Exit code [sudo]: %s (%s)' % (fRc, asArgs));
146 return (fRc, str(sOutput), str(sError));
147
148 def _execLocallyOrThroughTxs(self, sExec, asArgs, sInput, cMsTimeout):
149 """
150 Executes the given program locally or through TXS based on the
151 current config.
152 """
153 fRc = False;
154 sOutput = None;
155 if self.oTxsSession is not None:
156 reporter.log('Executing [remote]: %s %s %s' % (sExec, asArgs, sInput));
157 reporter.flushall();
158 oStdOut = StdInOutBuffer();
159 oStdErr = StdInOutBuffer();
160 oStdIn = None;
161 if sInput is not None:
162 oStdIn = StdInOutBuffer(sInput);
163 else:
164 oStdIn = '/dev/null'; # pylint: disable=redefined-variable-type
165 fRc = self.oTxsSession.syncExecEx(sExec, (sExec,) + asArgs,
166 oStdIn = oStdIn, oStdOut = oStdOut,
167 oStdErr = oStdErr, cMsTimeout = cMsTimeout);
168 sOutput = oStdOut.getOutput();
169 sError = oStdErr.getOutput();
170 if fRc is False:
171 reporter.log('Exit code [remote]: %s (stdout: %s stderr: %s)' % (fRc, sOutput, sError));
172 else:
173 reporter.log('Exit code [remote]: %s' % (fRc,));
174 else:
175 fRc, sOutput, sError = self._sudoExecuteSync([sExec, ] + list(asArgs), sInput);
176 return (fRc, sOutput, sError);
177
178 def execBinary(self, sExec, asArgs, sInput = None, cMsTimeout = 3600000):
179 """
180 Executes the given binary with the given arguments
181 providing some optional input through stdin and
182 returning whether the process exited successfully and the output
183 in a string.
184 """
185
186 fRc = True;
187 sOutput = None;
188 sError = None;
189 sBinary = self._getBinaryPath(sExec);
190 if sBinary is not None:
191 fRc, sOutput, sError = self._execLocallyOrThroughTxs(sBinary, asArgs, sInput, cMsTimeout);
192 else:
193 fRc = False;
194 return (fRc, sOutput, sError);
195
196 def execBinaryNoStdOut(self, sExec, asArgs, sInput = None):
197 """
198 Executes the given binary with the given arguments
199 providing some optional input through stdin and
200 returning whether the process exited successfully.
201 """
202 fRc, _, _ = self.execBinary(sExec, asArgs, sInput);
203 return fRc;
204
205 def copyFile(self, sLocalFile, sFilename, cMsTimeout = 30000):
206 """
207 Copies the local file to the remote destination
208 if configured
209
210 Returns a file ID which can be used as an input parameter
211 to execBinary() resolving to the real filepath on the remote side
212 or locally.
213 """
214 sFileId = None;
215 if self.oTxsSession is not None:
216 sFileId = '${SCRATCH}/' + sFilename;
217 fRc = self.oTxsSession.syncUploadFile(sLocalFile, sFileId, cMsTimeout);
218 if not fRc:
219 sFileId = None;
220 else:
221 sFileId = self.sScratchPath + '/' + sFilename;
222 try:
223 shutil.copy(sLocalFile, sFileId);
224 except:
225 sFileId = None;
226
227 return sFileId;
228
229 def copyString(self, sContent, sFilename, cMsTimeout = 30000):
230 """
231 Creates a file remotely or locally with the given content.
232
233 Returns a file ID which can be used as an input parameter
234 to execBinary() resolving to the real filepath on the remote side
235 or locally.
236 """
237 sFileId = None;
238 if self.oTxsSession is not None:
239 sFileId = '${SCRATCH}/' + sFilename;
240 fRc = self.oTxsSession.syncUploadString(sContent, sFileId, cMsTimeout);
241 if not fRc:
242 sFileId = None;
243 else:
244 sFileId = self.sScratchPath + '/' + sFilename;
245 try:
246 oFile = open(sFileId, 'wb');
247 oFile.write(sContent);
248 oFile.close();
249 except:
250 sFileId = None;
251
252 return sFileId;
253
254 def mkDir(self, sDir, fMode = 0o700, cMsTimeout = 30000):
255 """
256 Creates a new directory at the given location.
257 """
258 fRc = True;
259 if self.oTxsSession is not None:
260 fRc = self.oTxsSession.syncMkDir(sDir, fMode, cMsTimeout);
261 else:
262 fRc = self.execBinaryNoStdOut('mkdir', ('-m', format(fMode, 'o'), sDir));
263
264 return fRc;
265
266 def rmDir(self, sDir, cMsTimeout = 30000):
267 """
268 Removes the given directory.
269 """
270 fRc = True;
271 if self.oTxsSession is not None:
272 fRc = self.oTxsSession.syncRmDir(sDir, cMsTimeout);
273 else:
274 fRc = self.execBinaryNoStdOut('rmdir', (sDir,));
275
276 return fRc;
277
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