VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/utils/TestExecServ/txsshell/txsshell.py@ 109151

Last change on this file since 109151 was 107905, checked in by vboxsync, 4 months ago

ValKit/txsshell.py: fix pylint issue with ModuleNotFoundError use-before-definition

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.4 KB
Line 
1# -*- coding: utf-8 -*-
2# $Id: txsshell.py 107905 2025-01-23 10:02:59Z vboxsync $
3
4"""
5Test eXecution Service Shell.
6"""
7__copyright__ = \
8"""
9Copyright (C) 2025 Oracle and/or its affiliates.
10
11This file is part of VirtualBox base platform packages, as
12available from https://www.virtualbox.org.
13
14This program is free software; you can redistribute it and/or
15modify it under the terms of the GNU General Public License
16as published by the Free Software Foundation, in version 3 of the
17License.
18
19This program is distributed in the hope that it will be useful, but
20WITHOUT ANY WARRANTY; without even the implied warranty of
21MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22General Public License for more details.
23
24You should have received a copy of the GNU General Public License
25along with this program; if not, see <https://www.gnu.org/licenses>.
26
27The contents of this file may alternatively be used under the terms
28of the Common Development and Distribution License Version 1.0
29(CDDL), a copy of it is provided in the "COPYING.CDDL" file included
30in the VirtualBox distribution, in which case the provisions of the
31CDDL are applicable instead of those of the GPL.
32
33You may elect to license modified versions of this file under the
34terms and conditions of either the GPL or the CDDL or both.
35
36SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
37"""
38__version__ = '$Revision: 107905 $'
39
40import code;
41import os;
42import sys;
43import time;
44
45if sys.version_info[0] < 3 or (sys.version_info[0] == 3 and sys.version_info[1] < 6): # since 3.6
46 ModuleNotFoundError = ImportError # pylint: disable=redefined-builtin
47
48try: __file__ # pylint: disable=used-before-assignment
49except: __file__ = sys.argv[0];
50g_ksValidationKitDir = os.path.dirname(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '..', '..', '..'));
51sys.path.append(g_ksValidationKitDir);
52try:
53 from testdriver import reporter;
54 from testdriver import txsclient;
55except ModuleNotFoundError:
56 print('Error: Validation Kit testdriver module not found. Tweak your module import paths.');
57 print('Search path is: %s' % (sys.path,));
58 sys.exit(1);
59
60class TxsShell(code.InteractiveConsole):
61 """
62 The TxsShell implementation, derivred from code.InteractiveConsole.
63 """
64 def __init__(self, shellLocals=None, filename='<console>'):
65 """
66 Constructor.
67 """
68 code.InteractiveConsole.__init__(self, locals=shellLocals, filename=filename);
69 self.prompt = '>>> ';
70 self.cmds = {
71 'c': self.cmdConnect,
72 'connect': self.cmdConnect,
73 'd': self.cmdDisconnect,
74 'disconnect': self.cmdDisconnect,
75 'h': self.cmdHelp,
76 'help': self.cmdHelp,
77 'q': self.cmdQuit,
78 'quit': self.cmdQuit,
79 'r': self.cmdReconnect,
80 'reconnect': self.cmdReconnect,
81 's': self.cmdStatus,
82 'status': self.cmdStatus,
83 'v': self.cmdVerbose,
84 'verbose': self.cmdVerbose,
85 };
86 self.fTxsReversedSetup = None;
87 self.oTxsTransport = None;
88 self.oTxsSession = None;
89
90 self.setConnection();
91
92 def mainLoop(self):
93 """
94 The REPL main loop.
95 """
96 self.log('Welcome to VirtualBox TxsShell!\n\n'
97 'Type \'!quit\' or press Ctrl+D / CTRL + Z to exit.\n'
98 'Type \'!help\' for help.\n');
99 self.log('Default connection is set to %s:%u (%s)\n' \
100 % (self.sTxsHost, self.uTxsPort, 'reversed, as server' if self.fTxsReversedSetup else 'as client'));
101
102 try:
103 self.interact(banner = '');
104 except SystemExit:
105 pass
106 finally:
107 self.disconnect(fQuiet = True);
108 self.log('\nExiting. Have a nice day!');
109
110 def setConnection(self, sHostname=None, uPort=None, fReversed=None):
111 """
112 Set the TXS connection parameters.
113
114 Those will be used for retrieving the lastly used connection parameters.
115 """
116 try:
117 if not fReversed: # Use a reversed connection by default (if not explicitly specified).
118 fReversed = True;
119 self.sTxsHost = '127.0.0.1' if sHostname is None else sHostname;
120 assert self.sTxsHost is not None;
121 if uPort is None:
122 self.uTxsPort = 5048 if fReversed else 5042;
123 else:
124 self.uTxsPort = int(uPort);
125 self.fTxsReversedSetup = True if fReversed is None else fReversed;
126 self.oTxsTransport = None;
127 self.oTxsSession = None;
128 except ValueError:
129 self.log('Invalid parameters given!');
130 return False;
131 return True;
132
133 def connect(self, sHostname=None, uPort=None, fReversed=None, cMsTimeout = 30 * 1000):
134 """
135 Connects to a TXS instance (server or client).
136 """
137 if not sHostname:
138 sHostname = self.sTxsHost;
139 if not uPort:
140 uPort = self.uTxsPort;
141 if not fReversed:
142 fReversed = self.fTxsReversedSetup;
143 self.log('%s (%dms timeout) ...'
144 % ('Waiting for connection from TXS' if fReversed is True else 'Connecting to TXS', cMsTimeout));
145 try:
146 self.oTxsTransport = txsclient.TransportTcp(sHostname, uPort, fReversed);
147 if not self.oTxsTransport:
148 return False;
149 self.oTxsSession = txsclient.Session(self.oTxsTransport, cMsTimeout, cMsIdleFudge = 500, fTryConnect = True);
150 if not self.oTxsSession:
151 return False;
152 while not self.oTxsSession.isSuccess():
153 time.sleep(self.oTxsSession.getMsLeft(1, 1000) / 1000.0);
154 self.log('.', end='', flush=True);
155 except KeyboardInterrupt:
156 self.oTxsSession.cancelTask();
157 self.log('Connection cancelled');
158 self.disconnect();
159 return False;
160 self.log(''); # New line after connection dots.
161 if self.oTxsSession.hasTimedOut() \
162 or self.oTxsSession.isCancelled():
163 self.log('Connection error');
164 self.disconnect();
165 return False;
166
167 self.log('Connection successful');
168 return True;
169
170 def disconnect(self, fQuiet = True):
171 """
172 Disconnects from a TXS instance.
173 """
174 if self.oTxsSession:
175 if self.oTxsTransport:
176 rc = self.oTxsSession.sendMsg('BYE');
177 if rc is True:
178 rc = self.oTxsSession.recvAckLogged('BYE');
179 self.oTxsTransport.disconnect();
180 self.oTxsTransport = None;
181 self.oTxsSession = None;
182 if not fQuiet:
183 self.log('Disconnected.');
184 elif not fQuiet:
185 self.log('Not connected.');
186
187 def reconnect(self, fQuiet = False):
188 """
189 Re-connects to a TXS instance.
190 """
191 self.disconnect(fQuiet);
192 self.connect(fQuiet);
193
194 def sendMsg(self, sOpcode, asArgs):
195 """
196 Sends a message to a TXS instance.
197 """
198 if not self.oTxsSession:
199 self.log('Not connected.');
200 return;
201 fRc = self.oTxsSession.sendMsg(sOpcode, aoPayload = asArgs);
202 if fRc:
203 fRc = self.oTxsSession.recvAckLogged(sOpcode, False);
204
205 def cmdConnect(self, sHostname=None, uPort=None, fReversed=None, fQuiet = False):
206 """
207 Handles the '!connect' / '!c' command.
208 """
209 self.disconnect();
210 if not self.setConnection(sHostname, uPort, fReversed):
211 return;
212
213 if not fQuiet:
214 self.log('Connecting to %s:%u (%s) ...' % \
215 (self.sTxsHost, self.uTxsPort, 'reversed, as server' if self.fTxsReversedSetup else 'as client'));
216 fRc = self.connect(sHostname, uPort, fReversed);
217 if not fRc:
218 self.log('Hint: Is connecting to the host allowed by the VM?\n' \
219 ' Try VBoxManage modifyvm <VM> --nat-localhostreachable1=on\n\n');
220
221 def cmdVerbose(self):
222 """
223 Handles the '!verbose' / '!v' command.
224 """
225 reporter.incVerbosity();
226 reporter.incVerbosity();
227 reporter.incVerbosity();
228
229 def cmdDisconnect(self):
230 """
231 Handles the '!disconnect' / '!d' command.
232 """
233 self.disconnect(fQuiet = False);
234
235 def cmdHelp(self):
236 """
237 Handles the '!help' / '!h' command.
238 """
239 self.log('!connect|!c');
240 self.log(' Connects to a TXS instance.');
241 self.log('!disconnect|!d');
242 self.log(' Disconnects from a TXS instance.');
243 self.log('!help|!h');
244 self.log(' Displays this help.');
245 self.log('!quit|!q');
246 self.log(' Quits this application.');
247 self.log('!reconnect|!r');
248 self.log(' Reconnects to the last connected TXS instance.');
249 self.log('!status|!s');
250 self.log(' Prints the current connection status.');
251 self.log('!verbose|!v');
252 self.log(' Increases the logging verbosity.');
253 self.log();
254 self.log('When connected to a TXS instance, anything else will be sent');
255 self.log('directly to TXS (including parameters), for example:');
256 self.log(' ISDIR /tmp/');
257 self.log();
258
259 def cmdQuit(self):
260 """
261 Handles the '!quit' / '!q' command.
262 """
263 raise SystemExit;
264
265 def cmdReconnect(self):
266 """
267 Handles the '!reconnect' / '!r' command.
268 """
269 self.reconnect();
270
271 def cmdStatus(self):
272 """
273 Handles the '!s' / '!s' command.
274 """
275 if self.oTxsSession:
276 self.log('Connected to %s:%u (%s)' % \
277 (self.sTxsHost, self.uTxsPort, 'reversed, as server' if self.fTxsReversedSetup else 'as client'));
278 else:
279 self.log('Not connected.');
280
281 def log(self, sText = None, end = '\n', flush = None):
282 """
283 Prints a message
284 """
285 if sText:
286 sys.stdout.write(sText);
287 if end:
288 sys.stdout.write(end);
289 if flush is True:
290 sys.stdout.flush();
291
292 def raw_input(self, prompt=''):
293 """
294 Overwrites raw_input() to handle custom commands.
295 """
296 try:
297 sLine = code.InteractiveConsole.raw_input(self, prompt);
298 except EOFError:
299 raise SystemExit;
300 except KeyboardInterrupt:
301 self.log();
302 return self.raw_input(prompt);
303
304 # Check if the line is a custom command.
305 if sLine.startswith('!'):
306 asCmdTokens = sLine[1:].strip().split();
307 if not asCmdTokens:
308 self.log('No command specified.');
309 return self.raw_input(prompt);
310
311 sCmdName = asCmdTokens[0];
312 asArgs = asCmdTokens[1:];
313
314 if sCmdName in self.cmds:
315 try:
316 # Call the custom command with the provided arguments.
317 self.cmds[sCmdName](*asArgs);
318 except TypeError as e:
319 self.log('*** Error: %s' % (e, ));
320 return self.raw_input(prompt);
321
322 self.log('*** Unknown command: %s' % (sCmdName, ));
323 return self.raw_input(prompt);
324
325 # Send to TXS.
326 asCmdTokens = sLine.strip().split();
327 if asCmdTokens:
328 self.sendMsg(asCmdTokens[0], asCmdTokens[1:]);
329
330 return ''; # Don't evaluate as normal Python code.
331
332if __name__ == '__main__':
333 TxsShell(shellLocals=globals()).mainLoop();
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