blob: 1102f88617907196609533c319195389dec1da8e [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
217 def add_cdrom(help, filename, index=2):
218 if has_option(help, "drive"):
lmr09a78162010-06-14 16:29:23 +0000219 return " -drive file='%s',index=%d,media=cdrom" % (filename,
220 index)
lmr48abd7d2010-05-26 13:48:04 +0000221 else:
lmr09a78162010-06-14 16:29:23 +0000222 return " -cdrom '%s'" % filename
lmr48abd7d2010-05-26 13:48:04 +0000223
224 def add_drive(help, filename, format=None, cache=None, werror=None,
225 serial=None, snapshot=False, boot=False):
lmr09a78162010-06-14 16:29:23 +0000226 cmd = " -drive file='%s'" % filename
lmr48abd7d2010-05-26 13:48:04 +0000227 if format: cmd += ",if=%s" % format
228 if cache: cmd += ",cache=%s" % cache
229 if werror: cmd += ",werror=%s" % werror
lmr09a78162010-06-14 16:29:23 +0000230 if serial: cmd += ",serial='%s'" % serial
lmr48abd7d2010-05-26 13:48:04 +0000231 if snapshot: cmd += ",snapshot=on"
232 if boot: cmd += ",boot=on"
233 return cmd
234
lmrb1cad1e2010-06-17 17:36:09 +0000235 def add_nic(help, vlan, model=None, mac=None, netdev_id=None):
lmr48abd7d2010-05-26 13:48:04 +0000236 cmd = " -net nic,vlan=%d" % vlan
lmrb1cad1e2010-06-17 17:36:09 +0000237 if has_option(help, "netdev"):
238 cmd +=",netdev=%s" % netdev_id
lmr48abd7d2010-05-26 13:48:04 +0000239 if model: cmd += ",model=%s" % model
lmr09a78162010-06-14 16:29:23 +0000240 if mac: cmd += ",macaddr='%s'" % mac
lmr48abd7d2010-05-26 13:48:04 +0000241 return cmd
242
243 def add_net(help, vlan, mode, ifname=None, script=None,
lmrb1cad1e2010-06-17 17:36:09 +0000244 downscript=None, netdev_id=None):
245 if has_option(help, "netdev"):
246 cmd = " -netdev %s,id=%s" % (mode, netdev_id)
247 else:
248 cmd = " -net %s,vlan=%d" % (mode, vlan)
lmr48abd7d2010-05-26 13:48:04 +0000249 if mode == "tap":
lmr09a78162010-06-14 16:29:23 +0000250 if ifname: cmd += ",ifname='%s'" % ifname
251 if script: cmd += ",script='%s'" % script
252 cmd += ",downscript='%s'" % (downscript or "no")
lmr48abd7d2010-05-26 13:48:04 +0000253 return cmd
254
255 def add_floppy(help, filename):
lmr09a78162010-06-14 16:29:23 +0000256 return " -fda '%s'" % filename
lmr48abd7d2010-05-26 13:48:04 +0000257
258 def add_tftp(help, filename):
lmr09a78162010-06-14 16:29:23 +0000259 return " -tftp '%s'" % filename
lmr48abd7d2010-05-26 13:48:04 +0000260
261 def add_tcp_redir(help, host_port, guest_port):
262 return " -redir tcp:%s::%s" % (host_port, guest_port)
263
264 def add_vnc(help, vnc_port):
265 return " -vnc :%d" % (vnc_port - 5900)
266
267 def add_sdl(help):
268 if has_option(help, "sdl"):
269 return " -sdl"
270 else:
271 return ""
272
273 def add_nographic(help):
274 return " -nographic"
275
276 def add_uuid(help, uuid):
lmr09a78162010-06-14 16:29:23 +0000277 return " -uuid '%s'" % uuid
lmr48abd7d2010-05-26 13:48:04 +0000278
279 def add_pcidevice(help, host):
lmr09a78162010-06-14 16:29:23 +0000280 return " -pcidevice host='%s'" % host
lmr48abd7d2010-05-26 13:48:04 +0000281
lmr41cb8fc2010-06-10 15:30:45 +0000282 def add_kernel(help, filename):
lmr09a78162010-06-14 16:29:23 +0000283 return " -kernel '%s'" % filename
lmr41cb8fc2010-06-10 15:30:45 +0000284
285 def add_initrd(help, filename):
lmr09a78162010-06-14 16:29:23 +0000286 return " -initrd '%s'" % filename
lmr41cb8fc2010-06-10 15:30:45 +0000287
lmre0474e32010-06-29 14:10:09 +0000288 def add_kernel_cmdline(help, cmdline):
289 return " -append %s" % cmdline
290
lmr71024552010-06-29 14:12:35 +0000291 def add_testdev(help, filename):
292 return (" -chardev file,id=testlog,path=%s"
293 " -device testdev,chardev=testlog" % filename)
294
lmrce5c9252010-06-30 17:41:00 +0000295 def add_no_hpet(help):
296 if has_option(help, "no-hpet"):
297 return " -no-hpet"
298 else:
299 return ""
300
lmr48abd7d2010-05-26 13:48:04 +0000301 # End of command line option wrappers
302
303 if name is None: name = self.name
304 if params is None: params = self.params
305 if root_dir is None: root_dir = self.root_dir
306
307 qemu_binary = kvm_utils.get_path(root_dir, params.get("qemu_binary",
308 "qemu"))
309 # Get the output of 'qemu -help' (log a message in case this call never
310 # returns or causes some other kind of trouble)
311 logging.debug("Getting output of 'qemu -help'")
312 help = commands.getoutput("%s -help" % qemu_binary)
lmr6f669ce2009-05-31 19:02:42 +0000313
lmreeff0eb2009-06-10 19:19:15 +0000314 # Start constructing the qemu command
315 qemu_cmd = ""
316 # Set the X11 display parameter if requested
317 if params.get("x11_display"):
318 qemu_cmd += "DISPLAY=%s " % params.get("x11_display")
319 # Add the qemu binary
lmr48abd7d2010-05-26 13:48:04 +0000320 qemu_cmd += qemu_binary
lmreeff0eb2009-06-10 19:19:15 +0000321 # Add the VM's name
lmr48abd7d2010-05-26 13:48:04 +0000322 qemu_cmd += add_name(help, name)
lmr9e964a02010-06-18 03:46:21 +0000323 # Add monitors
324 for monitor_name in kvm_utils.get_sub_dict_names(params, "monitors"):
325 monitor_params = kvm_utils.get_sub_dict(params, monitor_name)
326 monitor_filename = self.get_monitor_filename(monitor_name)
327 if monitor_params.get("monitor_type") == "qmp":
328 qemu_cmd += add_qmp_monitor(help, monitor_filename)
329 else:
330 qemu_cmd += add_human_monitor(help, monitor_filename)
lmr6f669ce2009-05-31 19:02:42 +0000331
lmr2b06f332010-06-22 02:03:41 +0000332 # Add serial console redirection
333 qemu_cmd += add_serial(help, self.get_serial_console_filename())
334
lmr6f669ce2009-05-31 19:02:42 +0000335 for image_name in kvm_utils.get_sub_dict_names(params, "images"):
336 image_params = kvm_utils.get_sub_dict(params, image_name)
lmr9d75ee32009-09-29 13:14:13 +0000337 if image_params.get("boot_drive") == "no":
338 continue
lmr48abd7d2010-05-26 13:48:04 +0000339 qemu_cmd += add_drive(help,
340 get_image_filename(image_params, root_dir),
341 image_params.get("drive_format"),
342 image_params.get("drive_cache"),
343 image_params.get("drive_werror"),
344 image_params.get("drive_serial"),
345 image_params.get("image_snapshot") == "yes",
346 image_params.get("image_boot") == "yes")
lmr6f669ce2009-05-31 19:02:42 +0000347
348 vlan = 0
349 for nic_name in kvm_utils.get_sub_dict_names(params, "nics"):
350 nic_params = kvm_utils.get_sub_dict(params, nic_name)
lmrf4696342009-08-13 04:06:33 +0000351 # Handle the '-net nic' part
lmr48abd7d2010-05-26 13:48:04 +0000352 mac = None
353 if "address_index" in nic_params:
354 mac = kvm_utils.get_mac_ip_pair_from_dict(nic_params)[0]
lmrb1cad1e2010-06-17 17:36:09 +0000355 qemu_cmd += add_nic(help, vlan, nic_params.get("nic_model"), mac,
356 self.netdev_id[vlan])
lmrf4696342009-08-13 04:06:33 +0000357 # Handle the '-net tap' or '-net user' part
lmre4eaa862010-06-01 19:15:14 +0000358 script = nic_params.get("nic_script")
359 downscript = nic_params.get("nic_downscript")
lmr48abd7d2010-05-26 13:48:04 +0000360 if script:
361 script = kvm_utils.get_path(root_dir, script)
362 if downscript:
363 downscript = kvm_utils.get_path(root_dir, downscript)
364 qemu_cmd += add_net(help, vlan, nic_params.get("nic_mode", "user"),
365 nic_params.get("nic_ifname"),
lmrb1cad1e2010-06-17 17:36:09 +0000366 script, downscript, self.netdev_id[vlan])
lmrf4696342009-08-13 04:06:33 +0000367 # Proceed to next NIC
lmr6f669ce2009-05-31 19:02:42 +0000368 vlan += 1
369
370 mem = params.get("mem")
371 if mem:
lmr48abd7d2010-05-26 13:48:04 +0000372 qemu_cmd += add_mem(help, mem)
lmr6f669ce2009-05-31 19:02:42 +0000373
lmrc43bf372009-11-10 13:19:00 +0000374 smp = params.get("smp")
375 if smp:
lmrdb3fe612010-06-14 16:19:28 +0000376 qemu_cmd += add_smp(help, smp)
lmrc43bf372009-11-10 13:19:00 +0000377
lmr6f669ce2009-05-31 19:02:42 +0000378 iso = params.get("cdrom")
379 if iso:
lmr90b9fd52009-08-17 20:48:18 +0000380 iso = kvm_utils.get_path(root_dir, iso)
lmr48abd7d2010-05-26 13:48:04 +0000381 qemu_cmd += add_cdrom(help, iso)
lmr89fd6412010-01-18 02:42:57 +0000382
383 # Even though this is not a really scalable approach,
384 # it doesn't seem like we are going to need more than
385 # 2 CDs active on the same VM.
386 iso_extra = params.get("cdrom_extra")
387 if iso_extra:
388 iso_extra = kvm_utils.get_path(root_dir, iso_extra)
lmr48abd7d2010-05-26 13:48:04 +0000389 qemu_cmd += add_cdrom(help, iso_extra, 3)
lmr6f669ce2009-05-31 19:02:42 +0000390
lmrb0a9b762009-10-09 20:43:30 +0000391 # We may want to add {floppy_otps} parameter for -fda
lmr48abd7d2010-05-26 13:48:04 +0000392 # {fat:floppy:}/path/. However vvfat is not usually recommended.
lmrb0a9b762009-10-09 20:43:30 +0000393 floppy = params.get("floppy")
394 if floppy:
lmrf69f6b12009-11-10 16:33:44 +0000395 floppy = kvm_utils.get_path(root_dir, floppy)
lmr48abd7d2010-05-26 13:48:04 +0000396 qemu_cmd += add_floppy(help, floppy)
lmrb0a9b762009-10-09 20:43:30 +0000397
398 tftp = params.get("tftp")
lmr69e10f22010-06-30 17:39:30 +0000399 if tftp and nic_params.get("nic_mode") == "user":
lmrf69f6b12009-11-10 16:33:44 +0000400 tftp = kvm_utils.get_path(root_dir, tftp)
lmr48abd7d2010-05-26 13:48:04 +0000401 qemu_cmd += add_tftp(help, tftp)
lmr6f669ce2009-05-31 19:02:42 +0000402
lmr41cb8fc2010-06-10 15:30:45 +0000403 kernel = params.get("kernel")
404 if kernel:
405 kernel = kvm_utils.get_path(root_dir, kernel)
406 qemu_cmd += add_kernel(help, kernel)
407
lmre0474e32010-06-29 14:10:09 +0000408 kernel_cmdline = params.get("kernel_cmdline")
409 if kernel_cmdline:
410 qemu_cmd += add_kernel_cmdline(help, kernel_cmdline)
411
lmr41cb8fc2010-06-10 15:30:45 +0000412 initrd = params.get("initrd")
413 if initrd:
414 initrd = kvm_utils.get_path(root_dir, initrd)
415 qemu_cmd += add_initrd(help, initrd)
416
lmr6f669ce2009-05-31 19:02:42 +0000417 for redir_name in kvm_utils.get_sub_dict_names(params, "redirs"):
418 redir_params = kvm_utils.get_sub_dict(params, redir_name)
419 guest_port = int(redir_params.get("guest_port"))
lmrf4696342009-08-13 04:06:33 +0000420 host_port = self.redirs.get(guest_port)
lmr48abd7d2010-05-26 13:48:04 +0000421 qemu_cmd += add_tcp_redir(help, host_port, guest_port)
lmr6f669ce2009-05-31 19:02:42 +0000422
423 if params.get("display") == "vnc":
lmr48abd7d2010-05-26 13:48:04 +0000424 qemu_cmd += add_vnc(help, self.vnc_port)
lmr6f669ce2009-05-31 19:02:42 +0000425 elif params.get("display") == "sdl":
lmr48abd7d2010-05-26 13:48:04 +0000426 qemu_cmd += add_sdl(help)
lmr6f669ce2009-05-31 19:02:42 +0000427 elif params.get("display") == "nographic":
lmr48abd7d2010-05-26 13:48:04 +0000428 qemu_cmd += add_nographic(help)
lmr6f669ce2009-05-31 19:02:42 +0000429
lmra2533222009-07-20 12:43:46 +0000430 if params.get("uuid") == "random":
lmr48abd7d2010-05-26 13:48:04 +0000431 qemu_cmd += add_uuid(help, self.uuid)
lmra2533222009-07-20 12:43:46 +0000432 elif params.get("uuid"):
lmr48abd7d2010-05-26 13:48:04 +0000433 qemu_cmd += add_uuid(help, params.get("uuid"))
lmra2533222009-07-20 12:43:46 +0000434
lmr71024552010-06-29 14:12:35 +0000435 if params.get("testdev") == "yes":
436 qemu_cmd += add_testdev(help, self.get_testlog_filename())
437
lmrce5c9252010-06-30 17:41:00 +0000438 if params.get("disable_hpet") == "yes":
439 qemu_cmd += add_no_hpet(help)
440
lmr31af3a12010-01-18 16:46:52 +0000441 # If the PCI assignment step went OK, add each one of the PCI assigned
442 # devices to the qemu command line.
443 if self.pci_assignable:
444 for pci_id in self.pa_pci_ids:
lmr48abd7d2010-05-26 13:48:04 +0000445 qemu_cmd += add_pcidevice(help, pci_id)
446
447 extra_params = params.get("extra_params")
448 if extra_params:
449 qemu_cmd += " %s" % extra_params
lmr31af3a12010-01-18 16:46:52 +0000450
lmr6f669ce2009-05-31 19:02:42 +0000451 return qemu_cmd
452
453
lmr52800ba2009-08-17 20:49:58 +0000454 def create(self, name=None, params=None, root_dir=None,
lmr1424f3e2010-06-17 13:57:09 +0000455 for_migration=False, timeout=5.0, extra_params=None):
lmr6f669ce2009-05-31 19:02:42 +0000456 """
457 Start the VM by running a qemu command.
458 All parameters are optional. The following applies to all parameters
459 but for_migration: If a parameter is not supplied, the corresponding
460 value stored in the class attributes is used, and if it is supplied,
461 it is stored for later use.
462
463 @param name: The name of the object
464 @param params: A dict containing VM params
lmr90b9fd52009-08-17 20:48:18 +0000465 @param root_dir: Base directory for relative filenames
lmr6f669ce2009-05-31 19:02:42 +0000466 @param for_migration: If True, start the VM with the -incoming
467 option
lmr1424f3e2010-06-17 13:57:09 +0000468 @param extra_params: extra params for qemu command.e.g -incoming option
469 Please use this parameter instead of for_migration.
lmr6f669ce2009-05-31 19:02:42 +0000470 """
lmr135b5e62009-06-10 19:22:31 +0000471 self.destroy()
472
lmre45a1f22009-11-10 16:35:08 +0000473 if name is not None:
lmr6f669ce2009-05-31 19:02:42 +0000474 self.name = name
lmre45a1f22009-11-10 16:35:08 +0000475 if params is not None:
lmr6f669ce2009-05-31 19:02:42 +0000476 self.params = params
lmre45a1f22009-11-10 16:35:08 +0000477 if root_dir is not None:
lmr90b9fd52009-08-17 20:48:18 +0000478 self.root_dir = root_dir
lmr6f669ce2009-05-31 19:02:42 +0000479 name = self.name
480 params = self.params
lmr90b9fd52009-08-17 20:48:18 +0000481 root_dir = self.root_dir
lmr6f669ce2009-05-31 19:02:42 +0000482
483 # Verify the md5sum of the ISO image
484 iso = params.get("cdrom")
485 if iso:
lmr90b9fd52009-08-17 20:48:18 +0000486 iso = kvm_utils.get_path(root_dir, iso)
lmr6f669ce2009-05-31 19:02:42 +0000487 if not os.path.exists(iso):
488 logging.error("ISO file not found: %s" % iso)
489 return False
490 compare = False
491 if params.get("md5sum_1m"):
lmrf4696342009-08-13 04:06:33 +0000492 logging.debug("Comparing expected MD5 sum with MD5 sum of "
493 "first MB of ISO file...")
lmrd60882f2010-02-04 03:26:36 +0000494 actual_hash = utils.hash_file(iso, 1048576, method="md5")
lmr03ba22e2009-10-23 12:07:44 +0000495 expected_hash = params.get("md5sum_1m")
lmr6f669ce2009-05-31 19:02:42 +0000496 compare = True
497 elif params.get("md5sum"):
lmrf4696342009-08-13 04:06:33 +0000498 logging.debug("Comparing expected MD5 sum with MD5 sum of ISO "
499 "file...")
lmrd60882f2010-02-04 03:26:36 +0000500 actual_hash = utils.hash_file(iso, method="md5")
lmr03ba22e2009-10-23 12:07:44 +0000501 expected_hash = params.get("md5sum")
502 compare = True
503 elif params.get("sha1sum"):
504 logging.debug("Comparing expected SHA1 sum with SHA1 sum of "
505 "ISO file...")
lmrd60882f2010-02-04 03:26:36 +0000506 actual_hash = utils.hash_file(iso, method="sha1")
lmrea1266e2009-11-10 16:41:08 +0000507 expected_hash = params.get("sha1sum")
lmr6f669ce2009-05-31 19:02:42 +0000508 compare = True
509 if compare:
lmr03ba22e2009-10-23 12:07:44 +0000510 if actual_hash == expected_hash:
511 logging.debug("Hashes match")
lmr6f669ce2009-05-31 19:02:42 +0000512 else:
lmr03ba22e2009-10-23 12:07:44 +0000513 logging.error("Actual hash differs from expected one")
lmr6f669ce2009-05-31 19:02:42 +0000514 return False
515
lmrdc2ac6a2009-06-10 19:15:49 +0000516 # Make sure the following code is not executed by more than one thread
517 # at the same time
518 lockfile = open("/tmp/kvm-autotest-vm-create.lock", "w+")
519 fcntl.lockf(lockfile, fcntl.LOCK_EX)
lmr6f669ce2009-05-31 19:02:42 +0000520
lmrdc2ac6a2009-06-10 19:15:49 +0000521 try:
522 # Handle port redirections
523 redir_names = kvm_utils.get_sub_dict_names(params, "redirs")
524 host_ports = kvm_utils.find_free_ports(5000, 6000, len(redir_names))
525 self.redirs = {}
526 for i in range(len(redir_names)):
527 redir_params = kvm_utils.get_sub_dict(params, redir_names[i])
528 guest_port = int(redir_params.get("guest_port"))
529 self.redirs[guest_port] = host_ports[i]
lmr6f669ce2009-05-31 19:02:42 +0000530
lmr48349072010-06-29 14:14:55 +0000531 for nic in kvm_utils.get_sub_dict_names(params, "nics"):
532 self.netdev_id.append(kvm_utils.generate_random_id())
533
lmrdc2ac6a2009-06-10 19:15:49 +0000534 # Find available VNC port, if needed
535 if params.get("display") == "vnc":
lmrc0da8902010-05-17 20:31:36 +0000536 self.vnc_port = kvm_utils.find_free_port(5900, 6100)
lmr6f669ce2009-05-31 19:02:42 +0000537
lmra2533222009-07-20 12:43:46 +0000538 # Find random UUID if specified 'uuid = random' in config file
539 if params.get("uuid") == "random":
540 f = open("/proc/sys/kernel/random/uuid")
541 self.uuid = f.read().strip()
542 f.close()
543
lmr31ed61d2010-06-07 13:21:38 +0000544 # Assign a PCI assignable device
545 self.pci_assignable = None
546 pa_type = params.get("pci_assignable")
547 if pa_type in ["vf", "pf", "mixed"]:
lmr31af3a12010-01-18 16:46:52 +0000548 pa_devices_requested = params.get("devices_requested")
549
550 # Virtual Functions (VF) assignable devices
551 if pa_type == "vf":
lmr31ed61d2010-06-07 13:21:38 +0000552 self.pci_assignable = kvm_utils.PciAssignable(
553 type=pa_type,
554 driver=params.get("driver"),
555 driver_option=params.get("driver_option"),
556 devices_requested=pa_devices_requested)
lmr31af3a12010-01-18 16:46:52 +0000557 # Physical NIC (PF) assignable devices
558 elif pa_type == "pf":
lmr31ed61d2010-06-07 13:21:38 +0000559 self.pci_assignable = kvm_utils.PciAssignable(
560 type=pa_type,
561 names=params.get("device_names"),
562 devices_requested=pa_devices_requested)
lmr31af3a12010-01-18 16:46:52 +0000563 # Working with both VF and PF
564 elif pa_type == "mixed":
lmr31ed61d2010-06-07 13:21:38 +0000565 self.pci_assignable = kvm_utils.PciAssignable(
566 type=pa_type,
567 driver=params.get("driver"),
568 driver_option=params.get("driver_option"),
569 names=params.get("device_names"),
570 devices_requested=pa_devices_requested)
lmr31af3a12010-01-18 16:46:52 +0000571
572 self.pa_pci_ids = self.pci_assignable.request_devs()
573
574 if self.pa_pci_ids:
lmr31ed61d2010-06-07 13:21:38 +0000575 logging.debug("Successfuly assigned devices: %s",
lmr31af3a12010-01-18 16:46:52 +0000576 self.pa_pci_ids)
577 else:
578 logging.error("No PCI assignable devices were assigned "
579 "and 'pci_assignable' is defined to %s "
lmr31ed61d2010-06-07 13:21:38 +0000580 "on your config file. Aborting VM creation.",
lmr31af3a12010-01-18 16:46:52 +0000581 pa_type)
582 return False
583
lmr856d58c2010-06-08 18:29:31 +0000584 elif pa_type and pa_type != "no":
lmr31ed61d2010-06-07 13:21:38 +0000585 logging.warn("Unsupported pci_assignable type: %s", pa_type)
lmr31af3a12010-01-18 16:46:52 +0000586
lmrdc2ac6a2009-06-10 19:15:49 +0000587 # Make qemu command
588 qemu_command = self.make_qemu_command()
lmr6f669ce2009-05-31 19:02:42 +0000589
lmr1424f3e2010-06-17 13:57:09 +0000590 # Enable migration support for VM by adding extra_params.
591 if extra_params is not None:
592 if " -incoming tcp:0:%d" == extra_params:
593 self.migration_port = kvm_utils.find_free_port(5200, 6000)
594 qemu_command += extra_params % self.migration_port
595 elif " -incoming unix:%s" == extra_params:
596 self.migration_file = os.path.join("/tmp/", "unix-" +
597 time.strftime("%Y%m%d-%H%M%S"))
598 qemu_command += extra_params % self.migration_file
599 else:
600 qemu_command += extra_params
lmr6f669ce2009-05-31 19:02:42 +0000601
lmrdc2ac6a2009-06-10 19:15:49 +0000602 logging.debug("Running qemu command:\n%s", qemu_command)
lmra4967622009-07-23 01:36:32 +0000603 self.process = kvm_subprocess.run_bg(qemu_command, None,
604 logging.debug, "(qemu) ")
lmr6f669ce2009-05-31 19:02:42 +0000605
lmr9e964a02010-06-18 03:46:21 +0000606 # Make sure the process was started successfully
lmra4967622009-07-23 01:36:32 +0000607 if not self.process.is_alive():
608 logging.error("VM could not be created; "
609 "qemu command failed:\n%s" % qemu_command)
610 logging.error("Status: %s" % self.process.get_status())
611 logging.error("Output:" + kvm_utils.format_str_for_message(
612 self.process.get_output()))
lmrdc2ac6a2009-06-10 19:15:49 +0000613 self.destroy()
614 return False
lmr6f669ce2009-05-31 19:02:42 +0000615
lmr9e964a02010-06-18 03:46:21 +0000616 # Establish monitor connections
617 self.monitors = []
618 for monitor_name in kvm_utils.get_sub_dict_names(params,
619 "monitors"):
620 monitor_params = kvm_utils.get_sub_dict(params, monitor_name)
621 # Wait for monitor connection to succeed
622 end_time = time.time() + timeout
623 while time.time() < end_time:
624 try:
625 if monitor_params.get("monitor_type") == "qmp":
lmr449d2252010-06-18 03:48:23 +0000626 # Add a QMP monitor
627 monitor = kvm_monitor.QMPMonitor(
628 monitor_name,
629 self.get_monitor_filename(monitor_name))
lmr9e964a02010-06-18 03:46:21 +0000630 else:
631 # Add a "human" monitor
632 monitor = kvm_monitor.HumanMonitor(
633 monitor_name,
634 self.get_monitor_filename(monitor_name))
635 except kvm_monitor.MonitorError, e:
636 logging.warn(e)
637 else:
lmr449d2252010-06-18 03:48:23 +0000638 if monitor.is_responsive():
lmr9e964a02010-06-18 03:46:21 +0000639 break
640 time.sleep(1)
641 else:
642 logging.error("Could not connect to monitor '%s'" %
643 monitor_name)
644 self.destroy()
645 return False
646 # Add this monitor to the list
647 self.monitors += [monitor]
lmra4967622009-07-23 01:36:32 +0000648
lmrfe6515e2009-07-29 13:01:17 +0000649 # Get the output so far, to see if we have any problems with
650 # hugepage setup.
651 output = self.process.get_output()
652
653 if "alloc_mem_area" in output:
654 logging.error("Could not allocate hugepage memory; "
655 "qemu command:\n%s" % qemu_command)
656 logging.error("Output:" + kvm_utils.format_str_for_message(
657 self.process.get_output()))
lmr090cd7a2010-04-01 02:18:52 +0000658 self.destroy()
lmrfe6515e2009-07-29 13:01:17 +0000659 return False
660
lmr71fa4de2010-06-14 15:54:55 +0000661 logging.debug("VM appears to be alive with PID %s", self.get_pid())
lmraa380a22010-06-22 02:05:29 +0000662
663 # Establish a session with the serial console -- requires a version
664 # of netcat that supports -U
665 self.serial_console = kvm_subprocess.kvm_shell_session(
666 "nc -U %s" % self.get_serial_console_filename(),
667 auto_close=False,
668 output_func=kvm_utils.log_line,
669 output_params=("serial-%s.log" % name,))
670
lmrdc2ac6a2009-06-10 19:15:49 +0000671 return True
672
673 finally:
674 fcntl.lockf(lockfile, fcntl.LOCK_UN)
675 lockfile.close()
lmr6f669ce2009-05-31 19:02:42 +0000676
677
lmr6f669ce2009-05-31 19:02:42 +0000678 def destroy(self, gracefully=True):
679 """
680 Destroy the VM.
681
lmr912c74b2009-08-17 20:43:27 +0000682 If gracefully is True, first attempt to shutdown the VM with a shell
683 command. Then, attempt to destroy the VM via the monitor with a 'quit'
684 command. If that fails, send SIGKILL to the qemu process.
lmr6f669ce2009-05-31 19:02:42 +0000685
686 @param gracefully: Whether an attempt will be made to end the VM
lmr912c74b2009-08-17 20:43:27 +0000687 using a shell command before trying to end the qemu process
688 with a 'quit' or a kill signal.
lmr6f669ce2009-05-31 19:02:42 +0000689 """
lmrf320b042009-09-15 05:48:06 +0000690 try:
691 # Is it already dead?
692 if self.is_dead():
693 logging.debug("VM is already down")
694 return
lmr6f669ce2009-05-31 19:02:42 +0000695
lmr71fa4de2010-06-14 15:54:55 +0000696 logging.debug("Destroying VM with PID %s...", self.get_pid())
lmr6f669ce2009-05-31 19:02:42 +0000697
lmrf320b042009-09-15 05:48:06 +0000698 if gracefully and self.params.get("shutdown_command"):
699 # Try to destroy with shell command
700 logging.debug("Trying to shutdown VM with shell command...")
701 session = self.remote_login()
702 if session:
703 try:
704 # Send the shutdown command
705 session.sendline(self.params.get("shutdown_command"))
706 logging.debug("Shutdown command sent; waiting for VM "
707 "to go down...")
708 if kvm_utils.wait_for(self.is_dead, 60, 1, 1):
709 logging.debug("VM is down")
710 return
711 finally:
712 session.close()
lmr6f669ce2009-05-31 19:02:42 +0000713
lmr9e964a02010-06-18 03:46:21 +0000714 if self.monitor:
715 # Try to destroy with a monitor command
716 logging.debug("Trying to kill VM with monitor command...")
717 try:
718 self.monitor.quit()
719 except kvm_monitor.MonitorError, e:
720 logging.warn(e)
721 else:
722 # Wait for the VM to be really dead
723 if kvm_utils.wait_for(self.is_dead, 5, 0.5, 0.5):
724 logging.debug("VM is down")
725 return
lmrf320b042009-09-15 05:48:06 +0000726
727 # If the VM isn't dead yet...
728 logging.debug("Cannot quit normally; sending a kill to close the "
729 "deal...")
730 kvm_utils.kill_process_tree(self.process.get_pid(), 9)
lmr6f669ce2009-05-31 19:02:42 +0000731 # Wait for the VM to be really dead
732 if kvm_utils.wait_for(self.is_dead, 5, 0.5, 0.5):
733 logging.debug("VM is down")
lmr6f669ce2009-05-31 19:02:42 +0000734 return
735
lmrf320b042009-09-15 05:48:06 +0000736 logging.error("Process %s is a zombie!" % self.process.get_pid())
lmr6f669ce2009-05-31 19:02:42 +0000737
lmrf320b042009-09-15 05:48:06 +0000738 finally:
lmr9e964a02010-06-18 03:46:21 +0000739 self.monitors = []
lmr4513c432010-02-03 11:59:03 +0000740 if self.pci_assignable:
741 self.pci_assignable.release_devs()
lmrf320b042009-09-15 05:48:06 +0000742 if self.process:
743 self.process.close()
lmraa380a22010-06-22 02:05:29 +0000744 if self.serial_console:
745 self.serial_console.close()
lmr84546f22010-06-29 23:03:34 +0000746 for f in ([self.get_testlog_filename(),
747 self.get_serial_console_filename()] +
lmr9e964a02010-06-18 03:46:21 +0000748 self.get_monitor_filenames()):
749 try:
750 os.unlink(f)
751 except OSError:
752 pass
753
754
755 @property
756 def monitor(self):
757 """
758 Return the main monitor object, selected by the parameter main_monitor.
759 If main_monitor isn't defined, return the first monitor.
760 If no monitors exist, or if main_monitor refers to a nonexistent
761 monitor, return None.
762 """
763 for m in self.monitors:
764 if m.name == self.params.get("main_monitor"):
765 return m
766 if self.monitors and not self.params.get("main_monitor"):
767 return self.monitors[0]
lmr6f669ce2009-05-31 19:02:42 +0000768
769
770 def is_alive(self):
771 """
lmr9e964a02010-06-18 03:46:21 +0000772 Return True if the VM is alive and its monitor is responsive.
lmr6f669ce2009-05-31 19:02:42 +0000773 """
lmra4967622009-07-23 01:36:32 +0000774 # Check if the process is running
775 if self.is_dead():
lmr6f669ce2009-05-31 19:02:42 +0000776 return False
777 # Try sending a monitor command
lmr9e964a02010-06-18 03:46:21 +0000778 return bool(self.monitor) and self.monitor.is_responsive()
lmr6f669ce2009-05-31 19:02:42 +0000779
780
781 def is_dead(self):
782 """
lmra4967622009-07-23 01:36:32 +0000783 Return True if the qemu process is dead.
lmr6f669ce2009-05-31 19:02:42 +0000784 """
lmra4967622009-07-23 01:36:32 +0000785 return not self.process or not self.process.is_alive()
lmr6f669ce2009-05-31 19:02:42 +0000786
787
788 def get_params(self):
789 """
790 Return the VM's params dict. Most modified params take effect only
791 upon VM.create().
792 """
793 return self.params
794
795
lmr9e964a02010-06-18 03:46:21 +0000796 def get_monitor_filename(self, monitor_name):
797 """
798 Return the filename corresponding to a given monitor name.
799 """
800 return "/tmp/monitor-%s-%s" % (monitor_name, self.instance)
801
802
803 def get_monitor_filenames(self):
804 """
805 Return a list of all monitor filenames (as specified in the VM's
806 params).
807 """
808 return [self.get_monitor_filename(m) for m in
809 kvm_utils.get_sub_dict_names(self.params, "monitors")]
810
811
lmr2b06f332010-06-22 02:03:41 +0000812 def get_serial_console_filename(self):
813 """
814 Return the serial console filename.
815 """
816 return "/tmp/serial-%s" % self.instance
817
818
lmr9e964a02010-06-18 03:46:21 +0000819 def get_testlog_filename(self):
820 """
821 Return the testlog filename.
822 """
823 return "/tmp/testlog-%s" % self.instance
824
825
lmrf4696342009-08-13 04:06:33 +0000826 def get_address(self, index=0):
lmr6f669ce2009-05-31 19:02:42 +0000827 """
lmrf4696342009-08-13 04:06:33 +0000828 Return the address of a NIC of the guest, in host space.
lmr6f669ce2009-05-31 19:02:42 +0000829
lmrf4696342009-08-13 04:06:33 +0000830 If port redirection is used, return 'localhost' (the NIC has no IP
831 address of its own). Otherwise return the NIC's IP address.
832
833 @param index: Index of the NIC whose address is requested.
lmr6f669ce2009-05-31 19:02:42 +0000834 """
lmree90dd92009-08-13 04:13:39 +0000835 nics = kvm_utils.get_sub_dict_names(self.params, "nics")
836 nic_name = nics[index]
lmrf4696342009-08-13 04:06:33 +0000837 nic_params = kvm_utils.get_sub_dict(self.params, nic_name)
838 if nic_params.get("nic_mode") == "tap":
839 mac, ip = kvm_utils.get_mac_ip_pair_from_dict(nic_params)
lmree90dd92009-08-13 04:13:39 +0000840 if not mac:
841 logging.debug("MAC address unavailable")
842 return None
843 if not ip or nic_params.get("always_use_tcpdump") == "yes":
844 # Get the IP address from the cache
845 ip = self.address_cache.get(mac)
846 if not ip:
847 logging.debug("Could not find IP address for MAC address: "
848 "%s" % mac)
849 return None
850 # Make sure the IP address is assigned to this guest
851 nic_dicts = [kvm_utils.get_sub_dict(self.params, nic)
852 for nic in nics]
853 macs = [kvm_utils.get_mac_ip_pair_from_dict(dict)[0]
854 for dict in nic_dicts]
855 if not kvm_utils.verify_ip_address_ownership(ip, macs):
856 logging.debug("Could not verify MAC-IP address mapping: "
857 "%s ---> %s" % (mac, ip))
858 return None
lmrf4696342009-08-13 04:06:33 +0000859 return ip
860 else:
861 return "localhost"
lmr6f669ce2009-05-31 19:02:42 +0000862
863
lmree90dd92009-08-13 04:13:39 +0000864 def get_port(self, port, nic_index=0):
lmr6f669ce2009-05-31 19:02:42 +0000865 """
866 Return the port in host space corresponding to port in guest space.
867
868 @param port: Port number in host space.
lmree90dd92009-08-13 04:13:39 +0000869 @param nic_index: Index of the NIC.
lmr6f669ce2009-05-31 19:02:42 +0000870 @return: If port redirection is used, return the host port redirected
871 to guest port port. Otherwise return port.
872 """
lmree90dd92009-08-13 04:13:39 +0000873 nic_name = kvm_utils.get_sub_dict_names(self.params, "nics")[nic_index]
lmrf4696342009-08-13 04:06:33 +0000874 nic_params = kvm_utils.get_sub_dict(self.params, nic_name)
875 if nic_params.get("nic_mode") == "tap":
876 return port
lmr6f669ce2009-05-31 19:02:42 +0000877 else:
lmrf4696342009-08-13 04:06:33 +0000878 if not self.redirs.has_key(port):
879 logging.warn("Warning: guest port %s requested but not "
880 "redirected" % port)
881 return self.redirs.get(port)
lmr6f669ce2009-05-31 19:02:42 +0000882
883
lmra4967622009-07-23 01:36:32 +0000884 def get_pid(self):
885 """
lmr71fa4de2010-06-14 15:54:55 +0000886 Return the VM's PID. If the VM is dead return None.
887
888 @note: This works under the assumption that self.process.get_pid()
889 returns the PID of the parent shell process.
890 """
891 try:
892 children = commands.getoutput("ps --ppid=%d -o pid=" %
893 self.process.get_pid()).split()
894 return int(children[0])
895 except (TypeError, IndexError, ValueError):
896 return None
897
898
899 def get_shell_pid(self):
900 """
901 Return the PID of the parent shell process.
902
903 @note: This works under the assumption that self.process.get_pid()
904 returns the PID of the parent shell process.
lmra4967622009-07-23 01:36:32 +0000905 """
906 return self.process.get_pid()
907
908
lmr0bee2342010-02-24 00:01:37 +0000909 def get_shared_meminfo(self):
910 """
911 Returns the VM's shared memory information.
912
913 @return: Shared memory used by VM (MB)
914 """
915 if self.is_dead():
916 logging.error("Could not get shared memory info from dead VM.")
917 return None
918
lmr983ecdf2010-06-14 15:57:12 +0000919 filename = "/proc/%d/statm" % self.get_pid()
920 shm = int(open(filename).read().split()[2])
lmr0bee2342010-02-24 00:01:37 +0000921 # statm stores informations in pages, translate it to MB
lmr983ecdf2010-06-14 15:57:12 +0000922 return shm * 4.0 / 1024
lmr0bee2342010-02-24 00:01:37 +0000923
924
lmr912c74b2009-08-17 20:43:27 +0000925 def remote_login(self, nic_index=0, timeout=10):
lmr6f669ce2009-05-31 19:02:42 +0000926 """
lmr912c74b2009-08-17 20:43:27 +0000927 Log into the guest via SSH/Telnet/Netcat.
lmr6f669ce2009-05-31 19:02:42 +0000928 If timeout expires while waiting for output from the guest (e.g. a
929 password prompt or a shell prompt) -- fail.
930
lmree90dd92009-08-13 04:13:39 +0000931 @param nic_index: The index of the NIC to connect to.
lmr6f669ce2009-05-31 19:02:42 +0000932 @param timeout: Time (seconds) before giving up logging into the
933 guest.
934 @return: kvm_spawn object on success and None on failure.
935 """
936 username = self.params.get("username", "")
937 password = self.params.get("password", "")
lmr912c74b2009-08-17 20:43:27 +0000938 prompt = self.params.get("shell_prompt", "[\#\$]")
lmr59f9e2d2009-10-05 18:47:16 +0000939 linesep = eval("'%s'" % self.params.get("shell_linesep", r"\n"))
lmr912c74b2009-08-17 20:43:27 +0000940 client = self.params.get("shell_client")
lmree90dd92009-08-13 04:13:39 +0000941 address = self.get_address(nic_index)
lmr912c74b2009-08-17 20:43:27 +0000942 port = self.get_port(int(self.params.get("shell_port")))
lmre56903f2010-06-22 02:09:35 +0000943 log_filename = ("session-%s-%s.log" %
944 (self.name, kvm_utils.generate_random_string(4)))
lmr912c74b2009-08-17 20:43:27 +0000945
lmree90dd92009-08-13 04:13:39 +0000946 if not address or not port:
947 logging.debug("IP address or port unavailable")
lmr6f669ce2009-05-31 19:02:42 +0000948 return None
949
lmr158604f2010-06-22 01:57:34 +0000950 session = kvm_utils.remote_login(client, address, port, username,
lmre56903f2010-06-22 02:09:35 +0000951 password, prompt, linesep,
952 log_filename, timeout)
lmr912c74b2009-08-17 20:43:27 +0000953
lmr6f669ce2009-05-31 19:02:42 +0000954 if session:
lmr912c74b2009-08-17 20:43:27 +0000955 session.set_status_test_command(self.params.get("status_test_"
lmr6f669ce2009-05-31 19:02:42 +0000956 "command", ""))
957 return session
958
959
lmrc196d492010-05-07 14:14:26 +0000960 def copy_files_to(self, local_path, remote_path, nic_index=0, timeout=600):
lmr6f669ce2009-05-31 19:02:42 +0000961 """
lmr912c74b2009-08-17 20:43:27 +0000962 Transfer files to the guest.
lmr6f669ce2009-05-31 19:02:42 +0000963
964 @param local_path: Host path
965 @param remote_path: Guest path
lmr912c74b2009-08-17 20:43:27 +0000966 @param nic_index: The index of the NIC to connect to.
lmr6f669ce2009-05-31 19:02:42 +0000967 @param timeout: Time (seconds) before giving up on doing the remote
968 copy.
969 """
970 username = self.params.get("username", "")
971 password = self.params.get("password", "")
lmr912c74b2009-08-17 20:43:27 +0000972 client = self.params.get("file_transfer_client")
lmree90dd92009-08-13 04:13:39 +0000973 address = self.get_address(nic_index)
lmr912c74b2009-08-17 20:43:27 +0000974 port = self.get_port(int(self.params.get("file_transfer_port")))
975
lmree90dd92009-08-13 04:13:39 +0000976 if not address or not port:
977 logging.debug("IP address or port unavailable")
lmr6f669ce2009-05-31 19:02:42 +0000978 return None
lmr912c74b2009-08-17 20:43:27 +0000979
980 if client == "scp":
lmrcbc86ef2010-07-07 20:50:08 +0000981 log_filename = ("scp-%s-%s.log" %
982 (self.name, kvm_utils.generate_random_string(4)))
lmr912c74b2009-08-17 20:43:27 +0000983 return kvm_utils.scp_to_remote(address, port, username, password,
lmre56903f2010-06-22 02:09:35 +0000984 local_path, remote_path,
985 log_filename, timeout)
lmrcbc86ef2010-07-07 20:50:08 +0000986 elif client == "rss":
987 c = rss_file_transfer.FileUploadClient(address, port)
988 c.upload(local_path, remote_path, timeout)
989 c.close()
990 return True
lmr6f669ce2009-05-31 19:02:42 +0000991
992
lmrc196d492010-05-07 14:14:26 +0000993 def copy_files_from(self, remote_path, local_path, nic_index=0, timeout=600):
lmr6f669ce2009-05-31 19:02:42 +0000994 """
lmr912c74b2009-08-17 20:43:27 +0000995 Transfer files from the guest.
lmr6f669ce2009-05-31 19:02:42 +0000996
997 @param local_path: Guest path
998 @param remote_path: Host path
lmr912c74b2009-08-17 20:43:27 +0000999 @param nic_index: The index of the NIC to connect to.
lmr6f669ce2009-05-31 19:02:42 +00001000 @param timeout: Time (seconds) before giving up on doing the remote
1001 copy.
1002 """
1003 username = self.params.get("username", "")
1004 password = self.params.get("password", "")
lmr912c74b2009-08-17 20:43:27 +00001005 client = self.params.get("file_transfer_client")
lmree90dd92009-08-13 04:13:39 +00001006 address = self.get_address(nic_index)
lmr912c74b2009-08-17 20:43:27 +00001007 port = self.get_port(int(self.params.get("file_transfer_port")))
1008
lmree90dd92009-08-13 04:13:39 +00001009 if not address or not port:
1010 logging.debug("IP address or port unavailable")
lmr6f669ce2009-05-31 19:02:42 +00001011 return None
lmr6f669ce2009-05-31 19:02:42 +00001012
lmr912c74b2009-08-17 20:43:27 +00001013 if client == "scp":
lmrcbc86ef2010-07-07 20:50:08 +00001014 log_filename = ("scp-%s-%s.log" %
1015 (self.name, kvm_utils.generate_random_string(4)))
lmr912c74b2009-08-17 20:43:27 +00001016 return kvm_utils.scp_from_remote(address, port, username, password,
lmre56903f2010-06-22 02:09:35 +00001017 remote_path, local_path,
1018 log_filename, timeout)
lmrcbc86ef2010-07-07 20:50:08 +00001019 elif client == "rss":
1020 c = rss_file_transfer.FileDownloadClient(address, port)
1021 c.download(remote_path, local_path, timeout)
1022 c.close()
1023 return True
lmr6f669ce2009-05-31 19:02:42 +00001024
1025
lmraa380a22010-06-22 02:05:29 +00001026 def serial_login(self, timeout=10):
1027 """
1028 Log into the guest via the serial console.
1029 If timeout expires while waiting for output from the guest (e.g. a
1030 password prompt or a shell prompt) -- fail.
1031
1032 @param timeout: Time (seconds) before giving up logging into the guest.
1033 @return: kvm_spawn object on success and None on failure.
1034 """
1035 username = self.params.get("username", "")
1036 password = self.params.get("password", "")
1037 prompt = self.params.get("shell_prompt", "[\#\$]")
1038 linesep = eval("'%s'" % self.params.get("shell_linesep", r"\n"))
1039 status_test_command = self.params.get("status_test_command", "")
1040
1041 if self.serial_console:
1042 self.serial_console.set_linesep(linesep)
1043 self.serial_console.set_status_test_command(status_test_command)
1044 else:
1045 return None
1046
1047 # Make sure we get a login prompt
1048 self.serial_console.sendline()
1049
1050 if kvm_utils._remote_login(self.serial_console, username, password,
1051 prompt, timeout):
1052 return self.serial_console
1053
1054
lmr6f669ce2009-05-31 19:02:42 +00001055 def send_key(self, keystr):
1056 """
1057 Send a key event to the VM.
1058
1059 @param: keystr: A key event string (e.g. "ctrl-alt-delete")
1060 """
1061 # For compatibility with versions of QEMU that do not recognize all
1062 # key names: replace keyname with the hex value from the dict, which
1063 # QEMU will definitely accept
lmr9e964a02010-06-18 03:46:21 +00001064 dict = {"comma": "0x33",
1065 "dot": "0x34",
1066 "slash": "0x35"}
1067 for key, value in dict.items():
1068 keystr = keystr.replace(key, value)
1069 self.monitor.sendkey(keystr)
lmr6f669ce2009-05-31 19:02:42 +00001070 time.sleep(0.2)
1071
1072
1073 def send_string(self, str):
1074 """
1075 Send a string to the VM.
1076
1077 @param str: String, that must consist of alphanumeric characters only.
1078 Capital letters are allowed.
1079 """
1080 for char in str:
1081 if char.isupper():
1082 self.send_key("shift-%s" % char.lower())
1083 else:
1084 self.send_key(char)
lmra2533222009-07-20 12:43:46 +00001085
mbligh1ef218d2009-08-03 16:57:56 +00001086
lmra2533222009-07-20 12:43:46 +00001087 def get_uuid(self):
1088 """
1089 Catch UUID of the VM.
1090
1091 @return: None,if not specified in config file
1092 """
1093 if self.params.get("uuid") == "random":
1094 return self.uuid
1095 else:
1096 return self.params.get("uuid", None)
lmrdd2ff922009-12-01 23:39:12 +00001097
1098
1099 def get_cpu_count(self):
1100 """
1101 Get the cpu count of the VM.
1102 """
lmr13426552010-01-17 15:38:41 +00001103 session = self.remote_login()
1104 if not session:
1105 return None
lmrdd2ff922009-12-01 23:39:12 +00001106 try:
lmr13426552010-01-17 15:38:41 +00001107 cmd = self.params.get("cpu_chk_cmd")
1108 s, count = session.get_command_status_output(cmd)
1109 if s == 0:
1110 return int(count)
lmrdd2ff922009-12-01 23:39:12 +00001111 return None
1112 finally:
1113 session.close()
1114
1115
lmr28426c82010-04-16 06:02:58 +00001116 def get_memory_size(self, cmd=None):
lmrdd2ff922009-12-01 23:39:12 +00001117 """
lmr28426c82010-04-16 06:02:58 +00001118 Get bootup memory size of the VM.
1119
1120 @param check_cmd: Command used to check memory. If not provided,
1121 self.params.get("mem_chk_cmd") will be used.
lmrdd2ff922009-12-01 23:39:12 +00001122 """
lmr13426552010-01-17 15:38:41 +00001123 session = self.remote_login()
1124 if not session:
lmrdd2ff922009-12-01 23:39:12 +00001125 return None
lmr13426552010-01-17 15:38:41 +00001126 try:
lmr28426c82010-04-16 06:02:58 +00001127 if not cmd:
1128 cmd = self.params.get("mem_chk_cmd")
lmr13426552010-01-17 15:38:41 +00001129 s, mem_str = session.get_command_status_output(cmd)
1130 if s != 0:
1131 return None
lmr6d69f4d2010-02-12 11:35:55 +00001132 mem = re.findall("([0-9]+)", mem_str)
lmr13426552010-01-17 15:38:41 +00001133 mem_size = 0
1134 for m in mem:
1135 mem_size += int(m)
1136 if "GB" in mem_str:
1137 mem_size *= 1024
1138 elif "MB" in mem_str:
1139 pass
1140 else:
1141 mem_size /= 1024
1142 return int(mem_size)
lmrdd2ff922009-12-01 23:39:12 +00001143 finally:
1144 session.close()
lmr28426c82010-04-16 06:02:58 +00001145
1146
1147 def get_current_memory_size(self):
1148 """
1149 Get current memory size of the VM, rather than bootup memory.
1150 """
1151 cmd = self.params.get("mem_chk_cur_cmd")
1152 return self.get_memory_size(cmd)