1 | #!/usr/bin/env python
|
---|
2 | # -*- coding: utf-8 -*-
|
---|
3 | # "$Id: tdMoveVM1.py 71464 2018-03-22 16:15:14Z vboxsync $"
|
---|
4 |
|
---|
5 | """
|
---|
6 | VirtualBox Validation Kit - VM Move Test #1
|
---|
7 | """
|
---|
8 |
|
---|
9 | __copyright__ = \
|
---|
10 | """
|
---|
11 | Copyright (C) 2010-2018 Oracle Corporation
|
---|
12 |
|
---|
13 | This file is part of VirtualBox Open Source Edition (OSE), as
|
---|
14 | available from http://www.virtualbox.org. This file is free software;
|
---|
15 | you can redistribute it and/or modify it under the terms of the GNU
|
---|
16 | General Public License (GPL) as published by the Free Software
|
---|
17 | Foundation, in version 2 as it comes in the "COPYING" file of the
|
---|
18 | VirtualBox OSE distribution. VirtualBox OSE is distributed in the
|
---|
19 | hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
|
---|
20 |
|
---|
21 | The contents of this file may alternatively be used under the terms
|
---|
22 | of the Common Development and Distribution License Version 1.0
|
---|
23 | (CDDL) only, as it comes in the "COPYING.CDDL" file of the
|
---|
24 | VirtualBox OSE distribution, in which case the provisions of the
|
---|
25 | CDDL are applicable instead of those of the GPL.
|
---|
26 |
|
---|
27 | You may elect to license modified versions of this file under the
|
---|
28 | terms and conditions of either the GPL or the CDDL or both.
|
---|
29 | """
|
---|
30 | __version__ = "$Revision: 71464 $"
|
---|
31 |
|
---|
32 | # Standard Python imports.
|
---|
33 | import os
|
---|
34 | import sys
|
---|
35 | import time
|
---|
36 | import shutil
|
---|
37 |
|
---|
38 | # Only the main script needs to modify the path.
|
---|
39 | try: __file__
|
---|
40 | except: __file__ = sys.argv[0]
|
---|
41 | g_ksValidationKitDir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
---|
42 | sys.path.append(g_ksValidationKitDir)
|
---|
43 |
|
---|
44 | # Validation Kit imports.
|
---|
45 | from testdriver import base
|
---|
46 | from testdriver import reporter
|
---|
47 | from testdriver import vboxcon
|
---|
48 | from testdriver import vboxwrappers
|
---|
49 | from tdMoveMedium1 import SubTstDrvMoveMedium1
|
---|
50 |
|
---|
51 | class SubTstDrvMoveVM1(base.SubTestDriverBase):
|
---|
52 | """
|
---|
53 | Sub-test driver for VM Move Test #1.
|
---|
54 | """
|
---|
55 |
|
---|
56 | def __init__(self, oTstDrv):
|
---|
57 | base.SubTestDriverBase.__init__(self, 'move-vm', oTstDrv)
|
---|
58 | self.asRsrcs = self.__getResourceSet()
|
---|
59 |
|
---|
60 | for oRes in self.asRsrcs:
|
---|
61 | reporter.log('Resource is "%s"' % (oRes,))
|
---|
62 |
|
---|
63 | def testIt(self):
|
---|
64 | """
|
---|
65 | Execute the sub-testcase.
|
---|
66 | """
|
---|
67 | reporter.log('ValidationKit folder is "%s"' % (g_ksValidationKitDir,))
|
---|
68 | return self.testVMMove()
|
---|
69 |
|
---|
70 | #
|
---|
71 | # Test execution helpers.
|
---|
72 | #
|
---|
73 |
|
---|
74 | #
|
---|
75 | #createTestMachine
|
---|
76 | #
|
---|
77 | def createTestMachine(self):
|
---|
78 | oVM = self.oTstDrv.createTestVM('test-vm-move', 1, None, 4)
|
---|
79 | if oVM is None:
|
---|
80 | return None
|
---|
81 |
|
---|
82 | # create hard disk images, one for each file-based backend, using the first applicable extension
|
---|
83 | fRc = True
|
---|
84 | oSession = self.oTstDrv.openSession(oVM)
|
---|
85 | aoDskFmts = self.oTstDrv.oVBoxMgr.getArray(self.oTstDrv.oVBox.systemProperties, 'mediumFormats')
|
---|
86 | asFiles = []
|
---|
87 | for oDskFmt in aoDskFmts:
|
---|
88 | aoDskFmtCaps = self.oTstDrv.oVBoxMgr.getArray(oDskFmt, 'capabilities')
|
---|
89 | if vboxcon.MediumFormatCapabilities_File not in aoDskFmtCaps \
|
---|
90 | or vboxcon.MediumFormatCapabilities_CreateDynamic not in aoDskFmtCaps:
|
---|
91 | continue
|
---|
92 | (asExts, aTypes) = oDskFmt.describeFileExtensions()
|
---|
93 | for i in range(0, len(asExts)):
|
---|
94 | if aTypes[i] is vboxcon.DeviceType_HardDisk:
|
---|
95 | sExt = '.' + asExts[i]
|
---|
96 | break
|
---|
97 | if sExt is None:
|
---|
98 | fRc = False
|
---|
99 | break
|
---|
100 | sFile = 'test-vm-move' + str(len(asFiles)) + sExt
|
---|
101 | sHddPath = os.path.join(self.oTstDrv.sScratchPath, sFile)
|
---|
102 | oHd = oSession.createBaseHd(sHddPath, sFmt=oDskFmt.id, cb=1024*1024)
|
---|
103 | if oHd is None:
|
---|
104 | fRc = False
|
---|
105 | break
|
---|
106 |
|
---|
107 | # attach HDD, IDE controller exists by default, but we use SATA just in case
|
---|
108 | sController='SATA Controller'
|
---|
109 | fRc = fRc and oSession.attachHd(sHddPath, sController, iPort = len(asFiles),
|
---|
110 | fImmutable=False, fForceResource=False)
|
---|
111 | if fRc:
|
---|
112 | asFiles.append(sFile)
|
---|
113 |
|
---|
114 | fRc = fRc and oSession.saveSettings()
|
---|
115 | fRc = oSession.close() and fRc
|
---|
116 |
|
---|
117 | if fRc is False:
|
---|
118 | oVM = None
|
---|
119 |
|
---|
120 | return oVM
|
---|
121 |
|
---|
122 | #
|
---|
123 | #moveVMToLocation
|
---|
124 | #
|
---|
125 | def moveVMToLocation(self, sLocation, oVM):
|
---|
126 | fRc = True
|
---|
127 | try:
|
---|
128 | #move machine
|
---|
129 | reporter.log('Moving machine "%s" to the "%s"' % (oVM.name, sLocation))
|
---|
130 | oType = 'basic'
|
---|
131 | oProgress = vboxwrappers.ProgressWrapper(oVM.moveTo(sLocation, oType), self.oTstDrv.oVBoxMgr, self.oTstDrv,
|
---|
132 | 'moving machine "%s"' % (oVM.name,))
|
---|
133 |
|
---|
134 | except:
|
---|
135 | return reporter.errorXcpt('Machine::moveTo("%s") for machine "%s" failed' % (sLocation, oVM.name,))
|
---|
136 |
|
---|
137 | oProgress.wait()
|
---|
138 | if oProgress.logResult() is False:
|
---|
139 | fRc = False
|
---|
140 | reporter.log('Progress object returned False')
|
---|
141 | else:
|
---|
142 | fRc = True
|
---|
143 |
|
---|
144 | return fRc
|
---|
145 |
|
---|
146 | #
|
---|
147 | #checkLocation
|
---|
148 | #
|
---|
149 | def checkLocation(self, sLocation, aoMediumAttachments, asFiles):
|
---|
150 | fRc = True
|
---|
151 | for oAttachment in aoMediumAttachments:
|
---|
152 | sFilePath = os.path.join(sLocation, asFiles[oAttachment.port])
|
---|
153 | sActualFilePath = oAttachment.medium.location
|
---|
154 | if os.path.abspath(sFilePath) != os.path.abspath(sActualFilePath):
|
---|
155 | reporter.log('medium location expected to be "%s" but is "%s"' % (sFilePath, sActualFilePath))
|
---|
156 | fRc = False
|
---|
157 | if not os.path.exists(sFilePath):
|
---|
158 | reporter.log('medium file does not exist at "%s"' % (sFilePath,))
|
---|
159 | fRc = False
|
---|
160 | return fRc
|
---|
161 |
|
---|
162 | #
|
---|
163 | #checkAPIVersion
|
---|
164 | #
|
---|
165 | def checkAPIVersion(self):
|
---|
166 | if self.oTstDrv.fpApiVer >= 5.3:
|
---|
167 | return True
|
---|
168 |
|
---|
169 | return False
|
---|
170 |
|
---|
171 | def __getResourceSet(self):
|
---|
172 | # Construct the resource list the first time it's queried.
|
---|
173 | if self.oTstDrv.asRsrcs is None:
|
---|
174 | self.oTstDrv.asRsrcs = []
|
---|
175 | self.oTstDrv.asRsrcs.append('5.3/isos/tdMoveVM.iso')
|
---|
176 | self.oTstDrv.asRsrcs.append('5.3/floppy/tdMoveVM.img')
|
---|
177 |
|
---|
178 | return self.oTstDrv.asRsrcs
|
---|
179 |
|
---|
180 | def __testScenario_4(self, oMachine, sNewLoc, sOldLoc = 0):
|
---|
181 |
|
---|
182 | #Run VM and get new Session object
|
---|
183 | oSession = self.oTstDrv.startVm(oMachine)
|
---|
184 |
|
---|
185 | #some time interval should be here for not closing VM just after start
|
---|
186 | time.sleep(1)
|
---|
187 |
|
---|
188 | if oMachine.state != self.oTstDrv.oVBoxMgr.constants.MachineState_Running:
|
---|
189 | reporter.log("Machine '%s' is not Running" % (oMachine.name))
|
---|
190 | fRc = False
|
---|
191 |
|
---|
192 | #call Session::saveState(), already closes session unless it failed
|
---|
193 | fRc = oSession.saveState()
|
---|
194 | self.oTstDrv.terminateVmBySession(oSession)
|
---|
195 |
|
---|
196 | if fRc:
|
---|
197 | #create a new Session object for moving VM
|
---|
198 | oSession = self.oTstDrv.openSession(oMachine)
|
---|
199 | fRc = self.moveVMToLocation(sNewLoc, oSession.o.machine) and fRc
|
---|
200 |
|
---|
201 | # cleaning up: get rid of saved state
|
---|
202 | fRc = fRc and oSession.discardSavedState(True)
|
---|
203 | if fRc is False:
|
---|
204 | reporter.log('Failed to discard the saved state of machine')
|
---|
205 |
|
---|
206 | fRc = oSession.close() and fRc
|
---|
207 | if fRc is False:
|
---|
208 | reporter.log('Couldn\'t close machine session')
|
---|
209 |
|
---|
210 | return fRc
|
---|
211 |
|
---|
212 | def __testScenario_5(self, oMachine, sNewLoc, sOldLoc = 0):
|
---|
213 |
|
---|
214 | fRc = True
|
---|
215 | #create a new Session object
|
---|
216 | oSession = self.oTstDrv.openSession(oMachine)
|
---|
217 |
|
---|
218 | sISOLoc = '5.3/isos/tdMoveVM1.iso'
|
---|
219 | reporter.log("sHost is '%s', sResourcePath is '%s'" % (self.oTstDrv.sHost, self.oTstDrv.sResourcePath))
|
---|
220 | sISOLoc = self.oTstDrv.getFullResourceName(sISOLoc)
|
---|
221 |
|
---|
222 | if not os.path.exists(sISOLoc):
|
---|
223 | reporter.log('ISO file does not exist at "%s"' % (sISOLoc,))
|
---|
224 | fRc = False
|
---|
225 |
|
---|
226 | #Copy ISO image from the common resource folder into machine folder
|
---|
227 | shutil.copy(sISOLoc, sOldLoc)
|
---|
228 |
|
---|
229 | #attach ISO image to the IDE controller
|
---|
230 | if fRc is True:
|
---|
231 | #set actual ISO location
|
---|
232 | sISOLoc = sOldLoc + os.sep + 'tdMoveVM1.iso'
|
---|
233 | sController='IDE Controller'
|
---|
234 | aoMediumAttachments = oMachine.getMediumAttachmentsOfController(sController)
|
---|
235 | iPort = len(aoMediumAttachments)
|
---|
236 | reporter.log('sISOLoc "%s", sController "%s", iPort "%s"' % (sISOLoc,sController,iPort))
|
---|
237 | fRc = oSession.attachDvd(sISOLoc, sController, iPort, iDevice = 0)
|
---|
238 |
|
---|
239 | if fRc is True:
|
---|
240 | fRc = self.moveVMToLocation(sNewLoc, oSession.o.machine) and fRc
|
---|
241 |
|
---|
242 | #detach ISO image
|
---|
243 | fRc = oSession.detachHd(sController, iPort, 0)
|
---|
244 |
|
---|
245 | fRc = fRc and oSession.saveSettings()
|
---|
246 | if fRc is False:
|
---|
247 | reporter.log('Couldn\'t save machine settings after 5th scenario')
|
---|
248 |
|
---|
249 | fRc = oSession.close() and fRc
|
---|
250 | if fRc is False:
|
---|
251 | reporter.log('Couldn\'t close machine session')
|
---|
252 |
|
---|
253 | return fRc
|
---|
254 |
|
---|
255 | def __testScenario_6(self, oMachine, sNewLoc, sOldLoc = 0):
|
---|
256 |
|
---|
257 | fRc = True
|
---|
258 | #create a new Session object
|
---|
259 | oSession = self.oTstDrv.openSession(oMachine)
|
---|
260 |
|
---|
261 | sFloppyLoc = '5.3/floppy/tdMoveVM1.img'
|
---|
262 | sFloppyLoc = self.oTstDrv.getFullResourceName(sFloppyLoc)
|
---|
263 |
|
---|
264 | if not os.path.exists(sFloppyLoc):
|
---|
265 | reporter.log('Floppy disk does not exist at "%s"' % (sFloppyLoc,))
|
---|
266 | fRc = False
|
---|
267 |
|
---|
268 | #Copy floppy image from the common resource folder into machine folder
|
---|
269 | shutil.copy(sFloppyLoc, sOldLoc)
|
---|
270 |
|
---|
271 | # attach floppy image
|
---|
272 | if fRc is True:
|
---|
273 | #set actual floppy location
|
---|
274 | sFloppyLoc = sOldLoc + os.sep + 'tdMoveVM1.img'
|
---|
275 | sController='Floppy Controller'
|
---|
276 | reporter.log('sFloppyLoc "%s", sController "%s"' % (sFloppyLoc,sController))
|
---|
277 | fRc = fRc and oSession.attachFloppy(sFloppyLoc, sController, 0, 0)
|
---|
278 |
|
---|
279 | if fRc is True:
|
---|
280 | fRc = self.moveVMToLocation(sNewLoc, oSession.o.machine) and fRc
|
---|
281 |
|
---|
282 | #detach floppy image
|
---|
283 | fRc = oSession.detachHd(sController, 0, 0)
|
---|
284 |
|
---|
285 | fRc = fRc and oSession.saveSettings()
|
---|
286 | if fRc is False:
|
---|
287 | reporter.log('Couldn\'t save machine settings after 6th scenario')
|
---|
288 |
|
---|
289 | fRc = oSession.close() and fRc
|
---|
290 | if fRc is False:
|
---|
291 | reporter.log('Couldn\'t close machine session')
|
---|
292 |
|
---|
293 | return fRc
|
---|
294 |
|
---|
295 | #
|
---|
296 | #testVMMove
|
---|
297 | #
|
---|
298 | def testVMMove(self):
|
---|
299 | """
|
---|
300 | Test machine moving.
|
---|
301 | """
|
---|
302 | reporter.testStart('machine moving')
|
---|
303 |
|
---|
304 | if not self.oTstDrv.importVBoxApi():
|
---|
305 | return False
|
---|
306 |
|
---|
307 | isSupported = self.checkAPIVersion()
|
---|
308 |
|
---|
309 | if isSupported is False:
|
---|
310 | reporter.log('API version is below "%s". Just skip this test.' % (self.oTstDrv.fpApiVer))
|
---|
311 | return reporter.testDone()[1] == 0
|
---|
312 | else:
|
---|
313 | reporter.log('API version is "%s". Continuing the test.' % (self.oTstDrv.fpApiVer))
|
---|
314 |
|
---|
315 | #Scenarios
|
---|
316 | #1. All disks attached to VM are located outside the VM's folder.
|
---|
317 | # There are no any snapshots and logs.
|
---|
318 | # In this case only VM setting file should be moved (.vbox file)
|
---|
319 | #
|
---|
320 | #2. All disks attached to VM are located inside the VM's folder.
|
---|
321 | # There are no any snapshots and logs.
|
---|
322 | #
|
---|
323 | #3. There are snapshots.
|
---|
324 | #
|
---|
325 | #4. There are one or more save state files in the snapshots folder
|
---|
326 | # and some files in the logs folder.
|
---|
327 | #
|
---|
328 | #5. There is an ISO image (.iso) attached to the VM.
|
---|
329 | #
|
---|
330 | #6. There is a floppy image (.img) attached to the VM.
|
---|
331 | #
|
---|
332 | #7. There are shareable disk and immutable disk attached to the VM.
|
---|
333 |
|
---|
334 | try:
|
---|
335 | #create test machine
|
---|
336 | oMachine = self.createTestMachine()
|
---|
337 |
|
---|
338 | if oMachine is None:
|
---|
339 | reporter.error('Failed to create test machine')
|
---|
340 |
|
---|
341 | #create temporary subdirectory in the current working directory
|
---|
342 | sOrigLoc = self.oTstDrv.sScratchPath
|
---|
343 | sBaseLoc = os.path.join(sOrigLoc, 'moveFolder')
|
---|
344 | os.mkdir(sBaseLoc, 0o775)
|
---|
345 |
|
---|
346 | sController='SATA Controller'
|
---|
347 | aoMediumAttachments = oMachine.getMediumAttachmentsOfController(sController)
|
---|
348 |
|
---|
349 | #lock machine
|
---|
350 | #get session machine
|
---|
351 | oSession = self.oTstDrv.openSession(oMachine)
|
---|
352 | fRc = True
|
---|
353 |
|
---|
354 | sNewLoc = sBaseLoc + os.sep
|
---|
355 | ############# 1 case. ##########################################################################################
|
---|
356 | # All disks attached to VM are located outside the VM's folder.
|
---|
357 | # There are no any snapshots and logs.
|
---|
358 | # In this case only VM setting file should be moved (.vbox file)
|
---|
359 | fRc = self.moveVMToLocation(sNewLoc, oSession.o.machine) and fRc
|
---|
360 |
|
---|
361 | fRc = fRc and oSession.saveSettings()
|
---|
362 | if fRc is False:
|
---|
363 | reporter.log('Couldn\'t save machine settings after 1t scenario')
|
---|
364 |
|
---|
365 | ############# 2 case. ##########################################################################################
|
---|
366 | # All disks attached to VM are located inside the VM's folder.
|
---|
367 | # There are no any snapshots and logs.
|
---|
368 | sOldLoc = sNewLoc + os.sep + oMachine.name + os.sep
|
---|
369 | sNewLoc = os.path.join(sOrigLoc, 'moveFolder_2d_scenario')
|
---|
370 | os.mkdir(sNewLoc, 0o775)
|
---|
371 | aoMediumAttachments = oMachine.getMediumAttachmentsOfController(sController)
|
---|
372 | oSubTstDrvMoveMedium1Instance = SubTstDrvMoveMedium1(self.oTstDrv)
|
---|
373 | oSubTstDrvMoveMedium1Instance.setLocation(sOldLoc, aoMediumAttachments)
|
---|
374 |
|
---|
375 | del oSubTstDrvMoveMedium1Instance
|
---|
376 |
|
---|
377 | fRc = self.moveVMToLocation(sNewLoc, oSession.o.machine) and fRc
|
---|
378 |
|
---|
379 | fRc = fRc and oSession.saveSettings()
|
---|
380 | if fRc is False:
|
---|
381 | reporter.log('Couldn\'t save machine settings after 2nd scenario')
|
---|
382 |
|
---|
383 | ############# 3 case. ##########################################################################################
|
---|
384 | # There are snapshots.
|
---|
385 | sOldLoc = sNewLoc + os.sep + oMachine.name + os.sep
|
---|
386 | sNewLoc = os.path.join(sOrigLoc, 'moveFolder_3d_scenario')
|
---|
387 | os.mkdir(sNewLoc, 0o775)
|
---|
388 |
|
---|
389 | cSnap = 2
|
---|
390 | for counter in range(1,cSnap+1):
|
---|
391 | strSnapshot = 'Snapshot' + str(counter)
|
---|
392 | fRc = fRc and oSession.takeSnapshot(strSnapshot)
|
---|
393 | if fRc is False:
|
---|
394 | reporter.error('Error: Can\'t take snapshot "%s".' % (strSnapshot,))
|
---|
395 | reporter.testFailure('Error: Can\'t take snapshot "%s".' % (strSnapshot,))
|
---|
396 |
|
---|
397 | aoMediumAttachments = oMachine.getMediumAttachmentsOfController(sController)
|
---|
398 | if fRc is True:
|
---|
399 | fRc = self.moveVMToLocation(sNewLoc, oSession.o.machine) and fRc
|
---|
400 |
|
---|
401 | fRc = fRc and oSession.saveSettings()
|
---|
402 | if fRc is False:
|
---|
403 | reporter.log('Couldn\'t save machine settings after 3d scenario')
|
---|
404 |
|
---|
405 | ############# 4 case. ##########################################################################################
|
---|
406 | # There are one or more save state files in the snapshots folder
|
---|
407 | # and some files in the logs folder.
|
---|
408 | # Here we run VM, next stop it in the "save" state.
|
---|
409 | # And next move VM
|
---|
410 |
|
---|
411 | sOldLoc = sNewLoc + os.sep + oMachine.name + os.sep
|
---|
412 | sNewLoc = os.path.join(sOrigLoc, 'moveFolder_4th_scenario')
|
---|
413 | os.mkdir(sNewLoc, 0o775)
|
---|
414 |
|
---|
415 | #Close Session object because after starting VM we get new instance of session
|
---|
416 | fRc = oSession.close() and fRc
|
---|
417 | if fRc is False:
|
---|
418 | reporter.log('Couldn\'t close machine session')
|
---|
419 |
|
---|
420 | del oSession
|
---|
421 |
|
---|
422 | self.__testScenario_4(oMachine, sNewLoc)
|
---|
423 |
|
---|
424 | ############## 5 case. ##########################################################################################
|
---|
425 | #There is an ISO image (.iso) attached to the VM.
|
---|
426 | #Prerequisites - there is IDE Controller and there are no any images attached to it.
|
---|
427 |
|
---|
428 | sOldLoc = sNewLoc + os.sep + oMachine.name + os.sep
|
---|
429 | sNewLoc = os.path.join(sOrigLoc, 'moveFolder_5th_scenario')
|
---|
430 | os.mkdir(sNewLoc, 0o775)
|
---|
431 | self.__testScenario_5(oMachine, sNewLoc, sOldLoc)
|
---|
432 |
|
---|
433 | ############# 6 case. ##########################################################################################
|
---|
434 | #There is a floppy image (.img) attached to the VM.
|
---|
435 | #Prerequisites - there is Floppy Controller and there are no any images attached to it.
|
---|
436 |
|
---|
437 | sOldLoc = sNewLoc + os.sep + oMachine.name + os.sep
|
---|
438 | sNewLoc = os.path.join(sOrigLoc, 'moveFolder_6th_scenario')
|
---|
439 | os.mkdir(sNewLoc, 0o775)
|
---|
440 | self.__testScenario_6(oMachine, sNewLoc, sOldLoc)
|
---|
441 |
|
---|
442 | ############# 7 case. ##########################################################################################
|
---|
443 | # # There are shareable disk and immutable disk attached to the VM.
|
---|
444 | # #
|
---|
445 | #
|
---|
446 | # fRc = fRc and oSession.saveSettings()
|
---|
447 | # if fRc is False:
|
---|
448 | # reporter.log('Couldn\'t save machine settings')
|
---|
449 | #
|
---|
450 |
|
---|
451 | assert fRc is True
|
---|
452 | except:
|
---|
453 | reporter.errorXcpt()
|
---|
454 |
|
---|
455 | return reporter.testDone()[1] == 0
|
---|
456 |
|
---|
457 |
|
---|
458 | if __name__ == '__main__':
|
---|
459 | sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
---|
460 | from tdApi1 import tdApi1
|
---|
461 | sys.exit(tdApi1([SubTstDrvMoveVM1]).main(sys.argv))
|
---|
462 |
|
---|