blob: bdc9aabcff2ae65f6bf6116ee54feb5923129dd1 [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):
Benson Leung517d95a2010-09-28 18:00:17 -0700238 cmd = " -net nic,vlan=%d" % vlan
lmrb1cad1e2010-06-17 17:36:09 +0000239 if has_option(help, "netdev"):
Benson Leung517d95a2010-09-28 18:00:17 -0700240 cmd +=",netdev=%s" % netdev_id
lmr48abd7d2010-05-26 13:48:04 +0000241 if model: cmd += ",model=%s" % model
lmr09a78162010-06-14 16:29:23 +0000242 if mac: cmd += ",macaddr='%s'" % mac
lmr48abd7d2010-05-26 13:48:04 +0000243 return cmd
244
245 def add_net(help, vlan, mode, ifname=None, script=None,
lmr6976faa2010-07-09 21:11:06 +0000246 downscript=None, tftp=None, bootfile=None, hostfwd=[],
247 netdev_id=None):
lmrb1cad1e2010-06-17 17:36:09 +0000248 if has_option(help, "netdev"):
249 cmd = " -netdev %s,id=%s" % (mode, netdev_id)
250 else:
251 cmd = " -net %s,vlan=%d" % (mode, vlan)
lmr48abd7d2010-05-26 13:48:04 +0000252 if mode == "tap":
lmr09a78162010-06-14 16:29:23 +0000253 if ifname: cmd += ",ifname='%s'" % ifname
254 if script: cmd += ",script='%s'" % script
255 cmd += ",downscript='%s'" % (downscript or "no")
lmr6976faa2010-07-09 21:11:06 +0000256 elif mode == "user":
257 if tftp and "[,tftp=" in help:
258 cmd += ",tftp='%s'" % tftp
259 if bootfile and "[,bootfile=" in help:
260 cmd += ",bootfile='%s'" % bootfile
261 if "[,hostfwd=" in help:
262 for host_port, guest_port in hostfwd:
263 cmd += ",hostfwd=tcp::%s-:%s" % (host_port, guest_port)
lmr48abd7d2010-05-26 13:48:04 +0000264 return cmd
265
266 def add_floppy(help, filename):
lmr09a78162010-06-14 16:29:23 +0000267 return " -fda '%s'" % filename
lmr48abd7d2010-05-26 13:48:04 +0000268
269 def add_tftp(help, filename):
lmr6976faa2010-07-09 21:11:06 +0000270 # If the new syntax is supported, don't add -tftp
271 if "[,tftp=" in help:
272 return ""
273 else:
274 return " -tftp '%s'" % filename
275
276 def add_bootp(help, filename):
277 # If the new syntax is supported, don't add -bootp
278 if "[,bootfile=" in help:
279 return ""
280 else:
281 return " -bootp '%s'" % filename
lmr48abd7d2010-05-26 13:48:04 +0000282
283 def add_tcp_redir(help, host_port, guest_port):
lmr6976faa2010-07-09 21:11:06 +0000284 # If the new syntax is supported, don't add -redir
285 if "[,hostfwd=" in help:
286 return ""
287 else:
288 return " -redir tcp:%s::%s" % (host_port, guest_port)
lmr48abd7d2010-05-26 13:48:04 +0000289
290 def add_vnc(help, vnc_port):
291 return " -vnc :%d" % (vnc_port - 5900)
292
293 def add_sdl(help):
294 if has_option(help, "sdl"):
295 return " -sdl"
296 else:
297 return ""
298
299 def add_nographic(help):
300 return " -nographic"
301
302 def add_uuid(help, uuid):
lmr09a78162010-06-14 16:29:23 +0000303 return " -uuid '%s'" % uuid
lmr48abd7d2010-05-26 13:48:04 +0000304
305 def add_pcidevice(help, host):
lmr09a78162010-06-14 16:29:23 +0000306 return " -pcidevice host='%s'" % host
lmr48abd7d2010-05-26 13:48:04 +0000307
lmr41cb8fc2010-06-10 15:30:45 +0000308 def add_kernel(help, filename):
lmr09a78162010-06-14 16:29:23 +0000309 return " -kernel '%s'" % filename
lmr41cb8fc2010-06-10 15:30:45 +0000310
311 def add_initrd(help, filename):
lmr09a78162010-06-14 16:29:23 +0000312 return " -initrd '%s'" % filename
lmr41cb8fc2010-06-10 15:30:45 +0000313
lmre0474e32010-06-29 14:10:09 +0000314 def add_kernel_cmdline(help, cmdline):
315 return " -append %s" % cmdline
316
lmr71024552010-06-29 14:12:35 +0000317 def add_testdev(help, filename):
318 return (" -chardev file,id=testlog,path=%s"
319 " -device testdev,chardev=testlog" % filename)
320
lmrce5c9252010-06-30 17:41:00 +0000321 def add_no_hpet(help):
322 if has_option(help, "no-hpet"):
323 return " -no-hpet"
324 else:
325 return ""
326
lmr48abd7d2010-05-26 13:48:04 +0000327 # End of command line option wrappers
328
329 if name is None: name = self.name
330 if params is None: params = self.params
331 if root_dir is None: root_dir = self.root_dir
332
333 qemu_binary = kvm_utils.get_path(root_dir, params.get("qemu_binary",
334 "qemu"))
335 # Get the output of 'qemu -help' (log a message in case this call never
336 # returns or causes some other kind of trouble)
337 logging.debug("Getting output of 'qemu -help'")
338 help = commands.getoutput("%s -help" % qemu_binary)
lmr6f669ce2009-05-31 19:02:42 +0000339
lmreeff0eb2009-06-10 19:19:15 +0000340 # Start constructing the qemu command
341 qemu_cmd = ""
342 # Set the X11 display parameter if requested
343 if params.get("x11_display"):
344 qemu_cmd += "DISPLAY=%s " % params.get("x11_display")
345 # Add the qemu binary
lmr48abd7d2010-05-26 13:48:04 +0000346 qemu_cmd += qemu_binary
lmreeff0eb2009-06-10 19:19:15 +0000347 # Add the VM's name
lmr48abd7d2010-05-26 13:48:04 +0000348 qemu_cmd += add_name(help, name)
lmr9e964a02010-06-18 03:46:21 +0000349 # Add monitors
350 for monitor_name in kvm_utils.get_sub_dict_names(params, "monitors"):
351 monitor_params = kvm_utils.get_sub_dict(params, monitor_name)
352 monitor_filename = self.get_monitor_filename(monitor_name)
353 if monitor_params.get("monitor_type") == "qmp":
354 qemu_cmd += add_qmp_monitor(help, monitor_filename)
355 else:
356 qemu_cmd += add_human_monitor(help, monitor_filename)
lmr6f669ce2009-05-31 19:02:42 +0000357
lmr2b06f332010-06-22 02:03:41 +0000358 # Add serial console redirection
359 qemu_cmd += add_serial(help, self.get_serial_console_filename())
360
lmr6f669ce2009-05-31 19:02:42 +0000361 for image_name in kvm_utils.get_sub_dict_names(params, "images"):
362 image_params = kvm_utils.get_sub_dict(params, image_name)
lmr9d75ee32009-09-29 13:14:13 +0000363 if image_params.get("boot_drive") == "no":
364 continue
lmr48abd7d2010-05-26 13:48:04 +0000365 qemu_cmd += add_drive(help,
366 get_image_filename(image_params, root_dir),
lmraf709702010-07-20 00:56:33 +0000367 image_params.get("drive_index"),
lmr48abd7d2010-05-26 13:48:04 +0000368 image_params.get("drive_format"),
369 image_params.get("drive_cache"),
370 image_params.get("drive_werror"),
371 image_params.get("drive_serial"),
372 image_params.get("image_snapshot") == "yes",
373 image_params.get("image_boot") == "yes")
lmr6f669ce2009-05-31 19:02:42 +0000374
lmr6976faa2010-07-09 21:11:06 +0000375 redirs = []
376 for redir_name in kvm_utils.get_sub_dict_names(params, "redirs"):
377 redir_params = kvm_utils.get_sub_dict(params, redir_name)
378 guest_port = int(redir_params.get("guest_port"))
379 host_port = self.redirs.get(guest_port)
380 redirs += [(host_port, guest_port)]
381
lmr6f669ce2009-05-31 19:02:42 +0000382 vlan = 0
383 for nic_name in kvm_utils.get_sub_dict_names(params, "nics"):
384 nic_params = kvm_utils.get_sub_dict(params, nic_name)
lmrf4696342009-08-13 04:06:33 +0000385 # Handle the '-net nic' part
lmr48abd7d2010-05-26 13:48:04 +0000386 mac = None
387 if "address_index" in nic_params:
388 mac = kvm_utils.get_mac_ip_pair_from_dict(nic_params)[0]
lmrb1cad1e2010-06-17 17:36:09 +0000389 qemu_cmd += add_nic(help, vlan, nic_params.get("nic_model"), mac,
390 self.netdev_id[vlan])
lmrf4696342009-08-13 04:06:33 +0000391 # Handle the '-net tap' or '-net user' part
lmre4eaa862010-06-01 19:15:14 +0000392 script = nic_params.get("nic_script")
393 downscript = nic_params.get("nic_downscript")
lmr6976faa2010-07-09 21:11:06 +0000394 tftp = nic_params.get("tftp")
lmr48abd7d2010-05-26 13:48:04 +0000395 if script:
396 script = kvm_utils.get_path(root_dir, script)
397 if downscript:
398 downscript = kvm_utils.get_path(root_dir, downscript)
lmr6976faa2010-07-09 21:11:06 +0000399 if tftp:
400 tftp = kvm_utils.get_path(root_dir, tftp)
lmr48abd7d2010-05-26 13:48:04 +0000401 qemu_cmd += add_net(help, vlan, nic_params.get("nic_mode", "user"),
402 nic_params.get("nic_ifname"),
lmr6976faa2010-07-09 21:11:06 +0000403 script, downscript, tftp,
404 nic_params.get("bootp"), redirs,
405 self.netdev_id[vlan])
lmrf4696342009-08-13 04:06:33 +0000406 # Proceed to next NIC
lmr6f669ce2009-05-31 19:02:42 +0000407 vlan += 1
408
409 mem = params.get("mem")
410 if mem:
lmr48abd7d2010-05-26 13:48:04 +0000411 qemu_cmd += add_mem(help, mem)
lmr6f669ce2009-05-31 19:02:42 +0000412
lmrc43bf372009-11-10 13:19:00 +0000413 smp = params.get("smp")
414 if smp:
lmrdb3fe612010-06-14 16:19:28 +0000415 qemu_cmd += add_smp(help, smp)
lmrc43bf372009-11-10 13:19:00 +0000416
lmrac5dce72010-07-20 00:58:25 +0000417 cdroms = kvm_utils.get_sub_dict_names(params, "cdroms")
418 for cdrom in cdroms:
419 cdrom_params = kvm_utils.get_sub_dict(params, cdrom)
420 iso = cdrom_params.get("cdrom")
421 if iso:
422 qemu_cmd += add_cdrom(help, kvm_utils.get_path(root_dir, iso),
423 cdrom_params.get("drive_index"))
lmr6f669ce2009-05-31 19:02:42 +0000424
lmrb0a9b762009-10-09 20:43:30 +0000425 # We may want to add {floppy_otps} parameter for -fda
lmr48abd7d2010-05-26 13:48:04 +0000426 # {fat:floppy:}/path/. However vvfat is not usually recommended.
lmrb0a9b762009-10-09 20:43:30 +0000427 floppy = params.get("floppy")
428 if floppy:
lmrf69f6b12009-11-10 16:33:44 +0000429 floppy = kvm_utils.get_path(root_dir, floppy)
lmr48abd7d2010-05-26 13:48:04 +0000430 qemu_cmd += add_floppy(help, floppy)
lmrb0a9b762009-10-09 20:43:30 +0000431
432 tftp = params.get("tftp")
lmr62fc2bb2010-07-08 23:45:11 +0000433 if tftp:
lmrf69f6b12009-11-10 16:33:44 +0000434 tftp = kvm_utils.get_path(root_dir, tftp)
lmr48abd7d2010-05-26 13:48:04 +0000435 qemu_cmd += add_tftp(help, tftp)
lmr6f669ce2009-05-31 19:02:42 +0000436
lmr6976faa2010-07-09 21:11:06 +0000437 bootp = params.get("bootp")
438 if bootp:
439 qemu_cmd += add_bootp(help, bootp)
440
lmr41cb8fc2010-06-10 15:30:45 +0000441 kernel = params.get("kernel")
442 if kernel:
443 kernel = kvm_utils.get_path(root_dir, kernel)
444 qemu_cmd += add_kernel(help, kernel)
445
lmre0474e32010-06-29 14:10:09 +0000446 kernel_cmdline = params.get("kernel_cmdline")
447 if kernel_cmdline:
448 qemu_cmd += add_kernel_cmdline(help, kernel_cmdline)
449
lmr41cb8fc2010-06-10 15:30:45 +0000450 initrd = params.get("initrd")
451 if initrd:
452 initrd = kvm_utils.get_path(root_dir, initrd)
453 qemu_cmd += add_initrd(help, initrd)
454
lmr6976faa2010-07-09 21:11:06 +0000455 for host_port, guest_port in redirs:
lmr48abd7d2010-05-26 13:48:04 +0000456 qemu_cmd += add_tcp_redir(help, host_port, guest_port)
lmr6f669ce2009-05-31 19:02:42 +0000457
458 if params.get("display") == "vnc":
lmr48abd7d2010-05-26 13:48:04 +0000459 qemu_cmd += add_vnc(help, self.vnc_port)
lmr6f669ce2009-05-31 19:02:42 +0000460 elif params.get("display") == "sdl":
lmr48abd7d2010-05-26 13:48:04 +0000461 qemu_cmd += add_sdl(help)
lmr6f669ce2009-05-31 19:02:42 +0000462 elif params.get("display") == "nographic":
lmr48abd7d2010-05-26 13:48:04 +0000463 qemu_cmd += add_nographic(help)
lmr6f669ce2009-05-31 19:02:42 +0000464
lmra2533222009-07-20 12:43:46 +0000465 if params.get("uuid") == "random":
lmr48abd7d2010-05-26 13:48:04 +0000466 qemu_cmd += add_uuid(help, self.uuid)
lmra2533222009-07-20 12:43:46 +0000467 elif params.get("uuid"):
lmr48abd7d2010-05-26 13:48:04 +0000468 qemu_cmd += add_uuid(help, params.get("uuid"))
lmra2533222009-07-20 12:43:46 +0000469
lmr71024552010-06-29 14:12:35 +0000470 if params.get("testdev") == "yes":
471 qemu_cmd += add_testdev(help, self.get_testlog_filename())
472
lmrce5c9252010-06-30 17:41:00 +0000473 if params.get("disable_hpet") == "yes":
474 qemu_cmd += add_no_hpet(help)
475
lmr31af3a12010-01-18 16:46:52 +0000476 # If the PCI assignment step went OK, add each one of the PCI assigned
477 # devices to the qemu command line.
478 if self.pci_assignable:
479 for pci_id in self.pa_pci_ids:
lmr48abd7d2010-05-26 13:48:04 +0000480 qemu_cmd += add_pcidevice(help, pci_id)
481
482 extra_params = params.get("extra_params")
483 if extra_params:
484 qemu_cmd += " %s" % extra_params
lmr31af3a12010-01-18 16:46:52 +0000485
lmr6f669ce2009-05-31 19:02:42 +0000486 return qemu_cmd
487
488
lmr52800ba2009-08-17 20:49:58 +0000489 def create(self, name=None, params=None, root_dir=None,
lmr1424f3e2010-06-17 13:57:09 +0000490 for_migration=False, timeout=5.0, extra_params=None):
lmr6f669ce2009-05-31 19:02:42 +0000491 """
492 Start the VM by running a qemu command.
493 All parameters are optional. The following applies to all parameters
494 but for_migration: If a parameter is not supplied, the corresponding
495 value stored in the class attributes is used, and if it is supplied,
496 it is stored for later use.
497
498 @param name: The name of the object
499 @param params: A dict containing VM params
lmr90b9fd52009-08-17 20:48:18 +0000500 @param root_dir: Base directory for relative filenames
lmr6f669ce2009-05-31 19:02:42 +0000501 @param for_migration: If True, start the VM with the -incoming
502 option
lmr1424f3e2010-06-17 13:57:09 +0000503 @param extra_params: extra params for qemu command.e.g -incoming option
504 Please use this parameter instead of for_migration.
lmr6f669ce2009-05-31 19:02:42 +0000505 """
lmr135b5e62009-06-10 19:22:31 +0000506 self.destroy()
507
lmre45a1f22009-11-10 16:35:08 +0000508 if name is not None:
lmr6f669ce2009-05-31 19:02:42 +0000509 self.name = name
lmre45a1f22009-11-10 16:35:08 +0000510 if params is not None:
lmr6f669ce2009-05-31 19:02:42 +0000511 self.params = params
lmre45a1f22009-11-10 16:35:08 +0000512 if root_dir is not None:
lmr90b9fd52009-08-17 20:48:18 +0000513 self.root_dir = root_dir
lmr6f669ce2009-05-31 19:02:42 +0000514 name = self.name
515 params = self.params
lmr90b9fd52009-08-17 20:48:18 +0000516 root_dir = self.root_dir
lmr6f669ce2009-05-31 19:02:42 +0000517
518 # Verify the md5sum of the ISO image
519 iso = params.get("cdrom")
520 if iso:
lmr90b9fd52009-08-17 20:48:18 +0000521 iso = kvm_utils.get_path(root_dir, iso)
lmr6f669ce2009-05-31 19:02:42 +0000522 if not os.path.exists(iso):
523 logging.error("ISO file not found: %s" % iso)
524 return False
525 compare = False
526 if params.get("md5sum_1m"):
lmrf4696342009-08-13 04:06:33 +0000527 logging.debug("Comparing expected MD5 sum with MD5 sum of "
528 "first MB of ISO file...")
lmrd60882f2010-02-04 03:26:36 +0000529 actual_hash = utils.hash_file(iso, 1048576, method="md5")
lmr03ba22e2009-10-23 12:07:44 +0000530 expected_hash = params.get("md5sum_1m")
lmr6f669ce2009-05-31 19:02:42 +0000531 compare = True
532 elif params.get("md5sum"):
lmrf4696342009-08-13 04:06:33 +0000533 logging.debug("Comparing expected MD5 sum with MD5 sum of ISO "
534 "file...")
lmrd60882f2010-02-04 03:26:36 +0000535 actual_hash = utils.hash_file(iso, method="md5")
lmr03ba22e2009-10-23 12:07:44 +0000536 expected_hash = params.get("md5sum")
537 compare = True
538 elif params.get("sha1sum"):
539 logging.debug("Comparing expected SHA1 sum with SHA1 sum of "
540 "ISO file...")
lmrd60882f2010-02-04 03:26:36 +0000541 actual_hash = utils.hash_file(iso, method="sha1")
lmrea1266e2009-11-10 16:41:08 +0000542 expected_hash = params.get("sha1sum")
lmr6f669ce2009-05-31 19:02:42 +0000543 compare = True
544 if compare:
lmr03ba22e2009-10-23 12:07:44 +0000545 if actual_hash == expected_hash:
546 logging.debug("Hashes match")
lmr6f669ce2009-05-31 19:02:42 +0000547 else:
lmr03ba22e2009-10-23 12:07:44 +0000548 logging.error("Actual hash differs from expected one")
lmr6f669ce2009-05-31 19:02:42 +0000549 return False
550
lmrdc2ac6a2009-06-10 19:15:49 +0000551 # Make sure the following code is not executed by more than one thread
552 # at the same time
553 lockfile = open("/tmp/kvm-autotest-vm-create.lock", "w+")
554 fcntl.lockf(lockfile, fcntl.LOCK_EX)
lmr6f669ce2009-05-31 19:02:42 +0000555
lmrdc2ac6a2009-06-10 19:15:49 +0000556 try:
557 # Handle port redirections
558 redir_names = kvm_utils.get_sub_dict_names(params, "redirs")
559 host_ports = kvm_utils.find_free_ports(5000, 6000, len(redir_names))
560 self.redirs = {}
561 for i in range(len(redir_names)):
562 redir_params = kvm_utils.get_sub_dict(params, redir_names[i])
563 guest_port = int(redir_params.get("guest_port"))
564 self.redirs[guest_port] = host_ports[i]
lmr6f669ce2009-05-31 19:02:42 +0000565
lmr48349072010-06-29 14:14:55 +0000566 for nic in kvm_utils.get_sub_dict_names(params, "nics"):
567 self.netdev_id.append(kvm_utils.generate_random_id())
568
lmrdc2ac6a2009-06-10 19:15:49 +0000569 # Find available VNC port, if needed
570 if params.get("display") == "vnc":
lmrc0da8902010-05-17 20:31:36 +0000571 self.vnc_port = kvm_utils.find_free_port(5900, 6100)
lmr6f669ce2009-05-31 19:02:42 +0000572
lmra2533222009-07-20 12:43:46 +0000573 # Find random UUID if specified 'uuid = random' in config file
574 if params.get("uuid") == "random":
575 f = open("/proc/sys/kernel/random/uuid")
576 self.uuid = f.read().strip()
577 f.close()
578
lmr31ed61d2010-06-07 13:21:38 +0000579 # Assign a PCI assignable device
580 self.pci_assignable = None
581 pa_type = params.get("pci_assignable")
582 if pa_type in ["vf", "pf", "mixed"]:
lmr31af3a12010-01-18 16:46:52 +0000583 pa_devices_requested = params.get("devices_requested")
584
585 # Virtual Functions (VF) assignable devices
586 if pa_type == "vf":
lmr31ed61d2010-06-07 13:21:38 +0000587 self.pci_assignable = kvm_utils.PciAssignable(
588 type=pa_type,
589 driver=params.get("driver"),
590 driver_option=params.get("driver_option"),
591 devices_requested=pa_devices_requested)
lmr31af3a12010-01-18 16:46:52 +0000592 # Physical NIC (PF) assignable devices
593 elif pa_type == "pf":
lmr31ed61d2010-06-07 13:21:38 +0000594 self.pci_assignable = kvm_utils.PciAssignable(
595 type=pa_type,
596 names=params.get("device_names"),
597 devices_requested=pa_devices_requested)
lmr31af3a12010-01-18 16:46:52 +0000598 # Working with both VF and PF
599 elif pa_type == "mixed":
lmr31ed61d2010-06-07 13:21:38 +0000600 self.pci_assignable = kvm_utils.PciAssignable(
601 type=pa_type,
602 driver=params.get("driver"),
603 driver_option=params.get("driver_option"),
604 names=params.get("device_names"),
605 devices_requested=pa_devices_requested)
lmr31af3a12010-01-18 16:46:52 +0000606
607 self.pa_pci_ids = self.pci_assignable.request_devs()
608
609 if self.pa_pci_ids:
lmr31ed61d2010-06-07 13:21:38 +0000610 logging.debug("Successfuly assigned devices: %s",
lmr31af3a12010-01-18 16:46:52 +0000611 self.pa_pci_ids)
612 else:
613 logging.error("No PCI assignable devices were assigned "
614 "and 'pci_assignable' is defined to %s "
lmr31ed61d2010-06-07 13:21:38 +0000615 "on your config file. Aborting VM creation.",
lmr31af3a12010-01-18 16:46:52 +0000616 pa_type)
617 return False
618
lmr856d58c2010-06-08 18:29:31 +0000619 elif pa_type and pa_type != "no":
lmr31ed61d2010-06-07 13:21:38 +0000620 logging.warn("Unsupported pci_assignable type: %s", pa_type)
lmr31af3a12010-01-18 16:46:52 +0000621
lmrdc2ac6a2009-06-10 19:15:49 +0000622 # Make qemu command
623 qemu_command = self.make_qemu_command()
lmr6f669ce2009-05-31 19:02:42 +0000624
lmr1424f3e2010-06-17 13:57:09 +0000625 # Enable migration support for VM by adding extra_params.
626 if extra_params is not None:
627 if " -incoming tcp:0:%d" == extra_params:
628 self.migration_port = kvm_utils.find_free_port(5200, 6000)
629 qemu_command += extra_params % self.migration_port
630 elif " -incoming unix:%s" == extra_params:
631 self.migration_file = os.path.join("/tmp/", "unix-" +
632 time.strftime("%Y%m%d-%H%M%S"))
633 qemu_command += extra_params % self.migration_file
634 else:
635 qemu_command += extra_params
lmr6f669ce2009-05-31 19:02:42 +0000636
lmrdc2ac6a2009-06-10 19:15:49 +0000637 logging.debug("Running qemu command:\n%s", qemu_command)
lmra4967622009-07-23 01:36:32 +0000638 self.process = kvm_subprocess.run_bg(qemu_command, None,
639 logging.debug, "(qemu) ")
lmr6f669ce2009-05-31 19:02:42 +0000640
lmr9e964a02010-06-18 03:46:21 +0000641 # Make sure the process was started successfully
lmra4967622009-07-23 01:36:32 +0000642 if not self.process.is_alive():
643 logging.error("VM could not be created; "
644 "qemu command failed:\n%s" % qemu_command)
645 logging.error("Status: %s" % self.process.get_status())
646 logging.error("Output:" + kvm_utils.format_str_for_message(
647 self.process.get_output()))
lmrdc2ac6a2009-06-10 19:15:49 +0000648 self.destroy()
649 return False
lmr6f669ce2009-05-31 19:02:42 +0000650
lmr9e964a02010-06-18 03:46:21 +0000651 # Establish monitor connections
652 self.monitors = []
653 for monitor_name in kvm_utils.get_sub_dict_names(params,
654 "monitors"):
655 monitor_params = kvm_utils.get_sub_dict(params, monitor_name)
656 # Wait for monitor connection to succeed
657 end_time = time.time() + timeout
658 while time.time() < end_time:
659 try:
660 if monitor_params.get("monitor_type") == "qmp":
lmr449d2252010-06-18 03:48:23 +0000661 # Add a QMP monitor
662 monitor = kvm_monitor.QMPMonitor(
663 monitor_name,
664 self.get_monitor_filename(monitor_name))
lmr9e964a02010-06-18 03:46:21 +0000665 else:
666 # Add a "human" monitor
667 monitor = kvm_monitor.HumanMonitor(
668 monitor_name,
669 self.get_monitor_filename(monitor_name))
670 except kvm_monitor.MonitorError, e:
671 logging.warn(e)
672 else:
lmr449d2252010-06-18 03:48:23 +0000673 if monitor.is_responsive():
lmr9e964a02010-06-18 03:46:21 +0000674 break
675 time.sleep(1)
676 else:
677 logging.error("Could not connect to monitor '%s'" %
678 monitor_name)
679 self.destroy()
680 return False
681 # Add this monitor to the list
682 self.monitors += [monitor]
lmra4967622009-07-23 01:36:32 +0000683
lmrfe6515e2009-07-29 13:01:17 +0000684 # Get the output so far, to see if we have any problems with
lmrb306bf82010-07-08 23:47:00 +0000685 # KVM modules or with hugepage setup.
lmrfe6515e2009-07-29 13:01:17 +0000686 output = self.process.get_output()
687
lmrb306bf82010-07-08 23:47:00 +0000688 if re.search("Could not initialize KVM", output, re.IGNORECASE):
689 logging.error("Could not initialize KVM; "
690 "qemu command:\n%s" % qemu_command)
691 logging.error("Output:" + kvm_utils.format_str_for_message(
692 self.process.get_output()))
693 self.destroy()
694 return False
695
lmrfe6515e2009-07-29 13:01:17 +0000696 if "alloc_mem_area" in output:
697 logging.error("Could not allocate hugepage memory; "
698 "qemu command:\n%s" % qemu_command)
699 logging.error("Output:" + kvm_utils.format_str_for_message(
700 self.process.get_output()))
lmr090cd7a2010-04-01 02:18:52 +0000701 self.destroy()
lmrfe6515e2009-07-29 13:01:17 +0000702 return False
703
lmr71fa4de2010-06-14 15:54:55 +0000704 logging.debug("VM appears to be alive with PID %s", self.get_pid())
lmraa380a22010-06-22 02:05:29 +0000705
706 # Establish a session with the serial console -- requires a version
707 # of netcat that supports -U
708 self.serial_console = kvm_subprocess.kvm_shell_session(
709 "nc -U %s" % self.get_serial_console_filename(),
710 auto_close=False,
711 output_func=kvm_utils.log_line,
712 output_params=("serial-%s.log" % name,))
713
lmrdc2ac6a2009-06-10 19:15:49 +0000714 return True
715
716 finally:
717 fcntl.lockf(lockfile, fcntl.LOCK_UN)
718 lockfile.close()
lmr6f669ce2009-05-31 19:02:42 +0000719
720
lmr6f669ce2009-05-31 19:02:42 +0000721 def destroy(self, gracefully=True):
722 """
723 Destroy the VM.
724
lmr912c74b2009-08-17 20:43:27 +0000725 If gracefully is True, first attempt to shutdown the VM with a shell
726 command. Then, attempt to destroy the VM via the monitor with a 'quit'
727 command. If that fails, send SIGKILL to the qemu process.
lmr6f669ce2009-05-31 19:02:42 +0000728
729 @param gracefully: Whether an attempt will be made to end the VM
lmr912c74b2009-08-17 20:43:27 +0000730 using a shell command before trying to end the qemu process
731 with a 'quit' or a kill signal.
lmr6f669ce2009-05-31 19:02:42 +0000732 """
lmrf320b042009-09-15 05:48:06 +0000733 try:
734 # Is it already dead?
735 if self.is_dead():
736 logging.debug("VM is already down")
737 return
lmr6f669ce2009-05-31 19:02:42 +0000738
lmr71fa4de2010-06-14 15:54:55 +0000739 logging.debug("Destroying VM with PID %s...", self.get_pid())
lmr6f669ce2009-05-31 19:02:42 +0000740
lmrf320b042009-09-15 05:48:06 +0000741 if gracefully and self.params.get("shutdown_command"):
742 # Try to destroy with shell command
743 logging.debug("Trying to shutdown VM with shell command...")
744 session = self.remote_login()
745 if session:
746 try:
747 # Send the shutdown command
748 session.sendline(self.params.get("shutdown_command"))
749 logging.debug("Shutdown command sent; waiting for VM "
750 "to go down...")
751 if kvm_utils.wait_for(self.is_dead, 60, 1, 1):
752 logging.debug("VM is down")
753 return
754 finally:
755 session.close()
lmr6f669ce2009-05-31 19:02:42 +0000756
lmr9e964a02010-06-18 03:46:21 +0000757 if self.monitor:
758 # Try to destroy with a monitor command
759 logging.debug("Trying to kill VM with monitor command...")
760 try:
761 self.monitor.quit()
762 except kvm_monitor.MonitorError, e:
763 logging.warn(e)
764 else:
765 # Wait for the VM to be really dead
766 if kvm_utils.wait_for(self.is_dead, 5, 0.5, 0.5):
767 logging.debug("VM is down")
768 return
lmrf320b042009-09-15 05:48:06 +0000769
770 # If the VM isn't dead yet...
771 logging.debug("Cannot quit normally; sending a kill to close the "
772 "deal...")
773 kvm_utils.kill_process_tree(self.process.get_pid(), 9)
lmr6f669ce2009-05-31 19:02:42 +0000774 # Wait for the VM to be really dead
775 if kvm_utils.wait_for(self.is_dead, 5, 0.5, 0.5):
776 logging.debug("VM is down")
lmr6f669ce2009-05-31 19:02:42 +0000777 return
778
lmrf320b042009-09-15 05:48:06 +0000779 logging.error("Process %s is a zombie!" % self.process.get_pid())
lmr6f669ce2009-05-31 19:02:42 +0000780
lmrf320b042009-09-15 05:48:06 +0000781 finally:
lmr9e964a02010-06-18 03:46:21 +0000782 self.monitors = []
lmr4513c432010-02-03 11:59:03 +0000783 if self.pci_assignable:
784 self.pci_assignable.release_devs()
lmrf320b042009-09-15 05:48:06 +0000785 if self.process:
786 self.process.close()
lmraa380a22010-06-22 02:05:29 +0000787 if self.serial_console:
788 self.serial_console.close()
lmr84546f22010-06-29 23:03:34 +0000789 for f in ([self.get_testlog_filename(),
790 self.get_serial_console_filename()] +
lmr9e964a02010-06-18 03:46:21 +0000791 self.get_monitor_filenames()):
792 try:
793 os.unlink(f)
794 except OSError:
795 pass
796
797
798 @property
799 def monitor(self):
800 """
801 Return the main monitor object, selected by the parameter main_monitor.
802 If main_monitor isn't defined, return the first monitor.
803 If no monitors exist, or if main_monitor refers to a nonexistent
804 monitor, return None.
805 """
806 for m in self.monitors:
807 if m.name == self.params.get("main_monitor"):
808 return m
809 if self.monitors and not self.params.get("main_monitor"):
810 return self.monitors[0]
lmr6f669ce2009-05-31 19:02:42 +0000811
812
813 def is_alive(self):
814 """
lmr9e964a02010-06-18 03:46:21 +0000815 Return True if the VM is alive and its monitor is responsive.
lmr6f669ce2009-05-31 19:02:42 +0000816 """
lmra4967622009-07-23 01:36:32 +0000817 # Check if the process is running
818 if self.is_dead():
lmr6f669ce2009-05-31 19:02:42 +0000819 return False
820 # Try sending a monitor command
lmr9e964a02010-06-18 03:46:21 +0000821 return bool(self.monitor) and self.monitor.is_responsive()
lmr6f669ce2009-05-31 19:02:42 +0000822
823
824 def is_dead(self):
825 """
lmra4967622009-07-23 01:36:32 +0000826 Return True if the qemu process is dead.
lmr6f669ce2009-05-31 19:02:42 +0000827 """
lmra4967622009-07-23 01:36:32 +0000828 return not self.process or not self.process.is_alive()
lmr6f669ce2009-05-31 19:02:42 +0000829
830
831 def get_params(self):
832 """
833 Return the VM's params dict. Most modified params take effect only
834 upon VM.create().
835 """
836 return self.params
837
838
lmr9e964a02010-06-18 03:46:21 +0000839 def get_monitor_filename(self, monitor_name):
840 """
841 Return the filename corresponding to a given monitor name.
842 """
843 return "/tmp/monitor-%s-%s" % (monitor_name, self.instance)
844
845
846 def get_monitor_filenames(self):
847 """
848 Return a list of all monitor filenames (as specified in the VM's
849 params).
850 """
851 return [self.get_monitor_filename(m) for m in
852 kvm_utils.get_sub_dict_names(self.params, "monitors")]
853
854
lmr2b06f332010-06-22 02:03:41 +0000855 def get_serial_console_filename(self):
856 """
857 Return the serial console filename.
858 """
859 return "/tmp/serial-%s" % self.instance
860
861
lmr9e964a02010-06-18 03:46:21 +0000862 def get_testlog_filename(self):
863 """
864 Return the testlog filename.
865 """
866 return "/tmp/testlog-%s" % self.instance
867
868
lmrf4696342009-08-13 04:06:33 +0000869 def get_address(self, index=0):
lmr6f669ce2009-05-31 19:02:42 +0000870 """
lmrf4696342009-08-13 04:06:33 +0000871 Return the address of a NIC of the guest, in host space.
lmr6f669ce2009-05-31 19:02:42 +0000872
lmrf4696342009-08-13 04:06:33 +0000873 If port redirection is used, return 'localhost' (the NIC has no IP
874 address of its own). Otherwise return the NIC's IP address.
875
876 @param index: Index of the NIC whose address is requested.
lmr6f669ce2009-05-31 19:02:42 +0000877 """
lmree90dd92009-08-13 04:13:39 +0000878 nics = kvm_utils.get_sub_dict_names(self.params, "nics")
879 nic_name = nics[index]
lmrf4696342009-08-13 04:06:33 +0000880 nic_params = kvm_utils.get_sub_dict(self.params, nic_name)
881 if nic_params.get("nic_mode") == "tap":
882 mac, ip = kvm_utils.get_mac_ip_pair_from_dict(nic_params)
lmree90dd92009-08-13 04:13:39 +0000883 if not mac:
884 logging.debug("MAC address unavailable")
885 return None
886 if not ip or nic_params.get("always_use_tcpdump") == "yes":
887 # Get the IP address from the cache
888 ip = self.address_cache.get(mac)
889 if not ip:
890 logging.debug("Could not find IP address for MAC address: "
891 "%s" % mac)
892 return None
893 # Make sure the IP address is assigned to this guest
894 nic_dicts = [kvm_utils.get_sub_dict(self.params, nic)
895 for nic in nics]
896 macs = [kvm_utils.get_mac_ip_pair_from_dict(dict)[0]
897 for dict in nic_dicts]
898 if not kvm_utils.verify_ip_address_ownership(ip, macs):
899 logging.debug("Could not verify MAC-IP address mapping: "
900 "%s ---> %s" % (mac, ip))
901 return None
lmrf4696342009-08-13 04:06:33 +0000902 return ip
903 else:
904 return "localhost"
lmr6f669ce2009-05-31 19:02:42 +0000905
906
lmree90dd92009-08-13 04:13:39 +0000907 def get_port(self, port, nic_index=0):
lmr6f669ce2009-05-31 19:02:42 +0000908 """
909 Return the port in host space corresponding to port in guest space.
910
911 @param port: Port number in host space.
lmree90dd92009-08-13 04:13:39 +0000912 @param nic_index: Index of the NIC.
lmr6f669ce2009-05-31 19:02:42 +0000913 @return: If port redirection is used, return the host port redirected
914 to guest port port. Otherwise return port.
915 """
lmree90dd92009-08-13 04:13:39 +0000916 nic_name = kvm_utils.get_sub_dict_names(self.params, "nics")[nic_index]
lmrf4696342009-08-13 04:06:33 +0000917 nic_params = kvm_utils.get_sub_dict(self.params, nic_name)
918 if nic_params.get("nic_mode") == "tap":
919 return port
lmr6f669ce2009-05-31 19:02:42 +0000920 else:
lmrf4696342009-08-13 04:06:33 +0000921 if not self.redirs.has_key(port):
922 logging.warn("Warning: guest port %s requested but not "
923 "redirected" % port)
924 return self.redirs.get(port)
lmr6f669ce2009-05-31 19:02:42 +0000925
926
lmra4967622009-07-23 01:36:32 +0000927 def get_pid(self):
928 """
lmr71fa4de2010-06-14 15:54:55 +0000929 Return the VM's PID. If the VM is dead return None.
930
931 @note: This works under the assumption that self.process.get_pid()
932 returns the PID of the parent shell process.
933 """
934 try:
935 children = commands.getoutput("ps --ppid=%d -o pid=" %
936 self.process.get_pid()).split()
937 return int(children[0])
938 except (TypeError, IndexError, ValueError):
939 return None
940
941
942 def get_shell_pid(self):
943 """
944 Return the PID of the parent shell process.
945
946 @note: This works under the assumption that self.process.get_pid()
947 returns the PID of the parent shell process.
lmra4967622009-07-23 01:36:32 +0000948 """
949 return self.process.get_pid()
950
951
lmr0bee2342010-02-24 00:01:37 +0000952 def get_shared_meminfo(self):
953 """
954 Returns the VM's shared memory information.
955
956 @return: Shared memory used by VM (MB)
957 """
958 if self.is_dead():
959 logging.error("Could not get shared memory info from dead VM.")
960 return None
961
lmr983ecdf2010-06-14 15:57:12 +0000962 filename = "/proc/%d/statm" % self.get_pid()
963 shm = int(open(filename).read().split()[2])
lmr0bee2342010-02-24 00:01:37 +0000964 # statm stores informations in pages, translate it to MB
lmr983ecdf2010-06-14 15:57:12 +0000965 return shm * 4.0 / 1024
lmr0bee2342010-02-24 00:01:37 +0000966
967
lmr912c74b2009-08-17 20:43:27 +0000968 def remote_login(self, nic_index=0, timeout=10):
lmr6f669ce2009-05-31 19:02:42 +0000969 """
lmr912c74b2009-08-17 20:43:27 +0000970 Log into the guest via SSH/Telnet/Netcat.
lmr6f669ce2009-05-31 19:02:42 +0000971 If timeout expires while waiting for output from the guest (e.g. a
972 password prompt or a shell prompt) -- fail.
973
lmree90dd92009-08-13 04:13:39 +0000974 @param nic_index: The index of the NIC to connect to.
lmr6f669ce2009-05-31 19:02:42 +0000975 @param timeout: Time (seconds) before giving up logging into the
976 guest.
977 @return: kvm_spawn object on success and None on failure.
978 """
979 username = self.params.get("username", "")
980 password = self.params.get("password", "")
lmr912c74b2009-08-17 20:43:27 +0000981 prompt = self.params.get("shell_prompt", "[\#\$]")
lmr59f9e2d2009-10-05 18:47:16 +0000982 linesep = eval("'%s'" % self.params.get("shell_linesep", r"\n"))
lmr912c74b2009-08-17 20:43:27 +0000983 client = self.params.get("shell_client")
lmree90dd92009-08-13 04:13:39 +0000984 address = self.get_address(nic_index)
lmr912c74b2009-08-17 20:43:27 +0000985 port = self.get_port(int(self.params.get("shell_port")))
lmre56903f2010-06-22 02:09:35 +0000986 log_filename = ("session-%s-%s.log" %
987 (self.name, kvm_utils.generate_random_string(4)))
lmr912c74b2009-08-17 20:43:27 +0000988
lmree90dd92009-08-13 04:13:39 +0000989 if not address or not port:
990 logging.debug("IP address or port unavailable")
lmr6f669ce2009-05-31 19:02:42 +0000991 return None
992
lmr158604f2010-06-22 01:57:34 +0000993 session = kvm_utils.remote_login(client, address, port, username,
lmre56903f2010-06-22 02:09:35 +0000994 password, prompt, linesep,
995 log_filename, timeout)
lmr912c74b2009-08-17 20:43:27 +0000996
lmr6f669ce2009-05-31 19:02:42 +0000997 if session:
lmr912c74b2009-08-17 20:43:27 +0000998 session.set_status_test_command(self.params.get("status_test_"
lmr6f669ce2009-05-31 19:02:42 +0000999 "command", ""))
1000 return session
1001
1002
lmrc196d492010-05-07 14:14:26 +00001003 def copy_files_to(self, local_path, remote_path, nic_index=0, timeout=600):
lmr6f669ce2009-05-31 19:02:42 +00001004 """
lmr912c74b2009-08-17 20:43:27 +00001005 Transfer files to the guest.
lmr6f669ce2009-05-31 19:02:42 +00001006
1007 @param local_path: Host path
1008 @param remote_path: Guest path
lmr912c74b2009-08-17 20:43:27 +00001009 @param nic_index: The index of the NIC to connect to.
lmr6f669ce2009-05-31 19:02:42 +00001010 @param timeout: Time (seconds) before giving up on doing the remote
1011 copy.
1012 """
1013 username = self.params.get("username", "")
1014 password = self.params.get("password", "")
lmr912c74b2009-08-17 20:43:27 +00001015 client = self.params.get("file_transfer_client")
lmree90dd92009-08-13 04:13:39 +00001016 address = self.get_address(nic_index)
lmr912c74b2009-08-17 20:43:27 +00001017 port = self.get_port(int(self.params.get("file_transfer_port")))
1018
lmree90dd92009-08-13 04:13:39 +00001019 if not address or not port:
1020 logging.debug("IP address or port unavailable")
lmr6f669ce2009-05-31 19:02:42 +00001021 return None
lmr912c74b2009-08-17 20:43:27 +00001022
1023 if client == "scp":
lmrcbc86ef2010-07-07 20:50:08 +00001024 log_filename = ("scp-%s-%s.log" %
1025 (self.name, kvm_utils.generate_random_string(4)))
lmr912c74b2009-08-17 20:43:27 +00001026 return kvm_utils.scp_to_remote(address, port, username, password,
lmre56903f2010-06-22 02:09:35 +00001027 local_path, remote_path,
1028 log_filename, timeout)
lmrcbc86ef2010-07-07 20:50:08 +00001029 elif client == "rss":
1030 c = rss_file_transfer.FileUploadClient(address, port)
1031 c.upload(local_path, remote_path, timeout)
1032 c.close()
1033 return True
lmr6f669ce2009-05-31 19:02:42 +00001034
1035
lmrc196d492010-05-07 14:14:26 +00001036 def copy_files_from(self, remote_path, local_path, nic_index=0, timeout=600):
lmr6f669ce2009-05-31 19:02:42 +00001037 """
lmr912c74b2009-08-17 20:43:27 +00001038 Transfer files from the guest.
lmr6f669ce2009-05-31 19:02:42 +00001039
1040 @param local_path: Guest path
1041 @param remote_path: Host path
lmr912c74b2009-08-17 20:43:27 +00001042 @param nic_index: The index of the NIC to connect to.
lmr6f669ce2009-05-31 19:02:42 +00001043 @param timeout: Time (seconds) before giving up on doing the remote
1044 copy.
1045 """
1046 username = self.params.get("username", "")
1047 password = self.params.get("password", "")
lmr912c74b2009-08-17 20:43:27 +00001048 client = self.params.get("file_transfer_client")
lmree90dd92009-08-13 04:13:39 +00001049 address = self.get_address(nic_index)
lmr912c74b2009-08-17 20:43:27 +00001050 port = self.get_port(int(self.params.get("file_transfer_port")))
1051
lmree90dd92009-08-13 04:13:39 +00001052 if not address or not port:
1053 logging.debug("IP address or port unavailable")
lmr6f669ce2009-05-31 19:02:42 +00001054 return None
lmr6f669ce2009-05-31 19:02:42 +00001055
lmr912c74b2009-08-17 20:43:27 +00001056 if client == "scp":
lmrcbc86ef2010-07-07 20:50:08 +00001057 log_filename = ("scp-%s-%s.log" %
1058 (self.name, kvm_utils.generate_random_string(4)))
lmr912c74b2009-08-17 20:43:27 +00001059 return kvm_utils.scp_from_remote(address, port, username, password,
lmre56903f2010-06-22 02:09:35 +00001060 remote_path, local_path,
1061 log_filename, timeout)
lmrcbc86ef2010-07-07 20:50:08 +00001062 elif client == "rss":
1063 c = rss_file_transfer.FileDownloadClient(address, port)
1064 c.download(remote_path, local_path, timeout)
1065 c.close()
1066 return True
lmr6f669ce2009-05-31 19:02:42 +00001067
1068
lmraa380a22010-06-22 02:05:29 +00001069 def serial_login(self, timeout=10):
1070 """
1071 Log into the guest via the serial console.
1072 If timeout expires while waiting for output from the guest (e.g. a
1073 password prompt or a shell prompt) -- fail.
1074
1075 @param timeout: Time (seconds) before giving up logging into the guest.
1076 @return: kvm_spawn object on success and None on failure.
1077 """
1078 username = self.params.get("username", "")
1079 password = self.params.get("password", "")
1080 prompt = self.params.get("shell_prompt", "[\#\$]")
1081 linesep = eval("'%s'" % self.params.get("shell_linesep", r"\n"))
1082 status_test_command = self.params.get("status_test_command", "")
1083
1084 if self.serial_console:
1085 self.serial_console.set_linesep(linesep)
1086 self.serial_console.set_status_test_command(status_test_command)
1087 else:
1088 return None
1089
1090 # Make sure we get a login prompt
1091 self.serial_console.sendline()
1092
1093 if kvm_utils._remote_login(self.serial_console, username, password,
1094 prompt, timeout):
1095 return self.serial_console
1096
1097
lmr6f669ce2009-05-31 19:02:42 +00001098 def send_key(self, keystr):
1099 """
1100 Send a key event to the VM.
1101
1102 @param: keystr: A key event string (e.g. "ctrl-alt-delete")
1103 """
1104 # For compatibility with versions of QEMU that do not recognize all
1105 # key names: replace keyname with the hex value from the dict, which
1106 # QEMU will definitely accept
lmr9e964a02010-06-18 03:46:21 +00001107 dict = {"comma": "0x33",
1108 "dot": "0x34",
1109 "slash": "0x35"}
1110 for key, value in dict.items():
1111 keystr = keystr.replace(key, value)
1112 self.monitor.sendkey(keystr)
lmr6f669ce2009-05-31 19:02:42 +00001113 time.sleep(0.2)
1114
1115
1116 def send_string(self, str):
1117 """
1118 Send a string to the VM.
1119
1120 @param str: String, that must consist of alphanumeric characters only.
1121 Capital letters are allowed.
1122 """
1123 for char in str:
1124 if char.isupper():
1125 self.send_key("shift-%s" % char.lower())
1126 else:
1127 self.send_key(char)
lmra2533222009-07-20 12:43:46 +00001128
mbligh1ef218d2009-08-03 16:57:56 +00001129
lmra2533222009-07-20 12:43:46 +00001130 def get_uuid(self):
1131 """
1132 Catch UUID of the VM.
1133
1134 @return: None,if not specified in config file
1135 """
1136 if self.params.get("uuid") == "random":
1137 return self.uuid
1138 else:
1139 return self.params.get("uuid", None)
lmrdd2ff922009-12-01 23:39:12 +00001140
1141
1142 def get_cpu_count(self):
1143 """
1144 Get the cpu count of the VM.
1145 """
lmr13426552010-01-17 15:38:41 +00001146 session = self.remote_login()
1147 if not session:
1148 return None
lmrdd2ff922009-12-01 23:39:12 +00001149 try:
lmr13426552010-01-17 15:38:41 +00001150 cmd = self.params.get("cpu_chk_cmd")
1151 s, count = session.get_command_status_output(cmd)
1152 if s == 0:
1153 return int(count)
lmrdd2ff922009-12-01 23:39:12 +00001154 return None
1155 finally:
1156 session.close()
1157
1158
lmr28426c82010-04-16 06:02:58 +00001159 def get_memory_size(self, cmd=None):
lmrdd2ff922009-12-01 23:39:12 +00001160 """
lmr28426c82010-04-16 06:02:58 +00001161 Get bootup memory size of the VM.
1162
1163 @param check_cmd: Command used to check memory. If not provided,
1164 self.params.get("mem_chk_cmd") will be used.
lmrdd2ff922009-12-01 23:39:12 +00001165 """
lmr13426552010-01-17 15:38:41 +00001166 session = self.remote_login()
1167 if not session:
lmrdd2ff922009-12-01 23:39:12 +00001168 return None
lmr13426552010-01-17 15:38:41 +00001169 try:
lmr28426c82010-04-16 06:02:58 +00001170 if not cmd:
1171 cmd = self.params.get("mem_chk_cmd")
lmr13426552010-01-17 15:38:41 +00001172 s, mem_str = session.get_command_status_output(cmd)
1173 if s != 0:
1174 return None
lmr6d69f4d2010-02-12 11:35:55 +00001175 mem = re.findall("([0-9]+)", mem_str)
lmr13426552010-01-17 15:38:41 +00001176 mem_size = 0
1177 for m in mem:
1178 mem_size += int(m)
1179 if "GB" in mem_str:
1180 mem_size *= 1024
1181 elif "MB" in mem_str:
1182 pass
1183 else:
1184 mem_size /= 1024
1185 return int(mem_size)
lmrdd2ff922009-12-01 23:39:12 +00001186 finally:
1187 session.close()
lmr28426c82010-04-16 06:02:58 +00001188
1189
1190 def get_current_memory_size(self):
1191 """
1192 Get current memory size of the VM, rather than bootup memory.
1193 """
1194 cmd = self.params.get("mem_chk_cur_cmd")
1195 return self.get_memory_size(cmd)