blob: 135d08ebd8270040bfeb50aa4e5ae1132ccecfbc [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
lmr9e964a02010-06-18 03:46:21 +00008import time, socket, os, logging, fcntl, re, commands, 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
lmra2533222009-07-20 12:43:46 +0000112 self.uuid = None
lmr9e964a02010-06-18 03:46:21 +0000113 self.monitors = []
114 self.pci_assignable = None
lmr6f669ce2009-05-31 19:02:42 +0000115
116 self.name = name
117 self.params = params
lmr90b9fd52009-08-17 20:48:18 +0000118 self.root_dir = root_dir
lmree90dd92009-08-13 04:13:39 +0000119 self.address_cache = address_cache
lmrb1cad1e2010-06-17 17:36:09 +0000120 self.netdev_id = []
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
lmrb1cad1e2010-06-17 17:36:09 +0000237 def add_nic(help, vlan, model=None, mac=None, netdev_id=None):
lmrb1cad1e2010-06-17 17:36:09 +0000238 if has_option(help, "netdev"):
Eric Li6f27d4f2010-09-29 10:55:17 -0700239 cmd = " -net nic,netdev=%s" % netdev_id
240 else:
241 cmd = " -net nic,vlan=%d" % vlan
lmr48abd7d2010-05-26 13:48:04 +0000242 if model: cmd += ",model=%s" % model
lmr09a78162010-06-14 16:29:23 +0000243 if mac: cmd += ",macaddr='%s'" % mac
lmr48abd7d2010-05-26 13:48:04 +0000244 return cmd
245
246 def add_net(help, vlan, mode, ifname=None, script=None,
lmr6976faa2010-07-09 21:11:06 +0000247 downscript=None, tftp=None, bootfile=None, hostfwd=[],
248 netdev_id=None):
lmrb1cad1e2010-06-17 17:36:09 +0000249 if has_option(help, "netdev"):
250 cmd = " -netdev %s,id=%s" % (mode, netdev_id)
251 else:
252 cmd = " -net %s,vlan=%d" % (mode, vlan)
lmr48abd7d2010-05-26 13:48:04 +0000253 if mode == "tap":
lmr09a78162010-06-14 16:29:23 +0000254 if ifname: cmd += ",ifname='%s'" % ifname
255 if script: cmd += ",script='%s'" % script
256 cmd += ",downscript='%s'" % (downscript or "no")
lmr6976faa2010-07-09 21:11:06 +0000257 elif mode == "user":
258 if tftp and "[,tftp=" in help:
259 cmd += ",tftp='%s'" % tftp
260 if bootfile and "[,bootfile=" in help:
261 cmd += ",bootfile='%s'" % bootfile
262 if "[,hostfwd=" in help:
263 for host_port, guest_port in hostfwd:
264 cmd += ",hostfwd=tcp::%s-:%s" % (host_port, guest_port)
lmr48abd7d2010-05-26 13:48:04 +0000265 return cmd
266
267 def add_floppy(help, filename):
lmr09a78162010-06-14 16:29:23 +0000268 return " -fda '%s'" % filename
lmr48abd7d2010-05-26 13:48:04 +0000269
270 def add_tftp(help, filename):
lmr6976faa2010-07-09 21:11:06 +0000271 # If the new syntax is supported, don't add -tftp
272 if "[,tftp=" in help:
273 return ""
274 else:
275 return " -tftp '%s'" % filename
276
277 def add_bootp(help, filename):
278 # If the new syntax is supported, don't add -bootp
279 if "[,bootfile=" in help:
280 return ""
281 else:
282 return " -bootp '%s'" % filename
lmr48abd7d2010-05-26 13:48:04 +0000283
284 def add_tcp_redir(help, host_port, guest_port):
lmr6976faa2010-07-09 21:11:06 +0000285 # If the new syntax is supported, don't add -redir
286 if "[,hostfwd=" in help:
287 return ""
288 else:
289 return " -redir tcp:%s::%s" % (host_port, guest_port)
lmr48abd7d2010-05-26 13:48:04 +0000290
291 def add_vnc(help, vnc_port):
292 return " -vnc :%d" % (vnc_port - 5900)
293
294 def add_sdl(help):
295 if has_option(help, "sdl"):
296 return " -sdl"
297 else:
298 return ""
299
300 def add_nographic(help):
301 return " -nographic"
302
303 def add_uuid(help, uuid):
lmr09a78162010-06-14 16:29:23 +0000304 return " -uuid '%s'" % uuid
lmr48abd7d2010-05-26 13:48:04 +0000305
306 def add_pcidevice(help, host):
lmr09a78162010-06-14 16:29:23 +0000307 return " -pcidevice host='%s'" % host
lmr48abd7d2010-05-26 13:48:04 +0000308
lmr41cb8fc2010-06-10 15:30:45 +0000309 def add_kernel(help, filename):
lmr09a78162010-06-14 16:29:23 +0000310 return " -kernel '%s'" % filename
lmr41cb8fc2010-06-10 15:30:45 +0000311
312 def add_initrd(help, filename):
lmr09a78162010-06-14 16:29:23 +0000313 return " -initrd '%s'" % filename
lmr41cb8fc2010-06-10 15:30:45 +0000314
lmre0474e32010-06-29 14:10:09 +0000315 def add_kernel_cmdline(help, cmdline):
316 return " -append %s" % cmdline
317
lmr71024552010-06-29 14:12:35 +0000318 def add_testdev(help, filename):
319 return (" -chardev file,id=testlog,path=%s"
320 " -device testdev,chardev=testlog" % filename)
321
lmrce5c9252010-06-30 17:41:00 +0000322 def add_no_hpet(help):
323 if has_option(help, "no-hpet"):
324 return " -no-hpet"
325 else:
326 return ""
327
lmr48abd7d2010-05-26 13:48:04 +0000328 # End of command line option wrappers
329
330 if name is None: name = self.name
331 if params is None: params = self.params
332 if root_dir is None: root_dir = self.root_dir
333
334 qemu_binary = kvm_utils.get_path(root_dir, params.get("qemu_binary",
335 "qemu"))
336 # Get the output of 'qemu -help' (log a message in case this call never
337 # returns or causes some other kind of trouble)
338 logging.debug("Getting output of 'qemu -help'")
339 help = commands.getoutput("%s -help" % qemu_binary)
lmr6f669ce2009-05-31 19:02:42 +0000340
lmreeff0eb2009-06-10 19:19:15 +0000341 # Start constructing the qemu command
342 qemu_cmd = ""
343 # Set the X11 display parameter if requested
344 if params.get("x11_display"):
345 qemu_cmd += "DISPLAY=%s " % params.get("x11_display")
346 # Add the qemu binary
lmr48abd7d2010-05-26 13:48:04 +0000347 qemu_cmd += qemu_binary
lmreeff0eb2009-06-10 19:19:15 +0000348 # Add the VM's name
lmr48abd7d2010-05-26 13:48:04 +0000349 qemu_cmd += add_name(help, name)
lmr9e964a02010-06-18 03:46:21 +0000350 # Add monitors
351 for monitor_name in kvm_utils.get_sub_dict_names(params, "monitors"):
352 monitor_params = kvm_utils.get_sub_dict(params, monitor_name)
353 monitor_filename = self.get_monitor_filename(monitor_name)
354 if monitor_params.get("monitor_type") == "qmp":
355 qemu_cmd += add_qmp_monitor(help, monitor_filename)
356 else:
357 qemu_cmd += add_human_monitor(help, monitor_filename)
lmr6f669ce2009-05-31 19:02:42 +0000358
lmr2b06f332010-06-22 02:03:41 +0000359 # Add serial console redirection
360 qemu_cmd += add_serial(help, self.get_serial_console_filename())
361
lmr6f669ce2009-05-31 19:02:42 +0000362 for image_name in kvm_utils.get_sub_dict_names(params, "images"):
363 image_params = kvm_utils.get_sub_dict(params, image_name)
lmr9d75ee32009-09-29 13:14:13 +0000364 if image_params.get("boot_drive") == "no":
365 continue
lmr48abd7d2010-05-26 13:48:04 +0000366 qemu_cmd += add_drive(help,
367 get_image_filename(image_params, root_dir),
lmraf709702010-07-20 00:56:33 +0000368 image_params.get("drive_index"),
lmr48abd7d2010-05-26 13:48:04 +0000369 image_params.get("drive_format"),
370 image_params.get("drive_cache"),
371 image_params.get("drive_werror"),
372 image_params.get("drive_serial"),
373 image_params.get("image_snapshot") == "yes",
374 image_params.get("image_boot") == "yes")
lmr6f669ce2009-05-31 19:02:42 +0000375
lmr6976faa2010-07-09 21:11:06 +0000376 redirs = []
377 for redir_name in kvm_utils.get_sub_dict_names(params, "redirs"):
378 redir_params = kvm_utils.get_sub_dict(params, redir_name)
379 guest_port = int(redir_params.get("guest_port"))
380 host_port = self.redirs.get(guest_port)
381 redirs += [(host_port, guest_port)]
382
lmr6f669ce2009-05-31 19:02:42 +0000383 vlan = 0
384 for nic_name in kvm_utils.get_sub_dict_names(params, "nics"):
385 nic_params = kvm_utils.get_sub_dict(params, nic_name)
lmrf4696342009-08-13 04:06:33 +0000386 # Handle the '-net nic' part
lmr48abd7d2010-05-26 13:48:04 +0000387 mac = None
388 if "address_index" in nic_params:
389 mac = kvm_utils.get_mac_ip_pair_from_dict(nic_params)[0]
lmrb1cad1e2010-06-17 17:36:09 +0000390 qemu_cmd += add_nic(help, vlan, nic_params.get("nic_model"), mac,
391 self.netdev_id[vlan])
lmrf4696342009-08-13 04:06:33 +0000392 # Handle the '-net tap' or '-net user' part
lmre4eaa862010-06-01 19:15:14 +0000393 script = nic_params.get("nic_script")
394 downscript = nic_params.get("nic_downscript")
lmr6976faa2010-07-09 21:11:06 +0000395 tftp = nic_params.get("tftp")
lmr48abd7d2010-05-26 13:48:04 +0000396 if script:
397 script = kvm_utils.get_path(root_dir, script)
398 if downscript:
399 downscript = kvm_utils.get_path(root_dir, downscript)
lmr6976faa2010-07-09 21:11:06 +0000400 if tftp:
401 tftp = kvm_utils.get_path(root_dir, tftp)
lmr48abd7d2010-05-26 13:48:04 +0000402 qemu_cmd += add_net(help, vlan, nic_params.get("nic_mode", "user"),
403 nic_params.get("nic_ifname"),
lmr6976faa2010-07-09 21:11:06 +0000404 script, downscript, tftp,
405 nic_params.get("bootp"), redirs,
406 self.netdev_id[vlan])
lmrf4696342009-08-13 04:06:33 +0000407 # Proceed to next NIC
lmr6f669ce2009-05-31 19:02:42 +0000408 vlan += 1
409
410 mem = params.get("mem")
411 if mem:
lmr48abd7d2010-05-26 13:48:04 +0000412 qemu_cmd += add_mem(help, mem)
lmr6f669ce2009-05-31 19:02:42 +0000413
lmrc43bf372009-11-10 13:19:00 +0000414 smp = params.get("smp")
415 if smp:
lmrdb3fe612010-06-14 16:19:28 +0000416 qemu_cmd += add_smp(help, smp)
lmrc43bf372009-11-10 13:19:00 +0000417
lmrac5dce72010-07-20 00:58:25 +0000418 cdroms = kvm_utils.get_sub_dict_names(params, "cdroms")
419 for cdrom in cdroms:
420 cdrom_params = kvm_utils.get_sub_dict(params, cdrom)
421 iso = cdrom_params.get("cdrom")
422 if iso:
423 qemu_cmd += add_cdrom(help, kvm_utils.get_path(root_dir, iso),
424 cdrom_params.get("drive_index"))
lmr6f669ce2009-05-31 19:02:42 +0000425
lmrb0a9b762009-10-09 20:43:30 +0000426 # We may want to add {floppy_otps} parameter for -fda
lmr48abd7d2010-05-26 13:48:04 +0000427 # {fat:floppy:}/path/. However vvfat is not usually recommended.
lmrb0a9b762009-10-09 20:43:30 +0000428 floppy = params.get("floppy")
429 if floppy:
lmrf69f6b12009-11-10 16:33:44 +0000430 floppy = kvm_utils.get_path(root_dir, floppy)
lmr48abd7d2010-05-26 13:48:04 +0000431 qemu_cmd += add_floppy(help, floppy)
lmrb0a9b762009-10-09 20:43:30 +0000432
433 tftp = params.get("tftp")
lmr62fc2bb2010-07-08 23:45:11 +0000434 if tftp:
lmrf69f6b12009-11-10 16:33:44 +0000435 tftp = kvm_utils.get_path(root_dir, tftp)
lmr48abd7d2010-05-26 13:48:04 +0000436 qemu_cmd += add_tftp(help, tftp)
lmr6f669ce2009-05-31 19:02:42 +0000437
lmr6976faa2010-07-09 21:11:06 +0000438 bootp = params.get("bootp")
439 if bootp:
440 qemu_cmd += add_bootp(help, bootp)
441
lmr41cb8fc2010-06-10 15:30:45 +0000442 kernel = params.get("kernel")
443 if kernel:
444 kernel = kvm_utils.get_path(root_dir, kernel)
445 qemu_cmd += add_kernel(help, kernel)
446
lmre0474e32010-06-29 14:10:09 +0000447 kernel_cmdline = params.get("kernel_cmdline")
448 if kernel_cmdline:
449 qemu_cmd += add_kernel_cmdline(help, kernel_cmdline)
450
lmr41cb8fc2010-06-10 15:30:45 +0000451 initrd = params.get("initrd")
452 if initrd:
453 initrd = kvm_utils.get_path(root_dir, initrd)
454 qemu_cmd += add_initrd(help, initrd)
455
lmr6976faa2010-07-09 21:11:06 +0000456 for host_port, guest_port in redirs:
lmr48abd7d2010-05-26 13:48:04 +0000457 qemu_cmd += add_tcp_redir(help, host_port, guest_port)
lmr6f669ce2009-05-31 19:02:42 +0000458
459 if params.get("display") == "vnc":
lmr48abd7d2010-05-26 13:48:04 +0000460 qemu_cmd += add_vnc(help, self.vnc_port)
lmr6f669ce2009-05-31 19:02:42 +0000461 elif params.get("display") == "sdl":
lmr48abd7d2010-05-26 13:48:04 +0000462 qemu_cmd += add_sdl(help)
lmr6f669ce2009-05-31 19:02:42 +0000463 elif params.get("display") == "nographic":
lmr48abd7d2010-05-26 13:48:04 +0000464 qemu_cmd += add_nographic(help)
lmr6f669ce2009-05-31 19:02:42 +0000465
lmra2533222009-07-20 12:43:46 +0000466 if params.get("uuid") == "random":
lmr48abd7d2010-05-26 13:48:04 +0000467 qemu_cmd += add_uuid(help, self.uuid)
lmra2533222009-07-20 12:43:46 +0000468 elif params.get("uuid"):
lmr48abd7d2010-05-26 13:48:04 +0000469 qemu_cmd += add_uuid(help, params.get("uuid"))
lmra2533222009-07-20 12:43:46 +0000470
lmr71024552010-06-29 14:12:35 +0000471 if params.get("testdev") == "yes":
472 qemu_cmd += add_testdev(help, self.get_testlog_filename())
473
lmrce5c9252010-06-30 17:41:00 +0000474 if params.get("disable_hpet") == "yes":
475 qemu_cmd += add_no_hpet(help)
476
lmr31af3a12010-01-18 16:46:52 +0000477 # If the PCI assignment step went OK, add each one of the PCI assigned
478 # devices to the qemu command line.
479 if self.pci_assignable:
480 for pci_id in self.pa_pci_ids:
lmr48abd7d2010-05-26 13:48:04 +0000481 qemu_cmd += add_pcidevice(help, pci_id)
482
483 extra_params = params.get("extra_params")
484 if extra_params:
485 qemu_cmd += " %s" % extra_params
lmr31af3a12010-01-18 16:46:52 +0000486
lmr6f669ce2009-05-31 19:02:42 +0000487 return qemu_cmd
488
489
lmr52800ba2009-08-17 20:49:58 +0000490 def create(self, name=None, params=None, root_dir=None,
lmr1424f3e2010-06-17 13:57:09 +0000491 for_migration=False, timeout=5.0, extra_params=None):
lmr6f669ce2009-05-31 19:02:42 +0000492 """
493 Start the VM by running a qemu command.
494 All parameters are optional. The following applies to all parameters
495 but for_migration: If a parameter is not supplied, the corresponding
496 value stored in the class attributes is used, and if it is supplied,
497 it is stored for later use.
498
499 @param name: The name of the object
500 @param params: A dict containing VM params
lmr90b9fd52009-08-17 20:48:18 +0000501 @param root_dir: Base directory for relative filenames
lmr6f669ce2009-05-31 19:02:42 +0000502 @param for_migration: If True, start the VM with the -incoming
503 option
lmr1424f3e2010-06-17 13:57:09 +0000504 @param extra_params: extra params for qemu command.e.g -incoming option
505 Please use this parameter instead of for_migration.
lmr6f669ce2009-05-31 19:02:42 +0000506 """
lmr135b5e62009-06-10 19:22:31 +0000507 self.destroy()
508
lmre45a1f22009-11-10 16:35:08 +0000509 if name is not None:
lmr6f669ce2009-05-31 19:02:42 +0000510 self.name = name
lmre45a1f22009-11-10 16:35:08 +0000511 if params is not None:
lmr6f669ce2009-05-31 19:02:42 +0000512 self.params = params
lmre45a1f22009-11-10 16:35:08 +0000513 if root_dir is not None:
lmr90b9fd52009-08-17 20:48:18 +0000514 self.root_dir = root_dir
lmr6f669ce2009-05-31 19:02:42 +0000515 name = self.name
516 params = self.params
lmr90b9fd52009-08-17 20:48:18 +0000517 root_dir = self.root_dir
lmr6f669ce2009-05-31 19:02:42 +0000518
519 # Verify the md5sum of the ISO image
520 iso = params.get("cdrom")
521 if iso:
lmr90b9fd52009-08-17 20:48:18 +0000522 iso = kvm_utils.get_path(root_dir, iso)
lmr6f669ce2009-05-31 19:02:42 +0000523 if not os.path.exists(iso):
524 logging.error("ISO file not found: %s" % iso)
525 return False
526 compare = False
527 if params.get("md5sum_1m"):
lmrf4696342009-08-13 04:06:33 +0000528 logging.debug("Comparing expected MD5 sum with MD5 sum of "
529 "first MB of ISO file...")
lmrd60882f2010-02-04 03:26:36 +0000530 actual_hash = utils.hash_file(iso, 1048576, method="md5")
lmr03ba22e2009-10-23 12:07:44 +0000531 expected_hash = params.get("md5sum_1m")
lmr6f669ce2009-05-31 19:02:42 +0000532 compare = True
533 elif params.get("md5sum"):
lmrf4696342009-08-13 04:06:33 +0000534 logging.debug("Comparing expected MD5 sum with MD5 sum of ISO "
535 "file...")
lmrd60882f2010-02-04 03:26:36 +0000536 actual_hash = utils.hash_file(iso, method="md5")
lmr03ba22e2009-10-23 12:07:44 +0000537 expected_hash = params.get("md5sum")
538 compare = True
539 elif params.get("sha1sum"):
540 logging.debug("Comparing expected SHA1 sum with SHA1 sum of "
541 "ISO file...")
lmrd60882f2010-02-04 03:26:36 +0000542 actual_hash = utils.hash_file(iso, method="sha1")
lmrea1266e2009-11-10 16:41:08 +0000543 expected_hash = params.get("sha1sum")
lmr6f669ce2009-05-31 19:02:42 +0000544 compare = True
545 if compare:
lmr03ba22e2009-10-23 12:07:44 +0000546 if actual_hash == expected_hash:
547 logging.debug("Hashes match")
lmr6f669ce2009-05-31 19:02:42 +0000548 else:
lmr03ba22e2009-10-23 12:07:44 +0000549 logging.error("Actual hash differs from expected one")
lmr6f669ce2009-05-31 19:02:42 +0000550 return False
551
lmrdc2ac6a2009-06-10 19:15:49 +0000552 # Make sure the following code is not executed by more than one thread
553 # at the same time
554 lockfile = open("/tmp/kvm-autotest-vm-create.lock", "w+")
555 fcntl.lockf(lockfile, fcntl.LOCK_EX)
lmr6f669ce2009-05-31 19:02:42 +0000556
lmrdc2ac6a2009-06-10 19:15:49 +0000557 try:
558 # Handle port redirections
559 redir_names = kvm_utils.get_sub_dict_names(params, "redirs")
560 host_ports = kvm_utils.find_free_ports(5000, 6000, len(redir_names))
561 self.redirs = {}
562 for i in range(len(redir_names)):
563 redir_params = kvm_utils.get_sub_dict(params, redir_names[i])
564 guest_port = int(redir_params.get("guest_port"))
565 self.redirs[guest_port] = host_ports[i]
lmr6f669ce2009-05-31 19:02:42 +0000566
lmr48349072010-06-29 14:14:55 +0000567 for nic in kvm_utils.get_sub_dict_names(params, "nics"):
568 self.netdev_id.append(kvm_utils.generate_random_id())
569
lmrdc2ac6a2009-06-10 19:15:49 +0000570 # Find available VNC port, if needed
571 if params.get("display") == "vnc":
lmrc0da8902010-05-17 20:31:36 +0000572 self.vnc_port = kvm_utils.find_free_port(5900, 6100)
lmr6f669ce2009-05-31 19:02:42 +0000573
lmra2533222009-07-20 12:43:46 +0000574 # Find random UUID if specified 'uuid = random' in config file
575 if params.get("uuid") == "random":
576 f = open("/proc/sys/kernel/random/uuid")
577 self.uuid = f.read().strip()
578 f.close()
579
lmr31ed61d2010-06-07 13:21:38 +0000580 # Assign a PCI assignable device
581 self.pci_assignable = None
582 pa_type = params.get("pci_assignable")
583 if pa_type in ["vf", "pf", "mixed"]:
lmr31af3a12010-01-18 16:46:52 +0000584 pa_devices_requested = params.get("devices_requested")
585
586 # Virtual Functions (VF) assignable devices
587 if pa_type == "vf":
lmr31ed61d2010-06-07 13:21:38 +0000588 self.pci_assignable = kvm_utils.PciAssignable(
589 type=pa_type,
590 driver=params.get("driver"),
591 driver_option=params.get("driver_option"),
592 devices_requested=pa_devices_requested)
lmr31af3a12010-01-18 16:46:52 +0000593 # Physical NIC (PF) assignable devices
594 elif pa_type == "pf":
lmr31ed61d2010-06-07 13:21:38 +0000595 self.pci_assignable = kvm_utils.PciAssignable(
596 type=pa_type,
597 names=params.get("device_names"),
598 devices_requested=pa_devices_requested)
lmr31af3a12010-01-18 16:46:52 +0000599 # Working with both VF and PF
600 elif pa_type == "mixed":
lmr31ed61d2010-06-07 13:21:38 +0000601 self.pci_assignable = kvm_utils.PciAssignable(
602 type=pa_type,
603 driver=params.get("driver"),
604 driver_option=params.get("driver_option"),
605 names=params.get("device_names"),
606 devices_requested=pa_devices_requested)
lmr31af3a12010-01-18 16:46:52 +0000607
608 self.pa_pci_ids = self.pci_assignable.request_devs()
609
610 if self.pa_pci_ids:
lmr31ed61d2010-06-07 13:21:38 +0000611 logging.debug("Successfuly assigned devices: %s",
lmr31af3a12010-01-18 16:46:52 +0000612 self.pa_pci_ids)
613 else:
614 logging.error("No PCI assignable devices were assigned "
615 "and 'pci_assignable' is defined to %s "
lmr31ed61d2010-06-07 13:21:38 +0000616 "on your config file. Aborting VM creation.",
lmr31af3a12010-01-18 16:46:52 +0000617 pa_type)
618 return False
619
lmr856d58c2010-06-08 18:29:31 +0000620 elif pa_type and pa_type != "no":
lmr31ed61d2010-06-07 13:21:38 +0000621 logging.warn("Unsupported pci_assignable type: %s", pa_type)
lmr31af3a12010-01-18 16:46:52 +0000622
lmrdc2ac6a2009-06-10 19:15:49 +0000623 # Make qemu command
624 qemu_command = self.make_qemu_command()
lmr6f669ce2009-05-31 19:02:42 +0000625
lmr1424f3e2010-06-17 13:57:09 +0000626 # Enable migration support for VM by adding extra_params.
627 if extra_params is not None:
628 if " -incoming tcp:0:%d" == extra_params:
629 self.migration_port = kvm_utils.find_free_port(5200, 6000)
630 qemu_command += extra_params % self.migration_port
631 elif " -incoming unix:%s" == extra_params:
632 self.migration_file = os.path.join("/tmp/", "unix-" +
633 time.strftime("%Y%m%d-%H%M%S"))
634 qemu_command += extra_params % self.migration_file
635 else:
636 qemu_command += extra_params
lmr6f669ce2009-05-31 19:02:42 +0000637
lmrdc2ac6a2009-06-10 19:15:49 +0000638 logging.debug("Running qemu command:\n%s", qemu_command)
lmra4967622009-07-23 01:36:32 +0000639 self.process = kvm_subprocess.run_bg(qemu_command, None,
640 logging.debug, "(qemu) ")
lmr6f669ce2009-05-31 19:02:42 +0000641
lmr9e964a02010-06-18 03:46:21 +0000642 # Make sure the process was started successfully
lmra4967622009-07-23 01:36:32 +0000643 if not self.process.is_alive():
644 logging.error("VM could not be created; "
645 "qemu command failed:\n%s" % qemu_command)
646 logging.error("Status: %s" % self.process.get_status())
647 logging.error("Output:" + kvm_utils.format_str_for_message(
648 self.process.get_output()))
lmrdc2ac6a2009-06-10 19:15:49 +0000649 self.destroy()
650 return False
lmr6f669ce2009-05-31 19:02:42 +0000651
lmr9e964a02010-06-18 03:46:21 +0000652 # Establish monitor connections
653 self.monitors = []
654 for monitor_name in kvm_utils.get_sub_dict_names(params,
655 "monitors"):
656 monitor_params = kvm_utils.get_sub_dict(params, monitor_name)
657 # Wait for monitor connection to succeed
658 end_time = time.time() + timeout
659 while time.time() < end_time:
660 try:
661 if monitor_params.get("monitor_type") == "qmp":
lmr449d2252010-06-18 03:48:23 +0000662 # Add a QMP monitor
663 monitor = kvm_monitor.QMPMonitor(
664 monitor_name,
665 self.get_monitor_filename(monitor_name))
lmr9e964a02010-06-18 03:46:21 +0000666 else:
667 # Add a "human" monitor
668 monitor = kvm_monitor.HumanMonitor(
669 monitor_name,
670 self.get_monitor_filename(monitor_name))
671 except kvm_monitor.MonitorError, e:
672 logging.warn(e)
673 else:
lmr449d2252010-06-18 03:48:23 +0000674 if monitor.is_responsive():
lmr9e964a02010-06-18 03:46:21 +0000675 break
676 time.sleep(1)
677 else:
678 logging.error("Could not connect to monitor '%s'" %
679 monitor_name)
680 self.destroy()
681 return False
682 # Add this monitor to the list
683 self.monitors += [monitor]
lmra4967622009-07-23 01:36:32 +0000684
lmrfe6515e2009-07-29 13:01:17 +0000685 # Get the output so far, to see if we have any problems with
lmrb306bf82010-07-08 23:47:00 +0000686 # KVM modules or with hugepage setup.
lmrfe6515e2009-07-29 13:01:17 +0000687 output = self.process.get_output()
688
lmrb306bf82010-07-08 23:47:00 +0000689 if re.search("Could not initialize KVM", output, re.IGNORECASE):
690 logging.error("Could not initialize KVM; "
691 "qemu command:\n%s" % qemu_command)
692 logging.error("Output:" + kvm_utils.format_str_for_message(
693 self.process.get_output()))
694 self.destroy()
695 return False
696
lmrfe6515e2009-07-29 13:01:17 +0000697 if "alloc_mem_area" in output:
698 logging.error("Could not allocate hugepage memory; "
699 "qemu command:\n%s" % qemu_command)
700 logging.error("Output:" + kvm_utils.format_str_for_message(
701 self.process.get_output()))
lmr090cd7a2010-04-01 02:18:52 +0000702 self.destroy()
lmrfe6515e2009-07-29 13:01:17 +0000703 return False
704
lmr71fa4de2010-06-14 15:54:55 +0000705 logging.debug("VM appears to be alive with PID %s", self.get_pid())
lmraa380a22010-06-22 02:05:29 +0000706
707 # Establish a session with the serial console -- requires a version
708 # of netcat that supports -U
709 self.serial_console = kvm_subprocess.kvm_shell_session(
710 "nc -U %s" % self.get_serial_console_filename(),
711 auto_close=False,
712 output_func=kvm_utils.log_line,
713 output_params=("serial-%s.log" % name,))
714
lmrdc2ac6a2009-06-10 19:15:49 +0000715 return True
716
717 finally:
718 fcntl.lockf(lockfile, fcntl.LOCK_UN)
719 lockfile.close()
lmr6f669ce2009-05-31 19:02:42 +0000720
721
lmr6f669ce2009-05-31 19:02:42 +0000722 def destroy(self, gracefully=True):
723 """
724 Destroy the VM.
725
lmr912c74b2009-08-17 20:43:27 +0000726 If gracefully is True, first attempt to shutdown the VM with a shell
727 command. Then, attempt to destroy the VM via the monitor with a 'quit'
728 command. If that fails, send SIGKILL to the qemu process.
lmr6f669ce2009-05-31 19:02:42 +0000729
730 @param gracefully: Whether an attempt will be made to end the VM
lmr912c74b2009-08-17 20:43:27 +0000731 using a shell command before trying to end the qemu process
732 with a 'quit' or a kill signal.
lmr6f669ce2009-05-31 19:02:42 +0000733 """
lmrf320b042009-09-15 05:48:06 +0000734 try:
735 # Is it already dead?
736 if self.is_dead():
737 logging.debug("VM is already down")
738 return
lmr6f669ce2009-05-31 19:02:42 +0000739
lmr71fa4de2010-06-14 15:54:55 +0000740 logging.debug("Destroying VM with PID %s...", self.get_pid())
lmr6f669ce2009-05-31 19:02:42 +0000741
lmrf320b042009-09-15 05:48:06 +0000742 if gracefully and self.params.get("shutdown_command"):
743 # Try to destroy with shell command
744 logging.debug("Trying to shutdown VM with shell command...")
745 session = self.remote_login()
746 if session:
747 try:
748 # Send the shutdown command
749 session.sendline(self.params.get("shutdown_command"))
750 logging.debug("Shutdown command sent; waiting for VM "
751 "to go down...")
752 if kvm_utils.wait_for(self.is_dead, 60, 1, 1):
753 logging.debug("VM is down")
754 return
755 finally:
756 session.close()
lmr6f669ce2009-05-31 19:02:42 +0000757
lmr9e964a02010-06-18 03:46:21 +0000758 if self.monitor:
759 # Try to destroy with a monitor command
760 logging.debug("Trying to kill VM with monitor command...")
761 try:
762 self.monitor.quit()
763 except kvm_monitor.MonitorError, e:
764 logging.warn(e)
765 else:
766 # Wait for the VM to be really dead
767 if kvm_utils.wait_for(self.is_dead, 5, 0.5, 0.5):
768 logging.debug("VM is down")
769 return
lmrf320b042009-09-15 05:48:06 +0000770
771 # If the VM isn't dead yet...
772 logging.debug("Cannot quit normally; sending a kill to close the "
773 "deal...")
774 kvm_utils.kill_process_tree(self.process.get_pid(), 9)
lmr6f669ce2009-05-31 19:02:42 +0000775 # Wait for the VM to be really dead
776 if kvm_utils.wait_for(self.is_dead, 5, 0.5, 0.5):
777 logging.debug("VM is down")
lmr6f669ce2009-05-31 19:02:42 +0000778 return
779
lmrf320b042009-09-15 05:48:06 +0000780 logging.error("Process %s is a zombie!" % self.process.get_pid())
lmr6f669ce2009-05-31 19:02:42 +0000781
lmrf320b042009-09-15 05:48:06 +0000782 finally:
lmr9e964a02010-06-18 03:46:21 +0000783 self.monitors = []
lmr4513c432010-02-03 11:59:03 +0000784 if self.pci_assignable:
785 self.pci_assignable.release_devs()
lmrf320b042009-09-15 05:48:06 +0000786 if self.process:
787 self.process.close()
lmraa380a22010-06-22 02:05:29 +0000788 if self.serial_console:
789 self.serial_console.close()
lmr84546f22010-06-29 23:03:34 +0000790 for f in ([self.get_testlog_filename(),
791 self.get_serial_console_filename()] +
lmr9e964a02010-06-18 03:46:21 +0000792 self.get_monitor_filenames()):
793 try:
794 os.unlink(f)
795 except OSError:
796 pass
797
798
799 @property
800 def monitor(self):
801 """
802 Return the main monitor object, selected by the parameter main_monitor.
803 If main_monitor isn't defined, return the first monitor.
804 If no monitors exist, or if main_monitor refers to a nonexistent
805 monitor, return None.
806 """
807 for m in self.monitors:
808 if m.name == self.params.get("main_monitor"):
809 return m
810 if self.monitors and not self.params.get("main_monitor"):
811 return self.monitors[0]
lmr6f669ce2009-05-31 19:02:42 +0000812
813
814 def is_alive(self):
815 """
lmr9e964a02010-06-18 03:46:21 +0000816 Return True if the VM is alive and its monitor is responsive.
lmr6f669ce2009-05-31 19:02:42 +0000817 """
lmra4967622009-07-23 01:36:32 +0000818 # Check if the process is running
819 if self.is_dead():
lmr6f669ce2009-05-31 19:02:42 +0000820 return False
821 # Try sending a monitor command
lmr9e964a02010-06-18 03:46:21 +0000822 return bool(self.monitor) and self.monitor.is_responsive()
lmr6f669ce2009-05-31 19:02:42 +0000823
824
825 def is_dead(self):
826 """
lmra4967622009-07-23 01:36:32 +0000827 Return True if the qemu process is dead.
lmr6f669ce2009-05-31 19:02:42 +0000828 """
lmra4967622009-07-23 01:36:32 +0000829 return not self.process or not self.process.is_alive()
lmr6f669ce2009-05-31 19:02:42 +0000830
831
832 def get_params(self):
833 """
834 Return the VM's params dict. Most modified params take effect only
835 upon VM.create().
836 """
837 return self.params
838
839
lmr9e964a02010-06-18 03:46:21 +0000840 def get_monitor_filename(self, monitor_name):
841 """
842 Return the filename corresponding to a given monitor name.
843 """
844 return "/tmp/monitor-%s-%s" % (monitor_name, self.instance)
845
846
847 def get_monitor_filenames(self):
848 """
849 Return a list of all monitor filenames (as specified in the VM's
850 params).
851 """
852 return [self.get_monitor_filename(m) for m in
853 kvm_utils.get_sub_dict_names(self.params, "monitors")]
854
855
lmr2b06f332010-06-22 02:03:41 +0000856 def get_serial_console_filename(self):
857 """
858 Return the serial console filename.
859 """
860 return "/tmp/serial-%s" % self.instance
861
862
lmr9e964a02010-06-18 03:46:21 +0000863 def get_testlog_filename(self):
864 """
865 Return the testlog filename.
866 """
867 return "/tmp/testlog-%s" % self.instance
868
869
lmrf4696342009-08-13 04:06:33 +0000870 def get_address(self, index=0):
lmr6f669ce2009-05-31 19:02:42 +0000871 """
lmrf4696342009-08-13 04:06:33 +0000872 Return the address of a NIC of the guest, in host space.
lmr6f669ce2009-05-31 19:02:42 +0000873
lmrf4696342009-08-13 04:06:33 +0000874 If port redirection is used, return 'localhost' (the NIC has no IP
875 address of its own). Otherwise return the NIC's IP address.
876
877 @param index: Index of the NIC whose address is requested.
lmr6f669ce2009-05-31 19:02:42 +0000878 """
lmree90dd92009-08-13 04:13:39 +0000879 nics = kvm_utils.get_sub_dict_names(self.params, "nics")
880 nic_name = nics[index]
lmrf4696342009-08-13 04:06:33 +0000881 nic_params = kvm_utils.get_sub_dict(self.params, nic_name)
882 if nic_params.get("nic_mode") == "tap":
883 mac, ip = kvm_utils.get_mac_ip_pair_from_dict(nic_params)
lmree90dd92009-08-13 04:13:39 +0000884 if not mac:
885 logging.debug("MAC address unavailable")
886 return None
887 if not ip or nic_params.get("always_use_tcpdump") == "yes":
888 # Get the IP address from the cache
889 ip = self.address_cache.get(mac)
890 if not ip:
891 logging.debug("Could not find IP address for MAC address: "
892 "%s" % mac)
893 return None
894 # Make sure the IP address is assigned to this guest
895 nic_dicts = [kvm_utils.get_sub_dict(self.params, nic)
896 for nic in nics]
897 macs = [kvm_utils.get_mac_ip_pair_from_dict(dict)[0]
898 for dict in nic_dicts]
899 if not kvm_utils.verify_ip_address_ownership(ip, macs):
900 logging.debug("Could not verify MAC-IP address mapping: "
901 "%s ---> %s" % (mac, ip))
902 return None
lmrf4696342009-08-13 04:06:33 +0000903 return ip
904 else:
905 return "localhost"
lmr6f669ce2009-05-31 19:02:42 +0000906
907
lmree90dd92009-08-13 04:13:39 +0000908 def get_port(self, port, nic_index=0):
lmr6f669ce2009-05-31 19:02:42 +0000909 """
910 Return the port in host space corresponding to port in guest space.
911
912 @param port: Port number in host space.
lmree90dd92009-08-13 04:13:39 +0000913 @param nic_index: Index of the NIC.
lmr6f669ce2009-05-31 19:02:42 +0000914 @return: If port redirection is used, return the host port redirected
915 to guest port port. Otherwise return port.
916 """
lmree90dd92009-08-13 04:13:39 +0000917 nic_name = kvm_utils.get_sub_dict_names(self.params, "nics")[nic_index]
lmrf4696342009-08-13 04:06:33 +0000918 nic_params = kvm_utils.get_sub_dict(self.params, nic_name)
919 if nic_params.get("nic_mode") == "tap":
920 return port
lmr6f669ce2009-05-31 19:02:42 +0000921 else:
lmrf4696342009-08-13 04:06:33 +0000922 if not self.redirs.has_key(port):
923 logging.warn("Warning: guest port %s requested but not "
924 "redirected" % port)
925 return self.redirs.get(port)
lmr6f669ce2009-05-31 19:02:42 +0000926
927
lmra4967622009-07-23 01:36:32 +0000928 def get_pid(self):
929 """
lmr71fa4de2010-06-14 15:54:55 +0000930 Return the VM's PID. If the VM is dead return None.
931
932 @note: This works under the assumption that self.process.get_pid()
933 returns the PID of the parent shell process.
934 """
935 try:
936 children = commands.getoutput("ps --ppid=%d -o pid=" %
937 self.process.get_pid()).split()
938 return int(children[0])
939 except (TypeError, IndexError, ValueError):
940 return None
941
942
943 def get_shell_pid(self):
944 """
945 Return the PID of the parent shell process.
946
947 @note: This works under the assumption that self.process.get_pid()
948 returns the PID of the parent shell process.
lmra4967622009-07-23 01:36:32 +0000949 """
950 return self.process.get_pid()
951
952
lmr0bee2342010-02-24 00:01:37 +0000953 def get_shared_meminfo(self):
954 """
955 Returns the VM's shared memory information.
956
957 @return: Shared memory used by VM (MB)
958 """
959 if self.is_dead():
960 logging.error("Could not get shared memory info from dead VM.")
961 return None
962
lmr983ecdf2010-06-14 15:57:12 +0000963 filename = "/proc/%d/statm" % self.get_pid()
964 shm = int(open(filename).read().split()[2])
lmr0bee2342010-02-24 00:01:37 +0000965 # statm stores informations in pages, translate it to MB
lmr983ecdf2010-06-14 15:57:12 +0000966 return shm * 4.0 / 1024
lmr0bee2342010-02-24 00:01:37 +0000967
968
lmr912c74b2009-08-17 20:43:27 +0000969 def remote_login(self, nic_index=0, timeout=10):
lmr6f669ce2009-05-31 19:02:42 +0000970 """
lmr912c74b2009-08-17 20:43:27 +0000971 Log into the guest via SSH/Telnet/Netcat.
lmr6f669ce2009-05-31 19:02:42 +0000972 If timeout expires while waiting for output from the guest (e.g. a
973 password prompt or a shell prompt) -- fail.
974
lmree90dd92009-08-13 04:13:39 +0000975 @param nic_index: The index of the NIC to connect to.
lmr6f669ce2009-05-31 19:02:42 +0000976 @param timeout: Time (seconds) before giving up logging into the
977 guest.
978 @return: kvm_spawn object on success and None on failure.
979 """
980 username = self.params.get("username", "")
981 password = self.params.get("password", "")
lmr912c74b2009-08-17 20:43:27 +0000982 prompt = self.params.get("shell_prompt", "[\#\$]")
lmr59f9e2d2009-10-05 18:47:16 +0000983 linesep = eval("'%s'" % self.params.get("shell_linesep", r"\n"))
lmr912c74b2009-08-17 20:43:27 +0000984 client = self.params.get("shell_client")
lmree90dd92009-08-13 04:13:39 +0000985 address = self.get_address(nic_index)
lmr912c74b2009-08-17 20:43:27 +0000986 port = self.get_port(int(self.params.get("shell_port")))
lmre56903f2010-06-22 02:09:35 +0000987 log_filename = ("session-%s-%s.log" %
988 (self.name, kvm_utils.generate_random_string(4)))
lmr912c74b2009-08-17 20:43:27 +0000989
lmree90dd92009-08-13 04:13:39 +0000990 if not address or not port:
991 logging.debug("IP address or port unavailable")
lmr6f669ce2009-05-31 19:02:42 +0000992 return None
993
lmr158604f2010-06-22 01:57:34 +0000994 session = kvm_utils.remote_login(client, address, port, username,
lmre56903f2010-06-22 02:09:35 +0000995 password, prompt, linesep,
996 log_filename, timeout)
lmr912c74b2009-08-17 20:43:27 +0000997
lmr6f669ce2009-05-31 19:02:42 +0000998 if session:
lmr912c74b2009-08-17 20:43:27 +0000999 session.set_status_test_command(self.params.get("status_test_"
lmr6f669ce2009-05-31 19:02:42 +00001000 "command", ""))
1001 return session
1002
1003
lmrc196d492010-05-07 14:14:26 +00001004 def copy_files_to(self, local_path, remote_path, nic_index=0, timeout=600):
lmr6f669ce2009-05-31 19:02:42 +00001005 """
lmr912c74b2009-08-17 20:43:27 +00001006 Transfer files to the guest.
lmr6f669ce2009-05-31 19:02:42 +00001007
1008 @param local_path: Host path
1009 @param remote_path: Guest path
lmr912c74b2009-08-17 20:43:27 +00001010 @param nic_index: The index of the NIC to connect to.
lmr6f669ce2009-05-31 19:02:42 +00001011 @param timeout: Time (seconds) before giving up on doing the remote
1012 copy.
1013 """
1014 username = self.params.get("username", "")
1015 password = self.params.get("password", "")
lmr912c74b2009-08-17 20:43:27 +00001016 client = self.params.get("file_transfer_client")
lmree90dd92009-08-13 04:13:39 +00001017 address = self.get_address(nic_index)
lmr912c74b2009-08-17 20:43:27 +00001018 port = self.get_port(int(self.params.get("file_transfer_port")))
1019
lmree90dd92009-08-13 04:13:39 +00001020 if not address or not port:
1021 logging.debug("IP address or port unavailable")
lmr6f669ce2009-05-31 19:02:42 +00001022 return None
lmr912c74b2009-08-17 20:43:27 +00001023
1024 if client == "scp":
lmrcbc86ef2010-07-07 20:50:08 +00001025 log_filename = ("scp-%s-%s.log" %
1026 (self.name, kvm_utils.generate_random_string(4)))
lmr912c74b2009-08-17 20:43:27 +00001027 return kvm_utils.scp_to_remote(address, port, username, password,
lmre56903f2010-06-22 02:09:35 +00001028 local_path, remote_path,
1029 log_filename, timeout)
lmrcbc86ef2010-07-07 20:50:08 +00001030 elif client == "rss":
1031 c = rss_file_transfer.FileUploadClient(address, port)
1032 c.upload(local_path, remote_path, timeout)
1033 c.close()
1034 return True
lmr6f669ce2009-05-31 19:02:42 +00001035
1036
lmrc196d492010-05-07 14:14:26 +00001037 def copy_files_from(self, remote_path, local_path, nic_index=0, timeout=600):
lmr6f669ce2009-05-31 19:02:42 +00001038 """
lmr912c74b2009-08-17 20:43:27 +00001039 Transfer files from the guest.
lmr6f669ce2009-05-31 19:02:42 +00001040
1041 @param local_path: Guest path
1042 @param remote_path: Host path
lmr912c74b2009-08-17 20:43:27 +00001043 @param nic_index: The index of the NIC to connect to.
lmr6f669ce2009-05-31 19:02:42 +00001044 @param timeout: Time (seconds) before giving up on doing the remote
1045 copy.
1046 """
1047 username = self.params.get("username", "")
1048 password = self.params.get("password", "")
lmr912c74b2009-08-17 20:43:27 +00001049 client = self.params.get("file_transfer_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("file_transfer_port")))
1052
lmree90dd92009-08-13 04:13:39 +00001053 if not address or not port:
1054 logging.debug("IP address or port unavailable")
lmr6f669ce2009-05-31 19:02:42 +00001055 return None
lmr6f669ce2009-05-31 19:02:42 +00001056
lmr912c74b2009-08-17 20:43:27 +00001057 if client == "scp":
lmrcbc86ef2010-07-07 20:50:08 +00001058 log_filename = ("scp-%s-%s.log" %
1059 (self.name, kvm_utils.generate_random_string(4)))
lmr912c74b2009-08-17 20:43:27 +00001060 return kvm_utils.scp_from_remote(address, port, username, password,
lmre56903f2010-06-22 02:09:35 +00001061 remote_path, local_path,
1062 log_filename, timeout)
lmrcbc86ef2010-07-07 20:50:08 +00001063 elif client == "rss":
1064 c = rss_file_transfer.FileDownloadClient(address, port)
1065 c.download(remote_path, local_path, timeout)
1066 c.close()
1067 return True
lmr6f669ce2009-05-31 19:02:42 +00001068
1069
lmraa380a22010-06-22 02:05:29 +00001070 def serial_login(self, timeout=10):
1071 """
1072 Log into the guest via the serial console.
1073 If timeout expires while waiting for output from the guest (e.g. a
1074 password prompt or a shell prompt) -- fail.
1075
1076 @param timeout: Time (seconds) before giving up logging into the guest.
1077 @return: kvm_spawn object on success and None on failure.
1078 """
1079 username = self.params.get("username", "")
1080 password = self.params.get("password", "")
1081 prompt = self.params.get("shell_prompt", "[\#\$]")
1082 linesep = eval("'%s'" % self.params.get("shell_linesep", r"\n"))
1083 status_test_command = self.params.get("status_test_command", "")
1084
1085 if self.serial_console:
1086 self.serial_console.set_linesep(linesep)
1087 self.serial_console.set_status_test_command(status_test_command)
1088 else:
1089 return None
1090
1091 # Make sure we get a login prompt
1092 self.serial_console.sendline()
1093
1094 if kvm_utils._remote_login(self.serial_console, username, password,
1095 prompt, timeout):
1096 return self.serial_console
1097
1098
lmr6f669ce2009-05-31 19:02:42 +00001099 def send_key(self, keystr):
1100 """
1101 Send a key event to the VM.
1102
1103 @param: keystr: A key event string (e.g. "ctrl-alt-delete")
1104 """
1105 # For compatibility with versions of QEMU that do not recognize all
1106 # key names: replace keyname with the hex value from the dict, which
1107 # QEMU will definitely accept
lmr9e964a02010-06-18 03:46:21 +00001108 dict = {"comma": "0x33",
1109 "dot": "0x34",
1110 "slash": "0x35"}
1111 for key, value in dict.items():
1112 keystr = keystr.replace(key, value)
1113 self.monitor.sendkey(keystr)
lmr6f669ce2009-05-31 19:02:42 +00001114 time.sleep(0.2)
1115
1116
1117 def send_string(self, str):
1118 """
1119 Send a string to the VM.
1120
1121 @param str: String, that must consist of alphanumeric characters only.
1122 Capital letters are allowed.
1123 """
1124 for char in str:
1125 if char.isupper():
1126 self.send_key("shift-%s" % char.lower())
1127 else:
1128 self.send_key(char)
lmra2533222009-07-20 12:43:46 +00001129
mbligh1ef218d2009-08-03 16:57:56 +00001130
lmra2533222009-07-20 12:43:46 +00001131 def get_uuid(self):
1132 """
1133 Catch UUID of the VM.
1134
1135 @return: None,if not specified in config file
1136 """
1137 if self.params.get("uuid") == "random":
1138 return self.uuid
1139 else:
1140 return self.params.get("uuid", None)
lmrdd2ff922009-12-01 23:39:12 +00001141
1142
1143 def get_cpu_count(self):
1144 """
1145 Get the cpu count of the VM.
1146 """
lmr13426552010-01-17 15:38:41 +00001147 session = self.remote_login()
1148 if not session:
1149 return None
lmrdd2ff922009-12-01 23:39:12 +00001150 try:
lmr13426552010-01-17 15:38:41 +00001151 cmd = self.params.get("cpu_chk_cmd")
1152 s, count = session.get_command_status_output(cmd)
1153 if s == 0:
1154 return int(count)
lmrdd2ff922009-12-01 23:39:12 +00001155 return None
1156 finally:
1157 session.close()
1158
1159
lmr28426c82010-04-16 06:02:58 +00001160 def get_memory_size(self, cmd=None):
lmrdd2ff922009-12-01 23:39:12 +00001161 """
lmr28426c82010-04-16 06:02:58 +00001162 Get bootup memory size of the VM.
1163
1164 @param check_cmd: Command used to check memory. If not provided,
1165 self.params.get("mem_chk_cmd") will be used.
lmrdd2ff922009-12-01 23:39:12 +00001166 """
lmr13426552010-01-17 15:38:41 +00001167 session = self.remote_login()
1168 if not session:
lmrdd2ff922009-12-01 23:39:12 +00001169 return None
lmr13426552010-01-17 15:38:41 +00001170 try:
lmr28426c82010-04-16 06:02:58 +00001171 if not cmd:
1172 cmd = self.params.get("mem_chk_cmd")
lmr13426552010-01-17 15:38:41 +00001173 s, mem_str = session.get_command_status_output(cmd)
1174 if s != 0:
1175 return None
lmr6d69f4d2010-02-12 11:35:55 +00001176 mem = re.findall("([0-9]+)", mem_str)
lmr13426552010-01-17 15:38:41 +00001177 mem_size = 0
1178 for m in mem:
1179 mem_size += int(m)
1180 if "GB" in mem_str:
1181 mem_size *= 1024
1182 elif "MB" in mem_str:
1183 pass
1184 else:
1185 mem_size /= 1024
1186 return int(mem_size)
lmrdd2ff922009-12-01 23:39:12 +00001187 finally:
1188 session.close()
lmr28426c82010-04-16 06:02:58 +00001189
1190
1191 def get_current_memory_size(self):
1192 """
1193 Get current memory size of the VM, rather than bootup memory.
1194 """
1195 cmd = self.params.get("mem_chk_cur_cmd")
1196 return self.get_memory_size(cmd)