Merge lp:~pawciobiel/testdrive/1297377-fix-kvm-img-not-found-report-error into lp:testdrive

Proposed by pawciobiel
Status: Merged
Merged at revision: 451
Proposed branch: lp:~pawciobiel/testdrive/1297377-fix-kvm-img-not-found-report-error
Merge into: lp:testdrive
Diff against target: 345 lines (+108/-56)
7 files modified
bin/testdrive (+14/-9)
bin/testdrive-gtk (+18/-13)
testdrive/virt/base.py (+16/-0)
testdrive/virt/kvm.py (+24/-10)
testdrive/virt/parallels.py (+12/-10)
testdrive/virt/virtualbox.py (+23/-13)
testdrivegtk/PreferencesTestdrivegtkDialog.py (+1/-1)
To merge this branch: bzr merge lp:~pawciobiel/testdrive/1297377-fix-kvm-img-not-found-report-error
Reviewer Review Type Date Requested Status
Andres Rodriguez Approve
Review via email: mp+234571@code.launchpad.net

Description of the change

merge fix for lp:1297377

* fix virt.kvm so it checks if qemu-img or kvm-img is installed
* check if qemu-utils is installed when user selected kvm
* tide up virt a bit so testdrive-gtk can notify user about errors

To post a comment you must log in.
Revision history for this message
Andres Rodriguez (andreserl) wrote :

