blob: 87b9126d9e69ceeb313b7a8e621ad35c6880c6f6 [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
9import kvm_utils, kvm_subprocess, kvm_monitor
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
lmra4197002009-08-13 05:00:51 +0000788 def kill_tail_thread(self):
789 """
790 Stop the tailing thread which reports the output of qemu.
791 """
792 if self.process:
793 self.process.kill_tail_thread()
794
795
lmr6f669ce2009-05-31 19:02:42 +0000796 def get_params(self):
797 """
798 Return the VM's params dict. Most modified params take effect only
799 upon VM.create().
800 """
801 return self.params
802
803
lmr9e964a02010-06-18 03:46:21 +0000804 def get_monitor_filename(self, monitor_name):
805 """
806 Return the filename corresponding to a given monitor name.
807 """
808 return "/tmp/monitor-%s-%s" % (monitor_name, self.instance)
809
810
811 def get_monitor_filenames(self):
812 """
813 Return a list of all monitor filenames (as specified in the VM's
814 params).
815 """
816 return [self.get_monitor_filename(m) for m in
817 kvm_utils.get_sub_dict_names(self.params, "monitors")]
818
819
lmr2b06f332010-06-22 02:03:41 +0000820 def get_serial_console_filename(self):
821 """
822 Return the serial console filename.
823 """
824 return "/tmp/serial-%s" % self.instance
825
826
lmr9e964a02010-06-18 03:46:21 +0000827 def get_testlog_filename(self):
828 """
829 Return the testlog filename.
830 """
831 return "/tmp/testlog-%s" % self.instance
832
833
lmrf4696342009-08-13 04:06:33 +0000834 def get_address(self, index=0):
lmr6f669ce2009-05-31 19:02:42 +0000835 """
lmrf4696342009-08-13 04:06:33 +0000836 Return the address of a NIC of the guest, in host space.
lmr6f669ce2009-05-31 19:02:42 +0000837
lmrf4696342009-08-13 04:06:33 +0000838 If port redirection is used, return 'localhost' (the NIC has no IP
839 address of its own). Otherwise return the NIC's IP address.
840
841 @param index: Index of the NIC whose address is requested.
lmr6f669ce2009-05-31 19:02:42 +0000842 """
lmree90dd92009-08-13 04:13:39 +0000843 nics = kvm_utils.get_sub_dict_names(self.params, "nics")
844 nic_name = nics[index]
lmrf4696342009-08-13 04:06:33 +0000845 nic_params = kvm_utils.get_sub_dict(self.params, nic_name)
846 if nic_params.get("nic_mode") == "tap":
847 mac, ip = kvm_utils.get_mac_ip_pair_from_dict(nic_params)
lmree90dd92009-08-13 04:13:39 +0000848 if not mac:
849 logging.debug("MAC address unavailable")
850 return None
851 if not ip or nic_params.get("always_use_tcpdump") == "yes":
852 # Get the IP address from the cache
853 ip = self.address_cache.get(mac)
854 if not ip:
855 logging.debug("Could not find IP address for MAC address: "
856 "%s" % mac)
857 return None
858 # Make sure the IP address is assigned to this guest
859 nic_dicts = [kvm_utils.get_sub_dict(self.params, nic)
860 for nic in nics]
861 macs = [kvm_utils.get_mac_ip_pair_from_dict(dict)[0]
862 for dict in nic_dicts]
863 if not kvm_utils.verify_ip_address_ownership(ip, macs):
864 logging.debug("Could not verify MAC-IP address mapping: "
865 "%s ---> %s" % (mac, ip))
866 return None
lmrf4696342009-08-13 04:06:33 +0000867 return ip
868 else:
869 return "localhost"
lmr6f669ce2009-05-31 19:02:42 +0000870
871
lmree90dd92009-08-13 04:13:39 +0000872 def get_port(self, port, nic_index=0):
lmr6f669ce2009-05-31 19:02:42 +0000873 """
874 Return the port in host space corresponding to port in guest space.
875
876 @param port: Port number in host space.
lmree90dd92009-08-13 04:13:39 +0000877 @param nic_index: Index of the NIC.
lmr6f669ce2009-05-31 19:02:42 +0000878 @return: If port redirection is used, return the host port redirected
879 to guest port port. Otherwise return port.
880 """
lmree90dd92009-08-13 04:13:39 +0000881 nic_name = kvm_utils.get_sub_dict_names(self.params, "nics")[nic_index]
lmrf4696342009-08-13 04:06:33 +0000882 nic_params = kvm_utils.get_sub_dict(self.params, nic_name)
883 if nic_params.get("nic_mode") == "tap":
884 return port
lmr6f669ce2009-05-31 19:02:42 +0000885 else:
lmrf4696342009-08-13 04:06:33 +0000886 if not self.redirs.has_key(port):
887 logging.warn("Warning: guest port %s requested but not "
888 "redirected" % port)
889 return self.redirs.get(port)
lmr6f669ce2009-05-31 19:02:42 +0000890
891
lmra4967622009-07-23 01:36:32 +0000892 def get_pid(self):
893 """
lmr71fa4de2010-06-14 15:54:55 +0000894 Return the VM's PID. If the VM is dead return None.
895
896 @note: This works under the assumption that self.process.get_pid()
897 returns the PID of the parent shell process.
898 """
899 try:
900 children = commands.getoutput("ps --ppid=%d -o pid=" %
901 self.process.get_pid()).split()
902 return int(children[0])
903 except (TypeError, IndexError, ValueError):
904 return None
905
906
907 def get_shell_pid(self):
908 """
909 Return the PID of the parent shell process.
910
911 @note: This works under the assumption that self.process.get_pid()
912 returns the PID of the parent shell process.
lmra4967622009-07-23 01:36:32 +0000913 """
914 return self.process.get_pid()
915
916
lmr0bee2342010-02-24 00:01:37 +0000917 def get_shared_meminfo(self):
918 """
919 Returns the VM's shared memory information.
920
921 @return: Shared memory used by VM (MB)
922 """
923 if self.is_dead():
924 logging.error("Could not get shared memory info from dead VM.")
925 return None
926
lmr983ecdf2010-06-14 15:57:12 +0000927 filename = "/proc/%d/statm" % self.get_pid()
928 shm = int(open(filename).read().split()[2])
lmr0bee2342010-02-24 00:01:37 +0000929 # statm stores informations in pages, translate it to MB
lmr983ecdf2010-06-14 15:57:12 +0000930 return shm * 4.0 / 1024
lmr0bee2342010-02-24 00:01:37 +0000931
932
lmr912c74b2009-08-17 20:43:27 +0000933 def remote_login(self, nic_index=0, timeout=10):
lmr6f669ce2009-05-31 19:02:42 +0000934 """
lmr912c74b2009-08-17 20:43:27 +0000935 Log into the guest via SSH/Telnet/Netcat.
lmr6f669ce2009-05-31 19:02:42 +0000936 If timeout expires while waiting for output from the guest (e.g. a
937 password prompt or a shell prompt) -- fail.
938
lmree90dd92009-08-13 04:13:39 +0000939 @param nic_index: The index of the NIC to connect to.
lmr6f669ce2009-05-31 19:02:42 +0000940 @param timeout: Time (seconds) before giving up logging into the
941 guest.
942 @return: kvm_spawn object on success and None on failure.
943 """
944 username = self.params.get("username", "")
945 password = self.params.get("password", "")
lmr912c74b2009-08-17 20:43:27 +0000946 prompt = self.params.get("shell_prompt", "[\#\$]")
lmr59f9e2d2009-10-05 18:47:16 +0000947 linesep = eval("'%s'" % self.params.get("shell_linesep", r"\n"))
lmr912c74b2009-08-17 20:43:27 +0000948 client = self.params.get("shell_client")
lmree90dd92009-08-13 04:13:39 +0000949 address = self.get_address(nic_index)
lmr912c74b2009-08-17 20:43:27 +0000950 port = self.get_port(int(self.params.get("shell_port")))
lmre56903f2010-06-22 02:09:35 +0000951 log_filename = ("session-%s-%s.log" %
952 (self.name, kvm_utils.generate_random_string(4)))
lmr912c74b2009-08-17 20:43:27 +0000953
lmree90dd92009-08-13 04:13:39 +0000954 if not address or not port:
955 logging.debug("IP address or port unavailable")
lmr6f669ce2009-05-31 19:02:42 +0000956 return None
957
lmr158604f2010-06-22 01:57:34 +0000958 session = kvm_utils.remote_login(client, address, port, username,
lmre56903f2010-06-22 02:09:35 +0000959 password, prompt, linesep,
960 log_filename, timeout)
lmr912c74b2009-08-17 20:43:27 +0000961
lmr6f669ce2009-05-31 19:02:42 +0000962 if session:
lmr912c74b2009-08-17 20:43:27 +0000963 session.set_status_test_command(self.params.get("status_test_"
lmr6f669ce2009-05-31 19:02:42 +0000964 "command", ""))
965 return session
966
967
lmrc196d492010-05-07 14:14:26 +0000968 def copy_files_to(self, local_path, remote_path, nic_index=0, timeout=600):
lmr6f669ce2009-05-31 19:02:42 +0000969 """
lmr912c74b2009-08-17 20:43:27 +0000970 Transfer files to the guest.
lmr6f669ce2009-05-31 19:02:42 +0000971
972 @param local_path: Host path
973 @param remote_path: Guest path
lmr912c74b2009-08-17 20:43:27 +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 on doing the remote
976 copy.
977 """
978 username = self.params.get("username", "")
979 password = self.params.get("password", "")
lmr912c74b2009-08-17 20:43:27 +0000980 client = self.params.get("file_transfer_client")
lmree90dd92009-08-13 04:13:39 +0000981 address = self.get_address(nic_index)
lmr912c74b2009-08-17 20:43:27 +0000982 port = self.get_port(int(self.params.get("file_transfer_port")))
lmre56903f2010-06-22 02:09:35 +0000983 log_filename = ("scp-%s-%s.log" %
984 (self.name, kvm_utils.generate_random_string(4)))
lmr912c74b2009-08-17 20:43:27 +0000985
lmree90dd92009-08-13 04:13:39 +0000986 if not address or not port:
987 logging.debug("IP address or port unavailable")
lmr6f669ce2009-05-31 19:02:42 +0000988 return None
lmr912c74b2009-08-17 20:43:27 +0000989
990 if client == "scp":
991 return kvm_utils.scp_to_remote(address, port, username, password,
lmre56903f2010-06-22 02:09:35 +0000992 local_path, remote_path,
993 log_filename, timeout)
lmr6f669ce2009-05-31 19:02:42 +0000994
995
lmrc196d492010-05-07 14:14:26 +0000996 def copy_files_from(self, remote_path, local_path, nic_index=0, timeout=600):
lmr6f669ce2009-05-31 19:02:42 +0000997 """
lmr912c74b2009-08-17 20:43:27 +0000998 Transfer files from the guest.
lmr6f669ce2009-05-31 19:02:42 +0000999
1000 @param local_path: Guest path
1001 @param remote_path: Host path
lmr912c74b2009-08-17 20:43:27 +00001002 @param nic_index: The index of the NIC to connect to.
lmr6f669ce2009-05-31 19:02:42 +00001003 @param timeout: Time (seconds) before giving up on doing the remote
1004 copy.
1005 """
1006 username = self.params.get("username", "")
1007 password = self.params.get("password", "")
lmr912c74b2009-08-17 20:43:27 +00001008 client = self.params.get("file_transfer_client")
lmree90dd92009-08-13 04:13:39 +00001009 address = self.get_address(nic_index)
lmr912c74b2009-08-17 20:43:27 +00001010 port = self.get_port(int(self.params.get("file_transfer_port")))
lmre56903f2010-06-22 02:09:35 +00001011 log_filename = ("scp-%s-%s.log" %
1012 (self.name, kvm_utils.generate_random_string(4)))
lmr912c74b2009-08-17 20:43:27 +00001013
lmree90dd92009-08-13 04:13:39 +00001014 if not address or not port:
1015 logging.debug("IP address or port unavailable")
lmr6f669ce2009-05-31 19:02:42 +00001016 return None
lmr6f669ce2009-05-31 19:02:42 +00001017
lmr912c74b2009-08-17 20:43:27 +00001018 if client == "scp":
1019 return kvm_utils.scp_from_remote(address, port, username, password,
lmre56903f2010-06-22 02:09:35 +00001020 remote_path, local_path,
1021 log_filename, timeout)
lmr6f669ce2009-05-31 19:02:42 +00001022
1023
lmraa380a22010-06-22 02:05:29 +00001024 def serial_login(self, timeout=10):
1025 """
1026 Log into the guest via the serial console.
1027 If timeout expires while waiting for output from the guest (e.g. a
1028 password prompt or a shell prompt) -- fail.
1029
1030 @param timeout: Time (seconds) before giving up logging into the guest.
1031 @return: kvm_spawn object on success and None on failure.
1032 """
1033 username = self.params.get("username", "")
1034 password = self.params.get("password", "")
1035 prompt = self.params.get("shell_prompt", "[\#\$]")
1036 linesep = eval("'%s'" % self.params.get("shell_linesep", r"\n"))
1037 status_test_command = self.params.get("status_test_command", "")
1038
1039 if self.serial_console:
1040 self.serial_console.set_linesep(linesep)
1041 self.serial_console.set_status_test_command(status_test_command)
1042 else:
1043 return None
1044
1045 # Make sure we get a login prompt
1046 self.serial_console.sendline()
1047
1048 if kvm_utils._remote_login(self.serial_console, username, password,
1049 prompt, timeout):
1050 return self.serial_console
1051
1052
lmr6f669ce2009-05-31 19:02:42 +00001053 def send_key(self, keystr):
1054 """
1055 Send a key event to the VM.
1056
1057 @param: keystr: A key event string (e.g. "ctrl-alt-delete")
1058 """
1059 # For compatibility with versions of QEMU that do not recognize all
1060 # key names: replace keyname with the hex value from the dict, which
1061 # QEMU will definitely accept
lmr9e964a02010-06-18 03:46:21 +00001062 dict = {"comma": "0x33",
1063 "dot": "0x34",
1064 "slash": "0x35"}
1065 for key, value in dict.items():
1066 keystr = keystr.replace(key, value)
1067 self.monitor.sendkey(keystr)
lmr6f669ce2009-05-31 19:02:42 +00001068 time.sleep(0.2)
1069
1070
1071 def send_string(self, str):
1072 """
1073 Send a string to the VM.
1074
1075 @param str: String, that must consist of alphanumeric characters only.
1076 Capital letters are allowed.
1077 """
1078 for char in str:
1079 if char.isupper():
1080 self.send_key("shift-%s" % char.lower())
1081 else:
1082 self.send_key(char)
lmra2533222009-07-20 12:43:46 +00001083
mbligh1ef218d2009-08-03 16:57:56 +00001084
lmra2533222009-07-20 12:43:46 +00001085 def get_uuid(self):
1086 """
1087 Catch UUID of the VM.
1088
1089 @return: None,if not specified in config file
1090 """
1091 if self.params.get("uuid") == "random":
1092 return self.uuid
1093 else:
1094 return self.params.get("uuid", None)
lmrdd2ff922009-12-01 23:39:12 +00001095
1096
1097 def get_cpu_count(self):
1098 """
1099 Get the cpu count of the VM.
1100 """
lmr13426552010-01-17 15:38:41 +00001101 session = self.remote_login()
1102 if not session:
1103 return None
lmrdd2ff922009-12-01 23:39:12 +00001104 try:
lmr13426552010-01-17 15:38:41 +00001105 cmd = self.params.get("cpu_chk_cmd")
1106 s, count = session.get_command_status_output(cmd)
1107 if s == 0:
1108 return int(count)
lmrdd2ff922009-12-01 23:39:12 +00001109 return None
1110 finally:
1111 session.close()
1112
1113
lmr28426c82010-04-16 06:02:58 +00001114 def get_memory_size(self, cmd=None):
lmrdd2ff922009-12-01 23:39:12 +00001115 """
lmr28426c82010-04-16 06:02:58 +00001116 Get bootup memory size of the VM.
1117
1118 @param check_cmd: Command used to check memory. If not provided,
1119 self.params.get("mem_chk_cmd") will be used.
lmrdd2ff922009-12-01 23:39:12 +00001120 """
lmr13426552010-01-17 15:38:41 +00001121 session = self.remote_login()
1122 if not session:
lmrdd2ff922009-12-01 23:39:12 +00001123 return None
lmr13426552010-01-17 15:38:41 +00001124 try:
lmr28426c82010-04-16 06:02:58 +00001125 if not cmd:
1126 cmd = self.params.get("mem_chk_cmd")
lmr13426552010-01-17 15:38:41 +00001127 s, mem_str = session.get_command_status_output(cmd)
1128 if s != 0:
1129 return None
lmr6d69f4d2010-02-12 11:35:55 +00001130 mem = re.findall("([0-9]+)", mem_str)
lmr13426552010-01-17 15:38:41 +00001131 mem_size = 0
1132 for m in mem:
1133 mem_size += int(m)
1134 if "GB" in mem_str:
1135 mem_size *= 1024
1136 elif "MB" in mem_str:
1137 pass
1138 else:
1139 mem_size /= 1024
1140 return int(mem_size)
lmrdd2ff922009-12-01 23:39:12 +00001141 finally:
1142 session.close()
lmr28426c82010-04-16 06:02:58 +00001143
1144
1145 def get_current_memory_size(self):
1146 """
1147 Get current memory size of the VM, rather than bootup memory.
1148 """
1149 cmd = self.params.get("mem_chk_cur_cmd")
1150 return self.get_memory_size(cmd)