blob: a860437f6ea41e92d8f069b8bdc6e3a61d45e7f6 [file] [log] [blame]
lmr6f669ce2009-05-31 19:02:42 +00001#!/usr/bin/python
lmr6f669ce2009-05-31 19:02:42 +00002"""
3Utility classes and functions to handle Virtual Machine creation using qemu.
4
5@copyright: 2008-2009 Red Hat Inc.
6"""
7
Eric Lie0493a42010-11-15 13:05:43 -08008import time, socket, os, logging, fcntl, re, commands, shelve, glob
lmrcbc86ef2010-07-07 20:50:08 +00009import kvm_utils, kvm_subprocess, kvm_monitor, rss_file_transfer
lmr47a853b2010-02-04 13:56:48 +000010from autotest_lib.client.common_lib import error
lmrd60882f2010-02-04 03:26:36 +000011from autotest_lib.client.bin import utils
lmrb635b862009-09-10 14:53:21 +000012
lmr6f669ce2009-05-31 19:02:42 +000013
lmr90b9fd52009-08-17 20:48:18 +000014def get_image_filename(params, root_dir):
lmr6f669ce2009-05-31 19:02:42 +000015 """
lmr90b9fd52009-08-17 20:48:18 +000016 Generate an image path from params and root_dir.
lmr6f669ce2009-05-31 19:02:42 +000017
18 @param params: Dictionary containing the test parameters.
lmr90b9fd52009-08-17 20:48:18 +000019 @param root_dir: Base directory for relative filenames.
lmr6f669ce2009-05-31 19:02:42 +000020
21 @note: params should contain:
22 image_name -- the name of the image file, without extension
23 image_format -- the format of the image (qcow2, raw etc)
24 """
25 image_name = params.get("image_name", "image")
26 image_format = params.get("image_format", "qcow2")
27 image_filename = "%s.%s" % (image_name, image_format)
lmr90b9fd52009-08-17 20:48:18 +000028 image_filename = kvm_utils.get_path(root_dir, image_filename)
lmr6f669ce2009-05-31 19:02:42 +000029 return image_filename
30
31
lmr52800ba2009-08-17 20:49:58 +000032def create_image(params, root_dir):
lmr6f669ce2009-05-31 19:02:42 +000033 """
34 Create an image using qemu_image.
35
36 @param params: Dictionary containing the test parameters.
lmr90b9fd52009-08-17 20:48:18 +000037 @param root_dir: Base directory for relative filenames.
lmr6f669ce2009-05-31 19:02:42 +000038
39 @note: params should contain:
40 image_name -- the name of the image file, without extension
41 image_format -- the format of the image (qcow2, raw etc)
42 image_size -- the requested size of the image (a string
43 qemu-img can understand, such as '10G')
44 """
lmr52800ba2009-08-17 20:49:58 +000045 qemu_img_cmd = kvm_utils.get_path(root_dir, params.get("qemu_img_binary",
46 "qemu-img"))
lmr6f669ce2009-05-31 19:02:42 +000047 qemu_img_cmd += " create"
48
49 format = params.get("image_format", "qcow2")
50 qemu_img_cmd += " -f %s" % format
51
lmr90b9fd52009-08-17 20:48:18 +000052 image_filename = get_image_filename(params, root_dir)
lmr6f669ce2009-05-31 19:02:42 +000053 qemu_img_cmd += " %s" % image_filename
54
55 size = params.get("image_size", "10G")
56 qemu_img_cmd += " %s" % size
57
lmr47a853b2010-02-04 13:56:48 +000058 try:
59 utils.system(qemu_img_cmd)
60 except error.CmdError, e:
61 logging.error("Could not create image; qemu-img command failed:\n%s",
62 str(e))
63 return None
lmr6f669ce2009-05-31 19:02:42 +000064
lmr6f669ce2009-05-31 19:02:42 +000065 if not os.path.exists(image_filename):
lmra4967622009-07-23 01:36:32 +000066 logging.error("Image could not be created for some reason; "
67 "qemu-img command:\n%s" % qemu_img_cmd)
lmr6f669ce2009-05-31 19:02:42 +000068 return None
69
70 logging.info("Image created in %s" % image_filename)
71 return image_filename
72
73
lmr90b9fd52009-08-17 20:48:18 +000074def remove_image(params, root_dir):
lmr6f669ce2009-05-31 19:02:42 +000075 """
76 Remove an image file.
77
78 @param params: A dict
lmr90b9fd52009-08-17 20:48:18 +000079 @param root_dir: Base directory for relative filenames.
lmr6f669ce2009-05-31 19:02:42 +000080
81 @note: params should contain:
82 image_name -- the name of the image file, without extension
83 image_format -- the format of the image (qcow2, raw etc)
84 """
lmr90b9fd52009-08-17 20:48:18 +000085 image_filename = get_image_filename(params, root_dir)
lmr6f669ce2009-05-31 19:02:42 +000086 logging.debug("Removing image file %s..." % image_filename)
87 if os.path.exists(image_filename):
88 os.unlink(image_filename)
89 else:
90 logging.debug("Image file %s not found")
91
92
93class VM:
94 """
95 This class handles all basic VM operations.
96 """
97
lmr52800ba2009-08-17 20:49:58 +000098 def __init__(self, name, params, root_dir, address_cache):
lmr6f669ce2009-05-31 19:02:42 +000099 """
100 Initialize the object and set a few attributes.
101
102 @param name: The name of the object
103 @param params: A dict containing VM params
104 (see method make_qemu_command for a full description)
lmr90b9fd52009-08-17 20:48:18 +0000105 @param root_dir: Base directory for relative filenames
lmree90dd92009-08-13 04:13:39 +0000106 @param address_cache: A dict that maps MAC addresses to IP addresses
lmr6f669ce2009-05-31 19:02:42 +0000107 """
lmra4967622009-07-23 01:36:32 +0000108 self.process = None
lmraa380a22010-06-22 02:05:29 +0000109 self.serial_console = None
lmr953ffba2009-07-27 13:20:10 +0000110 self.redirs = {}
111 self.vnc_port = 5900
lmr9e964a02010-06-18 03:46:21 +0000112 self.monitors = []
113 self.pci_assignable = None
Eric Lie0493a42010-11-15 13:05:43 -0800114 self.netdev_id = []
115 self.uuid = None
lmr6f669ce2009-05-31 19:02:42 +0000116
117 self.name = name
118 self.params = params
lmr90b9fd52009-08-17 20:48:18 +0000119 self.root_dir = root_dir
lmree90dd92009-08-13 04:13:39 +0000120 self.address_cache = address_cache
lmr6f669ce2009-05-31 19:02:42 +0000121
lmr9e964a02010-06-18 03:46:21 +0000122 # Find a unique identifier for this VM
lmr8b134f92009-06-08 14:47:31 +0000123 while True:
lmrd16a67d2009-06-10 19:52:59 +0000124 self.instance = (time.strftime("%Y%m%d-%H%M%S-") +
125 kvm_utils.generate_random_string(4))
lmr9e964a02010-06-18 03:46:21 +0000126 if not glob.glob("/tmp/*%s" % self.instance):
lmr8b134f92009-06-08 14:47:31 +0000127 break
128
129
lmr52800ba2009-08-17 20:49:58 +0000130 def clone(self, name=None, params=None, root_dir=None, address_cache=None):
lmr2c241172009-06-08 15:11:29 +0000131 """
132 Return a clone of the VM object with optionally modified parameters.
133 The clone is initially not alive and needs to be started using create().
134 Any parameters not passed to this function are copied from the source
135 VM.
136
137 @param name: Optional new VM name
138 @param params: Optional new VM creation parameters
lmr90b9fd52009-08-17 20:48:18 +0000139 @param root_dir: Optional new base directory for relative filenames
lmree90dd92009-08-13 04:13:39 +0000140 @param address_cache: A dict that maps MAC addresses to IP addresses
lmr2c241172009-06-08 15:11:29 +0000141 """
lmre45a1f22009-11-10 16:35:08 +0000142 if name is None:
lmr2c241172009-06-08 15:11:29 +0000143 name = self.name
lmre45a1f22009-11-10 16:35:08 +0000144 if params is None:
lmr2c241172009-06-08 15:11:29 +0000145 params = self.params.copy()
lmre45a1f22009-11-10 16:35:08 +0000146 if root_dir is None:
lmr90b9fd52009-08-17 20:48:18 +0000147 root_dir = self.root_dir
lmre45a1f22009-11-10 16:35:08 +0000148 if address_cache is None:
lmree90dd92009-08-13 04:13:39 +0000149 address_cache = self.address_cache
lmr52800ba2009-08-17 20:49:58 +0000150 return VM(name, params, root_dir, address_cache)
lmr2c241172009-06-08 15:11:29 +0000151
152
lmr52800ba2009-08-17 20:49:58 +0000153 def make_qemu_command(self, name=None, params=None, root_dir=None):
lmr6f669ce2009-05-31 19:02:42 +0000154 """
155 Generate a qemu command line. All parameters are optional. If a
156 parameter is not supplied, the corresponding value stored in the
157 class attributes is used.
158
lmr6f669ce2009-05-31 19:02:42 +0000159 @param name: The name of the object
160 @param params: A dict containing VM params
lmr90b9fd52009-08-17 20:48:18 +0000161 @param root_dir: Base directory for relative filenames
lmr6f669ce2009-05-31 19:02:42 +0000162
163 @note: The params dict should contain:
164 mem -- memory size in MBs
165 cdrom -- ISO filename to use with the qemu -cdrom parameter
lmr6f669ce2009-05-31 19:02:42 +0000166 extra_params -- a string to append to the qemu command
lmr912c74b2009-08-17 20:43:27 +0000167 shell_port -- port of the remote shell daemon on the guest
168 (SSH, Telnet or the home-made Remote Shell Server)
169 shell_client -- client program to use for connecting to the
170 remote shell daemon on the guest (ssh, telnet or nc)
lmreeff0eb2009-06-10 19:19:15 +0000171 x11_display -- if specified, the DISPLAY environment variable
172 will be be set to this value for the qemu process (useful for
173 SDL rendering)
lmr6f669ce2009-05-31 19:02:42 +0000174 images -- a list of image object names, separated by spaces
175 nics -- a list of NIC object names, separated by spaces
176
177 For each image in images:
178 drive_format -- string to pass as 'if' parameter for this
179 image (e.g. ide, scsi)
180 image_snapshot -- if yes, pass 'snapshot=on' to qemu for
181 this image
182 image_boot -- if yes, pass 'boot=on' to qemu for this image
183 In addition, all parameters required by get_image_filename.
184
185 For each NIC in nics:
186 nic_model -- string to pass as 'model' parameter for this
187 NIC (e.g. e1000)
188 """
lmr48abd7d2010-05-26 13:48:04 +0000189 # Helper function for command line option wrappers
190 def has_option(help, option):
191 return bool(re.search(r"^-%s(\s|$)" % option, help, re.MULTILINE))
192
193 # Wrappers for all supported qemu command line parameters.
194 # This is meant to allow support for multiple qemu versions.
195 # Each of these functions receives the output of 'qemu -help' as a
196 # parameter, and should add the requested command line option
197 # accordingly.
198
199 def add_name(help, name):
200 return " -name '%s'" % name
201
lmr9e964a02010-06-18 03:46:21 +0000202 def add_human_monitor(help, filename):
lmr09a78162010-06-14 16:29:23 +0000203 return " -monitor unix:'%s',server,nowait" % filename
lmr48abd7d2010-05-26 13:48:04 +0000204
lmr9e964a02010-06-18 03:46:21 +0000205 def add_qmp_monitor(help, filename):
206 return " -qmp unix:'%s',server,nowait" % filename
207
lmr2b06f332010-06-22 02:03:41 +0000208 def add_serial(help, filename):
209 return " -serial unix:'%s',server,nowait" % filename
210
lmr48abd7d2010-05-26 13:48:04 +0000211 def add_mem(help, mem):
212 return " -m %s" % mem
213
214 def add_smp(help, smp):
215 return " -smp %s" % smp
216
lmraf709702010-07-20 00:56:33 +0000217 def add_cdrom(help, filename, index=None):
lmr48abd7d2010-05-26 13:48:04 +0000218 if has_option(help, "drive"):
lmraf709702010-07-20 00:56:33 +0000219 cmd = " -drive file='%s',media=cdrom" % filename
220 if index is not None: cmd += ",index=%s" % index
221 return cmd
lmr48abd7d2010-05-26 13:48:04 +0000222 else:
lmr09a78162010-06-14 16:29:23 +0000223 return " -cdrom '%s'" % filename
lmr48abd7d2010-05-26 13:48:04 +0000224
lmraf709702010-07-20 00:56:33 +0000225 def add_drive(help, filename, index=None, format=None, cache=None,
226 werror=None, serial=None, snapshot=False, boot=False):
lmr09a78162010-06-14 16:29:23 +0000227 cmd = " -drive file='%s'" % filename
lmraf709702010-07-20 00:56:33 +0000228 if index is not None: cmd += ",index=%s" % index
lmr48abd7d2010-05-26 13:48:04 +0000229 if format: cmd += ",if=%s" % format
230 if cache: cmd += ",cache=%s" % cache
231 if werror: cmd += ",werror=%s" % werror
lmr09a78162010-06-14 16:29:23 +0000232 if serial: cmd += ",serial='%s'" % serial
lmr48abd7d2010-05-26 13:48:04 +0000233 if snapshot: cmd += ",snapshot=on"
234 if boot: cmd += ",boot=on"
235 return cmd
236
Eric Lie0493a42010-11-15 13:05:43 -0800237 def add_nic(help, vlan, model=None, mac=None, netdev_id=None,
238 nic_extra_params=None):
239 if has_option(help, "device"):
240 if model == "virtio":
241 model="virtio-net-pci"
242 if not model:
243 model= "rtl8139"
244 cmd = " -device %s" % model
245 if mac:
246 cmd += ",mac=%s" % mac
247 if has_option(help, "netdev"):
248 cmd += ",netdev=%s" % netdev_id
249 else:
250 cmd += "vlan=%d," % vlan
251 if nic_extra_params:
252 cmd += ",%s" % nic_extra_params
Eric Li6f27d4f2010-09-29 10:55:17 -0700253 else:
Eric Lie0493a42010-11-15 13:05:43 -0800254 if has_option(help, "netdev"):
255 cmd = " -net nic,netdev=%s" % netdev_id
256 else:
257 cmd = " -net nic,vlan=%d" % vlan
258 if model:
259 cmd += ",model=%s" % model
260 if mac:
261 cmd += ",macaddr='%s'" % mac
lmr48abd7d2010-05-26 13:48:04 +0000262 return cmd
263
264 def add_net(help, vlan, mode, ifname=None, script=None,
lmr6976faa2010-07-09 21:11:06 +0000265 downscript=None, tftp=None, bootfile=None, hostfwd=[],
Eric Lie0493a42010-11-15 13:05:43 -0800266 netdev_id=None, vhost=False):
lmrb1cad1e2010-06-17 17:36:09 +0000267 if has_option(help, "netdev"):
268 cmd = " -netdev %s,id=%s" % (mode, netdev_id)
Eric Lie0493a42010-11-15 13:05:43 -0800269 if vhost:
270 cmd +=",vhost=on"
lmrb1cad1e2010-06-17 17:36:09 +0000271 else:
272 cmd = " -net %s,vlan=%d" % (mode, vlan)
lmr48abd7d2010-05-26 13:48:04 +0000273 if mode == "tap":
lmr09a78162010-06-14 16:29:23 +0000274 if ifname: cmd += ",ifname='%s'" % ifname
275 if script: cmd += ",script='%s'" % script
276 cmd += ",downscript='%s'" % (downscript or "no")
lmr6976faa2010-07-09 21:11:06 +0000277 elif mode == "user":
278 if tftp and "[,tftp=" in help:
279 cmd += ",tftp='%s'" % tftp
280 if bootfile and "[,bootfile=" in help:
281 cmd += ",bootfile='%s'" % bootfile
282 if "[,hostfwd=" in help:
283 for host_port, guest_port in hostfwd:
284 cmd += ",hostfwd=tcp::%s-:%s" % (host_port, guest_port)
lmr48abd7d2010-05-26 13:48:04 +0000285 return cmd
286
287 def add_floppy(help, filename):
lmr09a78162010-06-14 16:29:23 +0000288 return " -fda '%s'" % filename
lmr48abd7d2010-05-26 13:48:04 +0000289
290 def add_tftp(help, filename):
lmr6976faa2010-07-09 21:11:06 +0000291 # If the new syntax is supported, don't add -tftp
292 if "[,tftp=" in help:
293 return ""
294 else:
295 return " -tftp '%s'" % filename
296
297 def add_bootp(help, filename):
298 # If the new syntax is supported, don't add -bootp
299 if "[,bootfile=" in help:
300 return ""
301 else:
302 return " -bootp '%s'" % filename
lmr48abd7d2010-05-26 13:48:04 +0000303
304 def add_tcp_redir(help, host_port, guest_port):
lmr6976faa2010-07-09 21:11:06 +0000305 # If the new syntax is supported, don't add -redir
306 if "[,hostfwd=" in help:
307 return ""
308 else:
309 return " -redir tcp:%s::%s" % (host_port, guest_port)
lmr48abd7d2010-05-26 13:48:04 +0000310
311 def add_vnc(help, vnc_port):
312 return " -vnc :%d" % (vnc_port - 5900)
313
314 def add_sdl(help):
315 if has_option(help, "sdl"):
316 return " -sdl"
317 else:
318 return ""
319
320 def add_nographic(help):
321 return " -nographic"
322
323 def add_uuid(help, uuid):
lmr09a78162010-06-14 16:29:23 +0000324 return " -uuid '%s'" % uuid
lmr48abd7d2010-05-26 13:48:04 +0000325
326 def add_pcidevice(help, host):
lmr09a78162010-06-14 16:29:23 +0000327 return " -pcidevice host='%s'" % host
lmr48abd7d2010-05-26 13:48:04 +0000328
lmr41cb8fc2010-06-10 15:30:45 +0000329 def add_kernel(help, filename):
lmr09a78162010-06-14 16:29:23 +0000330 return " -kernel '%s'" % filename
lmr41cb8fc2010-06-10 15:30:45 +0000331
332 def add_initrd(help, filename):
lmr09a78162010-06-14 16:29:23 +0000333 return " -initrd '%s'" % filename
lmr41cb8fc2010-06-10 15:30:45 +0000334
lmre0474e32010-06-29 14:10:09 +0000335 def add_kernel_cmdline(help, cmdline):
336 return " -append %s" % cmdline
337
lmr71024552010-06-29 14:12:35 +0000338 def add_testdev(help, filename):
339 return (" -chardev file,id=testlog,path=%s"
340 " -device testdev,chardev=testlog" % filename)
341
lmrce5c9252010-06-30 17:41:00 +0000342 def add_no_hpet(help):
343 if has_option(help, "no-hpet"):
344 return " -no-hpet"
345 else:
346 return ""
347
lmr48abd7d2010-05-26 13:48:04 +0000348 # End of command line option wrappers
349
350 if name is None: name = self.name
351 if params is None: params = self.params
352 if root_dir is None: root_dir = self.root_dir
353
354 qemu_binary = kvm_utils.get_path(root_dir, params.get("qemu_binary",
355 "qemu"))
356 # Get the output of 'qemu -help' (log a message in case this call never
357 # returns or causes some other kind of trouble)
358 logging.debug("Getting output of 'qemu -help'")
359 help = commands.getoutput("%s -help" % qemu_binary)
lmr6f669ce2009-05-31 19:02:42 +0000360
lmreeff0eb2009-06-10 19:19:15 +0000361 # Start constructing the qemu command
362 qemu_cmd = ""
363 # Set the X11 display parameter if requested
364 if params.get("x11_display"):
365 qemu_cmd += "DISPLAY=%s " % params.get("x11_display")
366 # Add the qemu binary
lmr48abd7d2010-05-26 13:48:04 +0000367 qemu_cmd += qemu_binary
lmreeff0eb2009-06-10 19:19:15 +0000368 # Add the VM's name
lmr48abd7d2010-05-26 13:48:04 +0000369 qemu_cmd += add_name(help, name)
lmr9e964a02010-06-18 03:46:21 +0000370 # Add monitors
371 for monitor_name in kvm_utils.get_sub_dict_names(params, "monitors"):
372 monitor_params = kvm_utils.get_sub_dict(params, monitor_name)
373 monitor_filename = self.get_monitor_filename(monitor_name)
374 if monitor_params.get("monitor_type") == "qmp":
375 qemu_cmd += add_qmp_monitor(help, monitor_filename)
376 else:
377 qemu_cmd += add_human_monitor(help, monitor_filename)
lmr6f669ce2009-05-31 19:02:42 +0000378
lmr2b06f332010-06-22 02:03:41 +0000379 # Add serial console redirection
380 qemu_cmd += add_serial(help, self.get_serial_console_filename())
381
lmr6f669ce2009-05-31 19:02:42 +0000382 for image_name in kvm_utils.get_sub_dict_names(params, "images"):
383 image_params = kvm_utils.get_sub_dict(params, image_name)
lmr9d75ee32009-09-29 13:14:13 +0000384 if image_params.get("boot_drive") == "no":
385 continue
lmr48abd7d2010-05-26 13:48:04 +0000386 qemu_cmd += add_drive(help,
387 get_image_filename(image_params, root_dir),
lmraf709702010-07-20 00:56:33 +0000388 image_params.get("drive_index"),
lmr48abd7d2010-05-26 13:48:04 +0000389 image_params.get("drive_format"),
390 image_params.get("drive_cache"),
391 image_params.get("drive_werror"),
392 image_params.get("drive_serial"),
393 image_params.get("image_snapshot") == "yes",
394 image_params.get("image_boot") == "yes")
lmr6f669ce2009-05-31 19:02:42 +0000395
lmr6976faa2010-07-09 21:11:06 +0000396 redirs = []
397 for redir_name in kvm_utils.get_sub_dict_names(params, "redirs"):
398 redir_params = kvm_utils.get_sub_dict(params, redir_name)
399 guest_port = int(redir_params.get("guest_port"))
400 host_port = self.redirs.get(guest_port)
401 redirs += [(host_port, guest_port)]
402
lmr6f669ce2009-05-31 19:02:42 +0000403 vlan = 0
404 for nic_name in kvm_utils.get_sub_dict_names(params, "nics"):
405 nic_params = kvm_utils.get_sub_dict(params, nic_name)
lmrf4696342009-08-13 04:06:33 +0000406 # Handle the '-net nic' part
Eric Lie0493a42010-11-15 13:05:43 -0800407 mac = self.get_mac_address(vlan)
lmrb1cad1e2010-06-17 17:36:09 +0000408 qemu_cmd += add_nic(help, vlan, nic_params.get("nic_model"), mac,
Eric Lie0493a42010-11-15 13:05:43 -0800409 self.netdev_id[vlan],
410 nic_params.get("nic_extra_params"))
lmrf4696342009-08-13 04:06:33 +0000411 # Handle the '-net tap' or '-net user' part
lmre4eaa862010-06-01 19:15:14 +0000412 script = nic_params.get("nic_script")
413 downscript = nic_params.get("nic_downscript")
lmr6976faa2010-07-09 21:11:06 +0000414 tftp = nic_params.get("tftp")
lmr48abd7d2010-05-26 13:48:04 +0000415 if script:
416 script = kvm_utils.get_path(root_dir, script)
417 if downscript:
418 downscript = kvm_utils.get_path(root_dir, downscript)
lmr6976faa2010-07-09 21:11:06 +0000419 if tftp:
420 tftp = kvm_utils.get_path(root_dir, tftp)
lmr48abd7d2010-05-26 13:48:04 +0000421 qemu_cmd += add_net(help, vlan, nic_params.get("nic_mode", "user"),
Eric Lie0493a42010-11-15 13:05:43 -0800422 self.get_ifname(vlan),
lmr6976faa2010-07-09 21:11:06 +0000423 script, downscript, tftp,
424 nic_params.get("bootp"), redirs,
Eric Lie0493a42010-11-15 13:05:43 -0800425 self.netdev_id[vlan],
426 nic_params.get("vhost")=="yes")
lmrf4696342009-08-13 04:06:33 +0000427 # Proceed to next NIC
lmr6f669ce2009-05-31 19:02:42 +0000428 vlan += 1
429
430 mem = params.get("mem")
431 if mem:
lmr48abd7d2010-05-26 13:48:04 +0000432 qemu_cmd += add_mem(help, mem)
lmr6f669ce2009-05-31 19:02:42 +0000433
lmrc43bf372009-11-10 13:19:00 +0000434 smp = params.get("smp")
435 if smp:
lmrdb3fe612010-06-14 16:19:28 +0000436 qemu_cmd += add_smp(help, smp)
lmrc43bf372009-11-10 13:19:00 +0000437
lmrac5dce72010-07-20 00:58:25 +0000438 cdroms = kvm_utils.get_sub_dict_names(params, "cdroms")
439 for cdrom in cdroms:
440 cdrom_params = kvm_utils.get_sub_dict(params, cdrom)
441 iso = cdrom_params.get("cdrom")
442 if iso:
443 qemu_cmd += add_cdrom(help, kvm_utils.get_path(root_dir, iso),
444 cdrom_params.get("drive_index"))
lmr6f669ce2009-05-31 19:02:42 +0000445
lmrb0a9b762009-10-09 20:43:30 +0000446 # We may want to add {floppy_otps} parameter for -fda
lmr48abd7d2010-05-26 13:48:04 +0000447 # {fat:floppy:}/path/. However vvfat is not usually recommended.
lmrb0a9b762009-10-09 20:43:30 +0000448 floppy = params.get("floppy")
449 if floppy:
lmrf69f6b12009-11-10 16:33:44 +0000450 floppy = kvm_utils.get_path(root_dir, floppy)
lmr48abd7d2010-05-26 13:48:04 +0000451 qemu_cmd += add_floppy(help, floppy)
lmrb0a9b762009-10-09 20:43:30 +0000452
453 tftp = params.get("tftp")
lmr62fc2bb2010-07-08 23:45:11 +0000454 if tftp:
lmrf69f6b12009-11-10 16:33:44 +0000455 tftp = kvm_utils.get_path(root_dir, tftp)
lmr48abd7d2010-05-26 13:48:04 +0000456 qemu_cmd += add_tftp(help, tftp)
lmr6f669ce2009-05-31 19:02:42 +0000457
lmr6976faa2010-07-09 21:11:06 +0000458 bootp = params.get("bootp")
459 if bootp:
460 qemu_cmd += add_bootp(help, bootp)
461
lmr41cb8fc2010-06-10 15:30:45 +0000462 kernel = params.get("kernel")
463 if kernel:
464 kernel = kvm_utils.get_path(root_dir, kernel)
465 qemu_cmd += add_kernel(help, kernel)
466
lmre0474e32010-06-29 14:10:09 +0000467 kernel_cmdline = params.get("kernel_cmdline")
468 if kernel_cmdline:
469 qemu_cmd += add_kernel_cmdline(help, kernel_cmdline)
470
lmr41cb8fc2010-06-10 15:30:45 +0000471 initrd = params.get("initrd")
472 if initrd:
473 initrd = kvm_utils.get_path(root_dir, initrd)
474 qemu_cmd += add_initrd(help, initrd)
475
lmr6976faa2010-07-09 21:11:06 +0000476 for host_port, guest_port in redirs:
lmr48abd7d2010-05-26 13:48:04 +0000477 qemu_cmd += add_tcp_redir(help, host_port, guest_port)
lmr6f669ce2009-05-31 19:02:42 +0000478
479 if params.get("display") == "vnc":
lmr48abd7d2010-05-26 13:48:04 +0000480 qemu_cmd += add_vnc(help, self.vnc_port)
lmr6f669ce2009-05-31 19:02:42 +0000481 elif params.get("display") == "sdl":
lmr48abd7d2010-05-26 13:48:04 +0000482 qemu_cmd += add_sdl(help)
lmr6f669ce2009-05-31 19:02:42 +0000483 elif params.get("display") == "nographic":
lmr48abd7d2010-05-26 13:48:04 +0000484 qemu_cmd += add_nographic(help)
lmr6f669ce2009-05-31 19:02:42 +0000485
lmra2533222009-07-20 12:43:46 +0000486 if params.get("uuid") == "random":
lmr48abd7d2010-05-26 13:48:04 +0000487 qemu_cmd += add_uuid(help, self.uuid)
lmra2533222009-07-20 12:43:46 +0000488 elif params.get("uuid"):
lmr48abd7d2010-05-26 13:48:04 +0000489 qemu_cmd += add_uuid(help, params.get("uuid"))
lmra2533222009-07-20 12:43:46 +0000490
lmr71024552010-06-29 14:12:35 +0000491 if params.get("testdev") == "yes":
492 qemu_cmd += add_testdev(help, self.get_testlog_filename())
493
lmrce5c9252010-06-30 17:41:00 +0000494 if params.get("disable_hpet") == "yes":
495 qemu_cmd += add_no_hpet(help)
496
lmr31af3a12010-01-18 16:46:52 +0000497 # If the PCI assignment step went OK, add each one of the PCI assigned
498 # devices to the qemu command line.
499 if self.pci_assignable:
500 for pci_id in self.pa_pci_ids:
lmr48abd7d2010-05-26 13:48:04 +0000501 qemu_cmd += add_pcidevice(help, pci_id)
502
503 extra_params = params.get("extra_params")
504 if extra_params:
505 qemu_cmd += " %s" % extra_params
lmr31af3a12010-01-18 16:46:52 +0000506
lmr6f669ce2009-05-31 19:02:42 +0000507 return qemu_cmd
508
509
Eric Lie0493a42010-11-15 13:05:43 -0800510 def create(self, name=None, params=None, root_dir=None, timeout=5.0,
511 migration_mode=None, migration_exec_cmd=None, mac_source=None):
lmr6f669ce2009-05-31 19:02:42 +0000512 """
513 Start the VM by running a qemu command.
Eric Lie0493a42010-11-15 13:05:43 -0800514 All parameters are optional. If name, params or root_dir are not
515 supplied, the respective values stored as class attributes are used.
lmr6f669ce2009-05-31 19:02:42 +0000516
517 @param name: The name of the object
518 @param params: A dict containing VM params
lmr90b9fd52009-08-17 20:48:18 +0000519 @param root_dir: Base directory for relative filenames
Eric Lie0493a42010-11-15 13:05:43 -0800520 @param migration_mode: If supplied, start VM for incoming migration
521 using this protocol (either 'tcp', 'unix' or 'exec')
522 @param migration_exec_cmd: Command to embed in '-incoming "exec: ..."'
523 (e.g. 'gzip -c -d filename') if migration_mode is 'exec'
524 @param mac_source: A VM object from which to copy MAC addresses. If not
525 specified, new addresses will be generated.
lmr6f669ce2009-05-31 19:02:42 +0000526 """
lmr135b5e62009-06-10 19:22:31 +0000527 self.destroy()
528
lmre45a1f22009-11-10 16:35:08 +0000529 if name is not None:
lmr6f669ce2009-05-31 19:02:42 +0000530 self.name = name
lmre45a1f22009-11-10 16:35:08 +0000531 if params is not None:
lmr6f669ce2009-05-31 19:02:42 +0000532 self.params = params
lmre45a1f22009-11-10 16:35:08 +0000533 if root_dir is not None:
lmr90b9fd52009-08-17 20:48:18 +0000534 self.root_dir = root_dir
lmr6f669ce2009-05-31 19:02:42 +0000535 name = self.name
536 params = self.params
lmr90b9fd52009-08-17 20:48:18 +0000537 root_dir = self.root_dir
lmr6f669ce2009-05-31 19:02:42 +0000538
539 # Verify the md5sum of the ISO image
540 iso = params.get("cdrom")
541 if iso:
lmr90b9fd52009-08-17 20:48:18 +0000542 iso = kvm_utils.get_path(root_dir, iso)
lmr6f669ce2009-05-31 19:02:42 +0000543 if not os.path.exists(iso):
544 logging.error("ISO file not found: %s" % iso)
545 return False
546 compare = False
547 if params.get("md5sum_1m"):
lmrf4696342009-08-13 04:06:33 +0000548 logging.debug("Comparing expected MD5 sum with MD5 sum of "
549 "first MB of ISO file...")
lmrd60882f2010-02-04 03:26:36 +0000550 actual_hash = utils.hash_file(iso, 1048576, method="md5")
lmr03ba22e2009-10-23 12:07:44 +0000551 expected_hash = params.get("md5sum_1m")
lmr6f669ce2009-05-31 19:02:42 +0000552 compare = True
553 elif params.get("md5sum"):
lmrf4696342009-08-13 04:06:33 +0000554 logging.debug("Comparing expected MD5 sum with MD5 sum of ISO "
555 "file...")
lmrd60882f2010-02-04 03:26:36 +0000556 actual_hash = utils.hash_file(iso, method="md5")
lmr03ba22e2009-10-23 12:07:44 +0000557 expected_hash = params.get("md5sum")
558 compare = True
559 elif params.get("sha1sum"):
560 logging.debug("Comparing expected SHA1 sum with SHA1 sum of "
561 "ISO file...")
lmrd60882f2010-02-04 03:26:36 +0000562 actual_hash = utils.hash_file(iso, method="sha1")
lmrea1266e2009-11-10 16:41:08 +0000563 expected_hash = params.get("sha1sum")
lmr6f669ce2009-05-31 19:02:42 +0000564 compare = True
565 if compare:
lmr03ba22e2009-10-23 12:07:44 +0000566 if actual_hash == expected_hash:
567 logging.debug("Hashes match")
lmr6f669ce2009-05-31 19:02:42 +0000568 else:
lmr03ba22e2009-10-23 12:07:44 +0000569 logging.error("Actual hash differs from expected one")
lmr6f669ce2009-05-31 19:02:42 +0000570 return False
571
lmrdc2ac6a2009-06-10 19:15:49 +0000572 # Make sure the following code is not executed by more than one thread
573 # at the same time
574 lockfile = open("/tmp/kvm-autotest-vm-create.lock", "w+")
575 fcntl.lockf(lockfile, fcntl.LOCK_EX)
lmr6f669ce2009-05-31 19:02:42 +0000576
lmrdc2ac6a2009-06-10 19:15:49 +0000577 try:
578 # Handle port redirections
579 redir_names = kvm_utils.get_sub_dict_names(params, "redirs")
580 host_ports = kvm_utils.find_free_ports(5000, 6000, len(redir_names))
581 self.redirs = {}
582 for i in range(len(redir_names)):
583 redir_params = kvm_utils.get_sub_dict(params, redir_names[i])
584 guest_port = int(redir_params.get("guest_port"))
585 self.redirs[guest_port] = host_ports[i]
lmr6f669ce2009-05-31 19:02:42 +0000586
lmr48349072010-06-29 14:14:55 +0000587 for nic in kvm_utils.get_sub_dict_names(params, "nics"):
588 self.netdev_id.append(kvm_utils.generate_random_id())
589
lmrdc2ac6a2009-06-10 19:15:49 +0000590 # Find available VNC port, if needed
591 if params.get("display") == "vnc":
lmrc0da8902010-05-17 20:31:36 +0000592 self.vnc_port = kvm_utils.find_free_port(5900, 6100)
lmr6f669ce2009-05-31 19:02:42 +0000593
lmra2533222009-07-20 12:43:46 +0000594 # Find random UUID if specified 'uuid = random' in config file
595 if params.get("uuid") == "random":
596 f = open("/proc/sys/kernel/random/uuid")
597 self.uuid = f.read().strip()
598 f.close()
599
Eric Lie0493a42010-11-15 13:05:43 -0800600 # Generate or copy MAC addresses for all NICs
601 num_nics = len(kvm_utils.get_sub_dict_names(params, "nics"))
602 for vlan in range(num_nics):
603 mac = mac_source and mac_source.get_mac_address(vlan)
604 if mac:
605 kvm_utils.set_mac_address(self.instance, vlan, mac)
606 else:
607 kvm_utils.generate_mac_address(self.instance, vlan)
608
lmr31ed61d2010-06-07 13:21:38 +0000609 # Assign a PCI assignable device
610 self.pci_assignable = None
611 pa_type = params.get("pci_assignable")
612 if pa_type in ["vf", "pf", "mixed"]:
lmr31af3a12010-01-18 16:46:52 +0000613 pa_devices_requested = params.get("devices_requested")
614
615 # Virtual Functions (VF) assignable devices
616 if pa_type == "vf":
lmr31ed61d2010-06-07 13:21:38 +0000617 self.pci_assignable = kvm_utils.PciAssignable(
618 type=pa_type,
619 driver=params.get("driver"),
620 driver_option=params.get("driver_option"),
621 devices_requested=pa_devices_requested)
lmr31af3a12010-01-18 16:46:52 +0000622 # Physical NIC (PF) assignable devices
623 elif pa_type == "pf":
lmr31ed61d2010-06-07 13:21:38 +0000624 self.pci_assignable = kvm_utils.PciAssignable(
625 type=pa_type,
626 names=params.get("device_names"),
627 devices_requested=pa_devices_requested)
lmr31af3a12010-01-18 16:46:52 +0000628 # Working with both VF and PF
629 elif pa_type == "mixed":
lmr31ed61d2010-06-07 13:21:38 +0000630 self.pci_assignable = kvm_utils.PciAssignable(
631 type=pa_type,
632 driver=params.get("driver"),
633 driver_option=params.get("driver_option"),
634 names=params.get("device_names"),
635 devices_requested=pa_devices_requested)
lmr31af3a12010-01-18 16:46:52 +0000636
637 self.pa_pci_ids = self.pci_assignable.request_devs()
638
639 if self.pa_pci_ids:
lmr31ed61d2010-06-07 13:21:38 +0000640 logging.debug("Successfuly assigned devices: %s",
lmr31af3a12010-01-18 16:46:52 +0000641 self.pa_pci_ids)
642 else:
643 logging.error("No PCI assignable devices were assigned "
644 "and 'pci_assignable' is defined to %s "
lmr31ed61d2010-06-07 13:21:38 +0000645 "on your config file. Aborting VM creation.",
lmr31af3a12010-01-18 16:46:52 +0000646 pa_type)
647 return False
648
lmr856d58c2010-06-08 18:29:31 +0000649 elif pa_type and pa_type != "no":
lmr31ed61d2010-06-07 13:21:38 +0000650 logging.warn("Unsupported pci_assignable type: %s", pa_type)
lmr31af3a12010-01-18 16:46:52 +0000651
lmrdc2ac6a2009-06-10 19:15:49 +0000652 # Make qemu command
653 qemu_command = self.make_qemu_command()
lmr6f669ce2009-05-31 19:02:42 +0000654
Eric Lie0493a42010-11-15 13:05:43 -0800655 # Add migration parameters if required
656 if migration_mode == "tcp":
657 self.migration_port = kvm_utils.find_free_port(5200, 6000)
658 qemu_command += " -incoming tcp:0:%d" % self.migration_port
659 elif migration_mode == "unix":
660 self.migration_file = "/tmp/migration-unix-%s" % self.instance
661 qemu_command += " -incoming unix:%s" % self.migration_file
662 elif migration_mode == "exec":
663 qemu_command += ' -incoming "exec:%s"' % migration_exec_cmd
lmr6f669ce2009-05-31 19:02:42 +0000664
lmrdc2ac6a2009-06-10 19:15:49 +0000665 logging.debug("Running qemu command:\n%s", qemu_command)
lmra4967622009-07-23 01:36:32 +0000666 self.process = kvm_subprocess.run_bg(qemu_command, None,
667 logging.debug, "(qemu) ")
lmr6f669ce2009-05-31 19:02:42 +0000668
lmr9e964a02010-06-18 03:46:21 +0000669 # Make sure the process was started successfully
lmra4967622009-07-23 01:36:32 +0000670 if not self.process.is_alive():
671 logging.error("VM could not be created; "
672 "qemu command failed:\n%s" % qemu_command)
673 logging.error("Status: %s" % self.process.get_status())
674 logging.error("Output:" + kvm_utils.format_str_for_message(
675 self.process.get_output()))
lmrdc2ac6a2009-06-10 19:15:49 +0000676 self.destroy()
677 return False
lmr6f669ce2009-05-31 19:02:42 +0000678
lmr9e964a02010-06-18 03:46:21 +0000679 # Establish monitor connections
680 self.monitors = []
681 for monitor_name in kvm_utils.get_sub_dict_names(params,
682 "monitors"):
683 monitor_params = kvm_utils.get_sub_dict(params, monitor_name)
684 # Wait for monitor connection to succeed
685 end_time = time.time() + timeout
686 while time.time() < end_time:
687 try:
688 if monitor_params.get("monitor_type") == "qmp":
lmr449d2252010-06-18 03:48:23 +0000689 # Add a QMP monitor
690 monitor = kvm_monitor.QMPMonitor(
691 monitor_name,
692 self.get_monitor_filename(monitor_name))
lmr9e964a02010-06-18 03:46:21 +0000693 else:
694 # Add a "human" monitor
695 monitor = kvm_monitor.HumanMonitor(
696 monitor_name,
697 self.get_monitor_filename(monitor_name))
698 except kvm_monitor.MonitorError, e:
699 logging.warn(e)
700 else:
lmr449d2252010-06-18 03:48:23 +0000701 if monitor.is_responsive():
lmr9e964a02010-06-18 03:46:21 +0000702 break
703 time.sleep(1)
704 else:
705 logging.error("Could not connect to monitor '%s'" %
706 monitor_name)
707 self.destroy()
708 return False
709 # Add this monitor to the list
710 self.monitors += [monitor]
lmra4967622009-07-23 01:36:32 +0000711
lmrfe6515e2009-07-29 13:01:17 +0000712 # Get the output so far, to see if we have any problems with
lmrb306bf82010-07-08 23:47:00 +0000713 # KVM modules or with hugepage setup.
lmrfe6515e2009-07-29 13:01:17 +0000714 output = self.process.get_output()
715
lmrb306bf82010-07-08 23:47:00 +0000716 if re.search("Could not initialize KVM", output, re.IGNORECASE):
717 logging.error("Could not initialize KVM; "
718 "qemu command:\n%s" % qemu_command)
719 logging.error("Output:" + kvm_utils.format_str_for_message(
720 self.process.get_output()))
721 self.destroy()
722 return False
723
lmrfe6515e2009-07-29 13:01:17 +0000724 if "alloc_mem_area" in output:
725 logging.error("Could not allocate hugepage memory; "
726 "qemu command:\n%s" % qemu_command)
727 logging.error("Output:" + kvm_utils.format_str_for_message(
728 self.process.get_output()))
lmr090cd7a2010-04-01 02:18:52 +0000729 self.destroy()
lmrfe6515e2009-07-29 13:01:17 +0000730 return False
731
lmr71fa4de2010-06-14 15:54:55 +0000732 logging.debug("VM appears to be alive with PID %s", self.get_pid())
lmraa380a22010-06-22 02:05:29 +0000733
734 # Establish a session with the serial console -- requires a version
735 # of netcat that supports -U
736 self.serial_console = kvm_subprocess.kvm_shell_session(
737 "nc -U %s" % self.get_serial_console_filename(),
738 auto_close=False,
739 output_func=kvm_utils.log_line,
740 output_params=("serial-%s.log" % name,))
741
lmrdc2ac6a2009-06-10 19:15:49 +0000742 return True
743
744 finally:
745 fcntl.lockf(lockfile, fcntl.LOCK_UN)
746 lockfile.close()
lmr6f669ce2009-05-31 19:02:42 +0000747
748
lmr6f669ce2009-05-31 19:02:42 +0000749 def destroy(self, gracefully=True):
750 """
751 Destroy the VM.
752
lmr912c74b2009-08-17 20:43:27 +0000753 If gracefully is True, first attempt to shutdown the VM with a shell
754 command. Then, attempt to destroy the VM via the monitor with a 'quit'
755 command. If that fails, send SIGKILL to the qemu process.
lmr6f669ce2009-05-31 19:02:42 +0000756
757 @param gracefully: Whether an attempt will be made to end the VM
lmr912c74b2009-08-17 20:43:27 +0000758 using a shell command before trying to end the qemu process
759 with a 'quit' or a kill signal.
lmr6f669ce2009-05-31 19:02:42 +0000760 """
lmrf320b042009-09-15 05:48:06 +0000761 try:
762 # Is it already dead?
763 if self.is_dead():
764 logging.debug("VM is already down")
765 return
lmr6f669ce2009-05-31 19:02:42 +0000766
lmr71fa4de2010-06-14 15:54:55 +0000767 logging.debug("Destroying VM with PID %s...", self.get_pid())
lmr6f669ce2009-05-31 19:02:42 +0000768
lmrf320b042009-09-15 05:48:06 +0000769 if gracefully and self.params.get("shutdown_command"):
770 # Try to destroy with shell command
771 logging.debug("Trying to shutdown VM with shell command...")
772 session = self.remote_login()
773 if session:
774 try:
775 # Send the shutdown command
776 session.sendline(self.params.get("shutdown_command"))
777 logging.debug("Shutdown command sent; waiting for VM "
778 "to go down...")
779 if kvm_utils.wait_for(self.is_dead, 60, 1, 1):
Eric Lie0493a42010-11-15 13:05:43 -0800780 logging.debug("VM is down, freeing mac address.")
lmrf320b042009-09-15 05:48:06 +0000781 return
782 finally:
783 session.close()
lmr6f669ce2009-05-31 19:02:42 +0000784
lmr9e964a02010-06-18 03:46:21 +0000785 if self.monitor:
786 # Try to destroy with a monitor command
787 logging.debug("Trying to kill VM with monitor command...")
788 try:
789 self.monitor.quit()
790 except kvm_monitor.MonitorError, e:
791 logging.warn(e)
792 else:
793 # Wait for the VM to be really dead
794 if kvm_utils.wait_for(self.is_dead, 5, 0.5, 0.5):
795 logging.debug("VM is down")
796 return
lmrf320b042009-09-15 05:48:06 +0000797
798 # If the VM isn't dead yet...
799 logging.debug("Cannot quit normally; sending a kill to close the "
800 "deal...")
801 kvm_utils.kill_process_tree(self.process.get_pid(), 9)
lmr6f669ce2009-05-31 19:02:42 +0000802 # Wait for the VM to be really dead
803 if kvm_utils.wait_for(self.is_dead, 5, 0.5, 0.5):
804 logging.debug("VM is down")
lmr6f669ce2009-05-31 19:02:42 +0000805 return
806
lmrf320b042009-09-15 05:48:06 +0000807 logging.error("Process %s is a zombie!" % self.process.get_pid())
lmr6f669ce2009-05-31 19:02:42 +0000808
lmrf320b042009-09-15 05:48:06 +0000809 finally:
lmr9e964a02010-06-18 03:46:21 +0000810 self.monitors = []
lmr4513c432010-02-03 11:59:03 +0000811 if self.pci_assignable:
812 self.pci_assignable.release_devs()
lmrf320b042009-09-15 05:48:06 +0000813 if self.process:
814 self.process.close()
lmraa380a22010-06-22 02:05:29 +0000815 if self.serial_console:
816 self.serial_console.close()
lmr84546f22010-06-29 23:03:34 +0000817 for f in ([self.get_testlog_filename(),
818 self.get_serial_console_filename()] +
lmr9e964a02010-06-18 03:46:21 +0000819 self.get_monitor_filenames()):
820 try:
821 os.unlink(f)
822 except OSError:
823 pass
Eric Lie0493a42010-11-15 13:05:43 -0800824 if hasattr(self, "migration_file"):
825 try:
826 os.unlink(self.migration_file)
827 except OSError:
828 pass
829 num_nics = len(kvm_utils.get_sub_dict_names(self.params, "nics"))
830 for vlan in range(num_nics):
831 self.free_mac_address(vlan)
lmr9e964a02010-06-18 03:46:21 +0000832
833
834 @property
835 def monitor(self):
836 """
837 Return the main monitor object, selected by the parameter main_monitor.
838 If main_monitor isn't defined, return the first monitor.
839 If no monitors exist, or if main_monitor refers to a nonexistent
840 monitor, return None.
841 """
842 for m in self.monitors:
843 if m.name == self.params.get("main_monitor"):
844 return m
845 if self.monitors and not self.params.get("main_monitor"):
846 return self.monitors[0]
lmr6f669ce2009-05-31 19:02:42 +0000847
848
849 def is_alive(self):
850 """
lmr9e964a02010-06-18 03:46:21 +0000851 Return True if the VM is alive and its monitor is responsive.
lmr6f669ce2009-05-31 19:02:42 +0000852 """
lmra4967622009-07-23 01:36:32 +0000853 # Check if the process is running
854 if self.is_dead():
lmr6f669ce2009-05-31 19:02:42 +0000855 return False
856 # Try sending a monitor command
lmr9e964a02010-06-18 03:46:21 +0000857 return bool(self.monitor) and self.monitor.is_responsive()
lmr6f669ce2009-05-31 19:02:42 +0000858
859
860 def is_dead(self):
861 """
lmra4967622009-07-23 01:36:32 +0000862 Return True if the qemu process is dead.
lmr6f669ce2009-05-31 19:02:42 +0000863 """
lmra4967622009-07-23 01:36:32 +0000864 return not self.process or not self.process.is_alive()
lmr6f669ce2009-05-31 19:02:42 +0000865
866
867 def get_params(self):
868 """
869 Return the VM's params dict. Most modified params take effect only
870 upon VM.create().
871 """
872 return self.params
873
874
lmr9e964a02010-06-18 03:46:21 +0000875 def get_monitor_filename(self, monitor_name):
876 """
877 Return the filename corresponding to a given monitor name.
878 """
879 return "/tmp/monitor-%s-%s" % (monitor_name, self.instance)
880
881
882 def get_monitor_filenames(self):
883 """
884 Return a list of all monitor filenames (as specified in the VM's
885 params).
886 """
887 return [self.get_monitor_filename(m) for m in
888 kvm_utils.get_sub_dict_names(self.params, "monitors")]
889
890
lmr2b06f332010-06-22 02:03:41 +0000891 def get_serial_console_filename(self):
892 """
893 Return the serial console filename.
894 """
895 return "/tmp/serial-%s" % self.instance
896
897
lmr9e964a02010-06-18 03:46:21 +0000898 def get_testlog_filename(self):
899 """
900 Return the testlog filename.
901 """
902 return "/tmp/testlog-%s" % self.instance
903
904
lmrf4696342009-08-13 04:06:33 +0000905 def get_address(self, index=0):
lmr6f669ce2009-05-31 19:02:42 +0000906 """
lmrf4696342009-08-13 04:06:33 +0000907 Return the address of a NIC of the guest, in host space.
lmr6f669ce2009-05-31 19:02:42 +0000908
lmrf4696342009-08-13 04:06:33 +0000909 If port redirection is used, return 'localhost' (the NIC has no IP
910 address of its own). Otherwise return the NIC's IP address.
911
912 @param index: Index of the NIC whose address is requested.
lmr6f669ce2009-05-31 19:02:42 +0000913 """
lmree90dd92009-08-13 04:13:39 +0000914 nics = kvm_utils.get_sub_dict_names(self.params, "nics")
915 nic_name = nics[index]
lmrf4696342009-08-13 04:06:33 +0000916 nic_params = kvm_utils.get_sub_dict(self.params, nic_name)
917 if nic_params.get("nic_mode") == "tap":
Eric Lie0493a42010-11-15 13:05:43 -0800918 mac = self.get_mac_address(index)
lmree90dd92009-08-13 04:13:39 +0000919 if not mac:
920 logging.debug("MAC address unavailable")
921 return None
Eric Lie0493a42010-11-15 13:05:43 -0800922 mac = mac.lower()
923 # Get the IP address from the cache
924 ip = self.address_cache.get(mac)
925 if not ip:
926 logging.debug("Could not find IP address for MAC address: %s" %
927 mac)
928 return None
929 # Make sure the IP address is assigned to this guest
930 macs = [self.get_mac_address(i) for i in range(len(nics))]
931 if not kvm_utils.verify_ip_address_ownership(ip, macs):
932 logging.debug("Could not verify MAC-IP address mapping: "
933 "%s ---> %s" % (mac, ip))
934 return None
lmrf4696342009-08-13 04:06:33 +0000935 return ip
936 else:
937 return "localhost"
lmr6f669ce2009-05-31 19:02:42 +0000938
939
lmree90dd92009-08-13 04:13:39 +0000940 def get_port(self, port, nic_index=0):
lmr6f669ce2009-05-31 19:02:42 +0000941 """
942 Return the port in host space corresponding to port in guest space.
943
944 @param port: Port number in host space.
lmree90dd92009-08-13 04:13:39 +0000945 @param nic_index: Index of the NIC.
lmr6f669ce2009-05-31 19:02:42 +0000946 @return: If port redirection is used, return the host port redirected
947 to guest port port. Otherwise return port.
948 """
lmree90dd92009-08-13 04:13:39 +0000949 nic_name = kvm_utils.get_sub_dict_names(self.params, "nics")[nic_index]
lmrf4696342009-08-13 04:06:33 +0000950 nic_params = kvm_utils.get_sub_dict(self.params, nic_name)
951 if nic_params.get("nic_mode") == "tap":
952 return port
lmr6f669ce2009-05-31 19:02:42 +0000953 else:
lmrf4696342009-08-13 04:06:33 +0000954 if not self.redirs.has_key(port):
955 logging.warn("Warning: guest port %s requested but not "
956 "redirected" % port)
957 return self.redirs.get(port)
lmr6f669ce2009-05-31 19:02:42 +0000958
959
Eric Lie0493a42010-11-15 13:05:43 -0800960 def get_ifname(self, nic_index=0):
961 """
962 Return the ifname of a tap device associated with a NIC.
963
964 @param nic_index: Index of the NIC
965 """
966 nics = kvm_utils.get_sub_dict_names(self.params, "nics")
967 nic_name = nics[nic_index]
968 nic_params = kvm_utils.get_sub_dict(self.params, nic_name)
969 if nic_params.get("nic_ifname"):
970 return nic_params.get("nic_ifname")
971 else:
972 return "t%d-%s" % (nic_index, self.instance[-11:])
973
974
975 def get_mac_address(self, nic_index=0):
976 """
977 Return the MAC address of a NIC.
978
979 @param nic_index: Index of the NIC
980 """
981 return kvm_utils.get_mac_address(self.instance, nic_index)
982
983
984 def free_mac_address(self, nic_index=0):
985 """
986 Free a NIC's MAC address.
987
988 @param nic_index: Index of the NIC
989 """
990 kvm_utils.free_mac_address(self.instance, nic_index)
991
992
lmra4967622009-07-23 01:36:32 +0000993 def get_pid(self):
994 """
lmr71fa4de2010-06-14 15:54:55 +0000995 Return the VM's PID. If the VM is dead return None.
996
997 @note: This works under the assumption that self.process.get_pid()
998 returns the PID of the parent shell process.
999 """
1000 try:
1001 children = commands.getoutput("ps --ppid=%d -o pid=" %
1002 self.process.get_pid()).split()
1003 return int(children[0])
1004 except (TypeError, IndexError, ValueError):
1005 return None
1006
1007
1008 def get_shell_pid(self):
1009 """
1010 Return the PID of the parent shell process.
1011
1012 @note: This works under the assumption that self.process.get_pid()
1013 returns the PID of the parent shell process.
lmra4967622009-07-23 01:36:32 +00001014 """
1015 return self.process.get_pid()
1016
1017
lmr0bee2342010-02-24 00:01:37 +00001018 def get_shared_meminfo(self):
1019 """
1020 Returns the VM's shared memory information.
1021
1022 @return: Shared memory used by VM (MB)
1023 """
1024 if self.is_dead():
1025 logging.error("Could not get shared memory info from dead VM.")
1026 return None
1027
lmr983ecdf2010-06-14 15:57:12 +00001028 filename = "/proc/%d/statm" % self.get_pid()
1029 shm = int(open(filename).read().split()[2])
lmr0bee2342010-02-24 00:01:37 +00001030 # statm stores informations in pages, translate it to MB
lmr983ecdf2010-06-14 15:57:12 +00001031 return shm * 4.0 / 1024
lmr0bee2342010-02-24 00:01:37 +00001032
1033
lmr912c74b2009-08-17 20:43:27 +00001034 def remote_login(self, nic_index=0, timeout=10):
lmr6f669ce2009-05-31 19:02:42 +00001035 """
lmr912c74b2009-08-17 20:43:27 +00001036 Log into the guest via SSH/Telnet/Netcat.
lmr6f669ce2009-05-31 19:02:42 +00001037 If timeout expires while waiting for output from the guest (e.g. a
1038 password prompt or a shell prompt) -- fail.
1039
lmree90dd92009-08-13 04:13:39 +00001040 @param nic_index: The index of the NIC to connect to.
lmr6f669ce2009-05-31 19:02:42 +00001041 @param timeout: Time (seconds) before giving up logging into the
1042 guest.
1043 @return: kvm_spawn object on success and None on failure.
1044 """
1045 username = self.params.get("username", "")
1046 password = self.params.get("password", "")
lmr912c74b2009-08-17 20:43:27 +00001047 prompt = self.params.get("shell_prompt", "[\#\$]")
lmr59f9e2d2009-10-05 18:47:16 +00001048 linesep = eval("'%s'" % self.params.get("shell_linesep", r"\n"))
lmr912c74b2009-08-17 20:43:27 +00001049 client = self.params.get("shell_client")
lmree90dd92009-08-13 04:13:39 +00001050 address = self.get_address(nic_index)
lmr912c74b2009-08-17 20:43:27 +00001051 port = self.get_port(int(self.params.get("shell_port")))
lmre56903f2010-06-22 02:09:35 +00001052 log_filename = ("session-%s-%s.log" %
1053 (self.name, kvm_utils.generate_random_string(4)))
lmr912c74b2009-08-17 20:43:27 +00001054
lmree90dd92009-08-13 04:13:39 +00001055 if not address or not port:
1056 logging.debug("IP address or port unavailable")
lmr6f669ce2009-05-31 19:02:42 +00001057 return None
1058
lmr158604f2010-06-22 01:57:34 +00001059 session = kvm_utils.remote_login(client, address, port, username,
lmre56903f2010-06-22 02:09:35 +00001060 password, prompt, linesep,
1061 log_filename, timeout)
lmr912c74b2009-08-17 20:43:27 +00001062
lmr6f669ce2009-05-31 19:02:42 +00001063 if session:
lmr912c74b2009-08-17 20:43:27 +00001064 session.set_status_test_command(self.params.get("status_test_"
lmr6f669ce2009-05-31 19:02:42 +00001065 "command", ""))
1066 return session
1067
1068
lmrc196d492010-05-07 14:14:26 +00001069 def copy_files_to(self, local_path, remote_path, nic_index=0, timeout=600):
lmr6f669ce2009-05-31 19:02:42 +00001070 """
lmr912c74b2009-08-17 20:43:27 +00001071 Transfer files to the guest.
lmr6f669ce2009-05-31 19:02:42 +00001072
1073 @param local_path: Host path
1074 @param remote_path: Guest path
lmr912c74b2009-08-17 20:43:27 +00001075 @param nic_index: The index of the NIC to connect to.
lmr6f669ce2009-05-31 19:02:42 +00001076 @param timeout: Time (seconds) before giving up on doing the remote
1077 copy.
1078 """
1079 username = self.params.get("username", "")
1080 password = self.params.get("password", "")
lmr912c74b2009-08-17 20:43:27 +00001081 client = self.params.get("file_transfer_client")
lmree90dd92009-08-13 04:13:39 +00001082 address = self.get_address(nic_index)
lmr912c74b2009-08-17 20:43:27 +00001083 port = self.get_port(int(self.params.get("file_transfer_port")))
1084
lmree90dd92009-08-13 04:13:39 +00001085 if not address or not port:
1086 logging.debug("IP address or port unavailable")
lmr6f669ce2009-05-31 19:02:42 +00001087 return None
lmr912c74b2009-08-17 20:43:27 +00001088
1089 if client == "scp":
lmrcbc86ef2010-07-07 20:50:08 +00001090 log_filename = ("scp-%s-%s.log" %
1091 (self.name, kvm_utils.generate_random_string(4)))
lmr912c74b2009-08-17 20:43:27 +00001092 return kvm_utils.scp_to_remote(address, port, username, password,
lmre56903f2010-06-22 02:09:35 +00001093 local_path, remote_path,
1094 log_filename, timeout)
lmrcbc86ef2010-07-07 20:50:08 +00001095 elif client == "rss":
1096 c = rss_file_transfer.FileUploadClient(address, port)
1097 c.upload(local_path, remote_path, timeout)
1098 c.close()
1099 return True
lmr6f669ce2009-05-31 19:02:42 +00001100
1101
lmrc196d492010-05-07 14:14:26 +00001102 def copy_files_from(self, remote_path, local_path, nic_index=0, timeout=600):
lmr6f669ce2009-05-31 19:02:42 +00001103 """
lmr912c74b2009-08-17 20:43:27 +00001104 Transfer files from the guest.
lmr6f669ce2009-05-31 19:02:42 +00001105
1106 @param local_path: Guest path
1107 @param remote_path: Host path
lmr912c74b2009-08-17 20:43:27 +00001108 @param nic_index: The index of the NIC to connect to.
lmr6f669ce2009-05-31 19:02:42 +00001109 @param timeout: Time (seconds) before giving up on doing the remote
1110 copy.
1111 """
1112 username = self.params.get("username", "")
1113 password = self.params.get("password", "")
lmr912c74b2009-08-17 20:43:27 +00001114 client = self.params.get("file_transfer_client")
lmree90dd92009-08-13 04:13:39 +00001115 address = self.get_address(nic_index)
lmr912c74b2009-08-17 20:43:27 +00001116 port = self.get_port(int(self.params.get("file_transfer_port")))
1117
lmree90dd92009-08-13 04:13:39 +00001118 if not address or not port:
1119 logging.debug("IP address or port unavailable")
lmr6f669ce2009-05-31 19:02:42 +00001120 return None
lmr6f669ce2009-05-31 19:02:42 +00001121
lmr912c74b2009-08-17 20:43:27 +00001122 if client == "scp":
lmrcbc86ef2010-07-07 20:50:08 +00001123 log_filename = ("scp-%s-%s.log" %
1124 (self.name, kvm_utils.generate_random_string(4)))
lmr912c74b2009-08-17 20:43:27 +00001125 return kvm_utils.scp_from_remote(address, port, username, password,
lmre56903f2010-06-22 02:09:35 +00001126 remote_path, local_path,
1127 log_filename, timeout)
lmrcbc86ef2010-07-07 20:50:08 +00001128 elif client == "rss":
1129 c = rss_file_transfer.FileDownloadClient(address, port)
1130 c.download(remote_path, local_path, timeout)
1131 c.close()
1132 return True
lmr6f669ce2009-05-31 19:02:42 +00001133
1134
lmraa380a22010-06-22 02:05:29 +00001135 def serial_login(self, timeout=10):
1136 """
1137 Log into the guest via the serial console.
1138 If timeout expires while waiting for output from the guest (e.g. a
1139 password prompt or a shell prompt) -- fail.
1140
1141 @param timeout: Time (seconds) before giving up logging into the guest.
1142 @return: kvm_spawn object on success and None on failure.
1143 """
1144 username = self.params.get("username", "")
1145 password = self.params.get("password", "")
1146 prompt = self.params.get("shell_prompt", "[\#\$]")
1147 linesep = eval("'%s'" % self.params.get("shell_linesep", r"\n"))
1148 status_test_command = self.params.get("status_test_command", "")
1149
1150 if self.serial_console:
1151 self.serial_console.set_linesep(linesep)
1152 self.serial_console.set_status_test_command(status_test_command)
1153 else:
1154 return None
1155
1156 # Make sure we get a login prompt
1157 self.serial_console.sendline()
1158
1159 if kvm_utils._remote_login(self.serial_console, username, password,
1160 prompt, timeout):
1161 return self.serial_console
1162
1163
lmr6f669ce2009-05-31 19:02:42 +00001164 def send_key(self, keystr):
1165 """
1166 Send a key event to the VM.
1167
1168 @param: keystr: A key event string (e.g. "ctrl-alt-delete")
1169 """
1170 # For compatibility with versions of QEMU that do not recognize all
1171 # key names: replace keyname with the hex value from the dict, which
1172 # QEMU will definitely accept
lmr9e964a02010-06-18 03:46:21 +00001173 dict = {"comma": "0x33",
1174 "dot": "0x34",
1175 "slash": "0x35"}
1176 for key, value in dict.items():
1177 keystr = keystr.replace(key, value)
1178 self.monitor.sendkey(keystr)
lmr6f669ce2009-05-31 19:02:42 +00001179 time.sleep(0.2)
1180
1181
1182 def send_string(self, str):
1183 """
1184 Send a string to the VM.
1185
1186 @param str: String, that must consist of alphanumeric characters only.
1187 Capital letters are allowed.
1188 """
1189 for char in str:
1190 if char.isupper():
1191 self.send_key("shift-%s" % char.lower())
1192 else:
1193 self.send_key(char)
lmra2533222009-07-20 12:43:46 +00001194
mbligh1ef218d2009-08-03 16:57:56 +00001195
lmra2533222009-07-20 12:43:46 +00001196 def get_uuid(self):
1197 """
1198 Catch UUID of the VM.
1199
1200 @return: None,if not specified in config file
1201 """
1202 if self.params.get("uuid") == "random":
1203 return self.uuid
1204 else:
1205 return self.params.get("uuid", None)
lmrdd2ff922009-12-01 23:39:12 +00001206
1207
1208 def get_cpu_count(self):
1209 """
1210 Get the cpu count of the VM.
1211 """
lmr13426552010-01-17 15:38:41 +00001212 session = self.remote_login()
1213 if not session:
1214 return None
lmrdd2ff922009-12-01 23:39:12 +00001215 try:
lmr13426552010-01-17 15:38:41 +00001216 cmd = self.params.get("cpu_chk_cmd")
1217 s, count = session.get_command_status_output(cmd)
1218 if s == 0:
1219 return int(count)
lmrdd2ff922009-12-01 23:39:12 +00001220 return None
1221 finally:
1222 session.close()
1223
1224
lmr28426c82010-04-16 06:02:58 +00001225 def get_memory_size(self, cmd=None):
lmrdd2ff922009-12-01 23:39:12 +00001226 """
lmr28426c82010-04-16 06:02:58 +00001227 Get bootup memory size of the VM.
1228
1229 @param check_cmd: Command used to check memory. If not provided,
1230 self.params.get("mem_chk_cmd") will be used.
lmrdd2ff922009-12-01 23:39:12 +00001231 """
lmr13426552010-01-17 15:38:41 +00001232 session = self.remote_login()
1233 if not session:
lmrdd2ff922009-12-01 23:39:12 +00001234 return None
lmr13426552010-01-17 15:38:41 +00001235 try:
lmr28426c82010-04-16 06:02:58 +00001236 if not cmd:
1237 cmd = self.params.get("mem_chk_cmd")
lmr13426552010-01-17 15:38:41 +00001238 s, mem_str = session.get_command_status_output(cmd)
1239 if s != 0:
1240 return None
lmr6d69f4d2010-02-12 11:35:55 +00001241 mem = re.findall("([0-9]+)", mem_str)
lmr13426552010-01-17 15:38:41 +00001242 mem_size = 0
1243 for m in mem:
1244 mem_size += int(m)
1245 if "GB" in mem_str:
1246 mem_size *= 1024
1247 elif "MB" in mem_str:
1248 pass
1249 else:
1250 mem_size /= 1024
1251 return int(mem_size)
lmrdd2ff922009-12-01 23:39:12 +00001252 finally:
1253 session.close()
lmr28426c82010-04-16 06:02:58 +00001254
1255
1256 def get_current_memory_size(self):
1257 """
1258 Get current memory size of the VM, rather than bootup memory.
1259 """
1260 cmd = self.params.get("mem_chk_cur_cmd")
1261 return self.get_memory_size(cmd)