lgtm!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'bin/testdrive'
2--- bin/testdrive 2013-10-24 02:11:50 +0000
3+++ bin/testdrive 2014-09-13 13:13:23 +0000
4@@ -74,8 +74,12 @@
5 logger.error(_("\nERROR: Invalid input\n"))
6 continue
7 if choice == i:
8- url = raw_input(_("\nEnter an ISO URL to testdrive: "))
9- break
10+ try:
11+ url = raw_input(_("\nEnter an ISO URL to testdrive: "))
12+ break
13+ except KeyboardInterrupt:
14+ print("\n")
15+ exit(0)
16 elif choice in range(1, i):
17 url = menu[choice-1]["url"]
18 td.ISO_PATH_HEADER = menu[choice-1]["cat"]
19@@ -85,7 +89,7 @@
20 return(url)
21
22 def error(str):
23- logger.error(_("\n%s\n") % str)
24+ logger.error("\n%s\n" % str)
25 sys.exit(1)
26
27 def is_iso(file):
28@@ -401,14 +405,15 @@
29 logger.info(_("Validating Virtualization Method...."))
30 try:
31 virt.validate_virt()
32- except:
33- error(_("Unable to validate Virtualization Method [%s]") % td.VIRT)
34+ except Exception as exc:
35+ error(_("Unable to validate Virtualization Method [%s] (%s)") % \
36+ (td.VIRT, exc))
37
38 logger.info(_("Setting up Virtual Machine..."))
39 try:
40 virt.setup_virt()
41- except:
42- error(_("Unable to setup Virtual Machine"))
43+ except Exception as exc:
44+ error(_("Unable to setup Virtual Machine (%s)") % exc)
45
46 logger.info(_("Launching Virtual Machine..."))
47 try:
48@@ -417,8 +422,8 @@
49 if td.VIRT == "kvm":
50 logging.debug("%s:%s" % (time.strftime("%Y-%m-%d_%H:%M:%S"), cmd))
51 run_vm(cmd, td, cloud_curses)
52- except:
53- error(_("Unable to launch Virtual Machine"))
54+ except Exception as exc:
55+ error(_("Unable to launch Virtual Machine (%s)") % (exc))
56
57 rm_disk = td.delete_image()
58 if rm_disk:
59
60=== modified file 'bin/testdrive-gtk'
61--- bin/testdrive-gtk 2013-11-17 08:19:27 +0000
62+++ bin/testdrive-gtk 2014-09-13 13:13:23 +0000
63@@ -739,10 +739,9 @@
64 if self.td.VIRT == "virtualbox":
65 logging.info(_("Using VirtualBox for virtual machine hosting..."))
66 virt = virtualbox.VBox(self.td)
67- if self.td.VIRT == "paralels":
68+ if self.td.VIRT == "parallels":
69 logging.info(_("Using Parallels Desktop for virtual machine hosting..."))
70 virt = parallels.Parallels(self.td)
71-
72 # Passing VIRT object to ISOLIST
73 ISOLIST[vm_id]["virt"] = virt
74 ISOLIST[vm_id]["virt_type"] = self.td.VIRT
75@@ -924,20 +923,24 @@
76 self.p = None
77
78 def prepare_to_launch_vm(self):
79- ###################################################################
80- ######## Prepare the VM to launch and return launch command #######
81- ###################################################################
82- # TODO TODO TODO - Re-add validation
83- self.ovirt.validate_virt()
84- self.ovirt.setup_virt()
85- return self.ovirt.launch_virt()
86-
87- def run(self):
88- if self.virt == "virtualbox":
89- text = _(" Configuring Virtual Machine...")
90+ """Prepare the VM to launch and return launch command"""
91+ try:
92+ self.ovirt.validate_virt()
93+ self.ovirt.setup_virt()
94+ return self.ovirt.launch_virt()
95+ except Exception as exc:
96+ text = _("Error preparing virtualization: %s") % (exc)
97 self.status_label.set_markup("<b><i>%s</i></b>" % text)
98 self.status_label.show()
99+ logging.error("%s", exc, exc_info=1)
100+
101+ def run(self):
102+ text = _(" Configuring Virtual Machine...")
103+ self.status_label.set_markup("<b><i>%s</i></b>" % text)
104+ self.status_label.show()
105 command = self.prepare_to_launch_vm()
106+ if not command: return
107+ logger.info("Running VM command %s", command)
108 cmd = command.split()
109 self.p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
110 text = _(" Running Virtual Machine...")
111@@ -948,6 +951,7 @@
112 while not self.stopthread.isSet():
113 if self.p.poll() != None:
114 self.status_label.set_markup("<i>%s</i>" % self.previous_text)
115+ self.status_label.show()
116 self.p = None
117 break
118 time.sleep(0.1)
119@@ -969,6 +973,7 @@
120 break
121 time.sleep(2)
122
123+
124 def stop(self):
125 try:
126 if self.p.poll() is None:
127
128=== added file 'testdrive/virt/base.py'
129--- testdrive/virt/base.py 1970-01-01 00:00:00 +0000
130+++ testdrive/virt/base.py 2014-09-13 13:13:23 +0000
131@@ -0,0 +1,16 @@
132+
133+import os
134+
135+
136+class VirtException(Exception):
137+ pass
138+
139+
140+class VirtBase(object):
141+
142+ def run(self, cmd):
143+ return(os.system(cmd))
144+
145+ def run_or_die(self, cmd):
146+ if self.run(cmd) != 0:
147+ raise VirtException("Failed executing command: `%s`" % cmd)
148
149=== modified file 'testdrive/virt/kvm.py'
150--- testdrive/virt/kvm.py 2013-05-20 17:12:31 +0000
151+++ testdrive/virt/kvm.py 2014-09-13 13:13:23 +0000
152@@ -19,10 +19,15 @@
153 # You should have received a copy of the GNU General Public License
154 # along with this program. If not, see <http://www.gnu.org/licenses/>.
155
156+import sys
157 import commands, os, uuid, logging
158
159+from .base import VirtException
160+
161+
162 logger = logging.getLogger("testdrive.virt.kvm")
163
164+
165 class KVM:
166
167 def __init__(self, td):
168@@ -45,19 +50,35 @@
169 def validate_virt(self):
170 (status, output) = commands.getstatusoutput("kvm-ok")
171 if status != 0:
172- logger.info(output)
173+ logger.warn("kvm-ok failed: %s", output)
174+ (status, output) = commands.getstatusoutput("dpkg -l qemu-utils")
175+ if status != 0:
176+ raise VirtException("Package qemu-utils is not installed.")
177+
178+ def get_kvm_img_path(self):
179+ """Get kvm-img or qemu-img path and return it.
180+
181+ Fall back to deprecated kvm-img. It may appear to be better
182+ to call just `which qemu-img kvm-img` but this way is cleaner.
183+ """
184+ for cmd in ['qemu-img', 'kvm-img']:
185+ status, output = commands.getstatusoutput('which %s' % (cmd))
186+ if status == 0 and output:
187+ return output.strip()
188+ raise VirtException("Can not find qemu-img nor kvm-img!")
189
190 # Code to setup virtual machine
191 def setup_virt(self):
192+ kvm_img = self.get_kvm_img_path()
193 if self.p == 'cloud-daily' or self.p == 'cloud-releases':
194 #path = "%s/%s" % (self.CACHE_ISO, self.PATH_TO_ISO.split(".tar.gz")[0].split("_")[-1])
195 path = "%s/%s" % (self.CACHE_ISO, os.path.basename(self.PATH_TO_ISO).split(".tar.gz")[0])
196 self.ORIG_DISK = "%s.img" % path
197 self.FLOPPY_FILE = "%s-floppy" % path
198- self.run_or_die("kvm-img create -f qcow2 -b %s %s" % (self.ORIG_DISK, self.DISK_FILE))
199+ self.run_or_die("%s create -f qcow2 -b %s %s" % (kvm_img, self.ORIG_DISK, self.DISK_FILE))
200 elif not os.path.exists(self.DISK_FILE) or self.is_disk_empty():
201 logger.info("Creating disk image [%s]..." % self.DISK_FILE)
202- self.run_or_die("kvm-img create -f qcow2 %s %s" % (self.DISK_FILE, self.DISK_SIZE))
203+ self.run_or_die("%s create -f qcow2 %s %s" % (kvm_img, self.DISK_FILE, self.DISK_SIZE))
204
205 # Code launch virtual machine
206 def launch_virt(self):
207@@ -68,10 +89,3 @@
208 else:
209 cmd = "qemu-system-x86_64 -uuid %s -m %s -smp %s -cdrom %s -drive file=%s,if=virtio,cache=writeback,index=0 %s" % (UUID, self.MEM, self.SMP, self.PATH_TO_ISO, self.DISK_FILE, self.KVM_ARGS)
210 return cmd
211-
212- def run(self, cmd):
213- return(os.system(cmd))
214-
215- def run_or_die(self, cmd):
216- if self.run(cmd) != 0:
217- logger.error("Command failed\n `%s`" % cmd)
218
219=== modified file 'testdrive/virt/parallels.py'
220--- testdrive/virt/parallels.py 2012-04-21 02:05:42 +0000
221+++ testdrive/virt/parallels.py 2014-09-13 13:13:23 +0000
222@@ -19,9 +19,16 @@
223 # You should have received a copy of the GNU General Public License
224 # along with this program. If not, see <http://www.gnu.org/licenses/>.
225
226+import logging
227 import commands, os, time
228
229-class Parallels:
230+from .base import VirtBase, VirtException
231+
232+
233+logger = logging.getLogger(__name__)
234+
235+
236+class Parallels(VirtBase):
237
238 def __init__(self, td):
239 self.HOME = td.HOME
240@@ -32,8 +39,11 @@
241 self.DISK_SIZE = td.DISK_SIZE
242 self.VBOX_NAME = td.VBOX_NAME
243
244- # Code to validate if virtualization is installed/supported
245 def validate_virt(self):
246+ """validate if virtualization is installed/supported"""
247+ if commands.getstatusoutput("which prlctl")[0] != 0:
248+ raise VirtException("prlctl not found")
249+
250 if commands.getstatusoutput("prlctl list %s | grep -qsv \"UUID\"" % self.VBOX_NAME)[0] == 0:
251 self.run_or_die("prlctl delete %s" % self.VBOX_NAME)
252
253@@ -55,11 +65,3 @@
254 # Loop as long as this VM is running
255 #while commands.getstatusoutput("prlctl list %s | grep -qs stopped" % self.td.VBOX_NAME)[0] != 0:
256 # time.sleep(2)
257-
258- def run(self, cmd):
259- return(os.system(cmd))
260-
261- def run_or_die(self, cmd):
262- if self.run(cmd) != 0:
263- #error("Command failed\n `%s`" % cmd)
264- print "Command failed\n `%s`" % cmd
265
266=== modified file 'testdrive/virt/virtualbox.py'
267--- testdrive/virt/virtualbox.py 2013-10-28 19:55:24 +0000
268+++ testdrive/virt/virtualbox.py 2014-09-13 13:13:23 +0000
269@@ -21,9 +21,13 @@
270
271 import commands, os, time, logging
272
273+from .base import VirtException, VirtBase
274+
275+
276 logger = logging.getLogger("testdrive.virt.vbox")
277
278-class VBox:
279+
280+class VBox(VirtBase):
281
282 def __init__(self, td):
283 self.vboxversion = None
284@@ -42,19 +46,32 @@
285 return True
286 return False
287
288+ def get_vboxversion(self):
289+ status, verstr = commands.getstatusoutput("VBoxManage --version")
290+ if status != 0:
291+ raise VirtException("No VirtualBox found")
292+ try:
293+ self.vboxversion = (int(verstr.split(".")[0]),
294+ int(verstr.split(".")[1]))
295+ except (IndexError, ValueError) as exc:
296+ raise VirtException("Can not extract version "
297+ "[VBoxManage --version]")
298+
299+
300 # Code to validate if virtualization is installed/supported
301 def validate_virt(self):
302 # Determine which version of VirtualBox we have installed. What is returned is
303 # typically a string such as '4.1.0r55467', lets assume that the command line
304 # is consistent within 4.x.x versions extract this part of the
305 # version string for comparison later
306- self.vboxversion = commands.getoutput("VBoxManage --version")
307- self.vboxversion = ( int(self.vboxversion.split(".")[0]), int(self.vboxversion.split(".")[1]) )
308- if self.vboxversion == (4,0) or self.vboxversion == (4,1) or self.vboxversion == (4,2) or self.vboxversion == (4,3):
309+ self.vboxversion = self.get_vboxversion()
310+ supported_versions = ((4,0), (4,1), (4,2), (4,3))
311+ if self.vboxversion in supported_versions:
312 logger.info("VirtualBox %s.%s detected." % self.vboxversion)
313 else:
314- logger.error("ERROR: Unsupported version (%s.%s) of VirtualBox; please install v4.0 or newer." % self.vboxversion)
315- exit(0)
316+ err_text = ("Unsupported version (%s.%s) of VirtualBox; "
317+ "please install v4.0 or newer.") % self.vboxversion
318+ raise VirtException(err_text)
319
320 # Code to setup virtual machine
321 def setup_virt(self):
322@@ -104,10 +121,3 @@
323 # Loop as long as this VM is running
324 #while commands.getstatusoutput("VBoxManage list runningvms | grep -qs %s" % self.td.VBOX_NAME)[0] == 0:
325 # time.sleep(2)
326-
327- def run(self, cmd):
328- return(os.system(cmd))
329-
330- def run_or_die(self, cmd):
331- if self.run(cmd) != 0:
332- logger.error("Command failed\n `%s`" % cmd)
333
334=== modified file 'testdrivegtk/PreferencesTestdrivegtkDialog.py'
335--- testdrivegtk/PreferencesTestdrivegtkDialog.py 2013-10-24 14:10:11 +0000
336+++ testdrivegtk/PreferencesTestdrivegtkDialog.py 2014-09-13 13:13:23 +0000
337@@ -481,7 +481,7 @@
338 path = "%s/%s" % (cache_path, file)
339 os.unlink(path)
340 except:
341- on_error_dlg(_("Unable to clean up files from [%s]") % cache_path)
342+ self.on_error_dlg(_("Unable to clean up files from [%s]") % cache_path)
343
344 def on_select_iso_image_repo(self, widget):
345 ##################################################################

Subscribers

People subscribed via source and target branches