blob: f6f168486e6178b1de61b1d3ba72a27c1bbe80d2 [file] [log] [blame]
lmr6f669ce2009-05-31 19:02:42 +00001#!/usr/bin/python
lmr6f669ce2009-05-31 19:02:42 +00002"""
3Utility classes and functions to handle Virtual Machine creation using qemu.
4
5@copyright: 2008-2009 Red Hat Inc.
6"""
7
Eric Lie0493a42010-11-15 13:05:43 -08008import time, socket, os, logging, fcntl, re, commands, shelve, glob
lmrcbc86ef2010-07-07 20:50:08 +00009import kvm_utils, kvm_subprocess, kvm_monitor, rss_file_transfer
lmr47a853b2010-02-04 13:56:48 +000010from autotest_lib.client.common_lib import error
lmrd60882f2010-02-04 03:26:36 +000011from autotest_lib.client.bin import utils
lmrb635b862009-09-10 14:53:21 +000012
lmr6f669ce2009-05-31 19:02:42 +000013
lmr90b9fd52009-08-17 20:48:18 +000014def get_image_filename(params, root_dir):
lmr6f669ce2009-05-31 19:02:42 +000015 """
lmr90b9fd52009-08-17 20:48:18 +000016 Generate an image path from params and root_dir.
lmr6f669ce2009-05-31 19:02:42 +000017
18 @param params: Dictionary containing the test parameters.
lmr90b9fd52009-08-17 20:48:18 +000019 @param root_dir: Base directory for relative filenames.
lmr6f669ce2009-05-31 19:02:42 +000020
21 @note: params should contain:
22 image_name -- the name of the image file, without extension
23 image_format -- the format of the image (qcow2, raw etc)
24 """
25 image_name = params.get("image_name", "image")
26 image_format = params.get("image_format", "qcow2")
Eric Li7edb3042011-01-06 17:57:17 -080027 if params.get("image_raw_device") == "yes":
28 return image_name
lmr6f669ce2009-05-31 19:02:42 +000029 image_filename = "%s.%s" % (image_name, image_format)
lmr90b9fd52009-08-17 20:48:18 +000030 image_filename = kvm_utils.get_path(root_dir, image_filename)
lmr6f669ce2009-05-31 19:02:42 +000031 return image_filename
32
33
lmr52800ba2009-08-17 20:49:58 +000034def create_image(params, root_dir):
lmr6f669ce2009-05-31 19:02:42 +000035 """
36 Create an image using qemu_image.
37
38 @param params: Dictionary containing the test parameters.
lmr90b9fd52009-08-17 20:48:18 +000039 @param root_dir: Base directory for relative filenames.
lmr6f669ce2009-05-31 19:02:42 +000040
41 @note: params should contain:
42 image_name -- the name of the image file, without extension
43 image_format -- the format of the image (qcow2, raw etc)
44 image_size -- the requested size of the image (a string
45 qemu-img can understand, such as '10G')
46 """
lmr52800ba2009-08-17 20:49:58 +000047 qemu_img_cmd = kvm_utils.get_path(root_dir, params.get("qemu_img_binary",
48 "qemu-img"))
lmr6f669ce2009-05-31 19:02:42 +000049 qemu_img_cmd += " create"
50
51 format = params.get("image_format", "qcow2")
52 qemu_img_cmd += " -f %s" % format
53
lmr90b9fd52009-08-17 20:48:18 +000054 image_filename = get_image_filename(params, root_dir)
lmr6f669ce2009-05-31 19:02:42 +000055 qemu_img_cmd += " %s" % image_filename
56
57 size = params.get("image_size", "10G")
58 qemu_img_cmd += " %s" % size
59
lmr47a853b2010-02-04 13:56:48 +000060 try:
61 utils.system(qemu_img_cmd)
62 except error.CmdError, e:
63 logging.error("Could not create image; qemu-img command failed:\n%s",
64 str(e))
65 return None
lmr6f669ce2009-05-31 19:02:42 +000066
lmr6f669ce2009-05-31 19:02:42 +000067 if not os.path.exists(image_filename):
lmra4967622009-07-23 01:36:32 +000068 logging.error("Image could not be created for some reason; "
69 "qemu-img command:\n%s" % qemu_img_cmd)
lmr6f669ce2009-05-31 19:02:42 +000070 return None
71
72 logging.info("Image created in %s" % image_filename)
73 return image_filename
74
75
lmr90b9fd52009-08-17 20:48:18 +000076def remove_image(params, root_dir):
lmr6f669ce2009-05-31 19:02:42 +000077 """
78 Remove an image file.
79
80 @param params: A dict
lmr90b9fd52009-08-17 20:48:18 +000081 @param root_dir: Base directory for relative filenames.
lmr6f669ce2009-05-31 19:02:42 +000082
83 @note: params should contain:
84 image_name -- the name of the image file, without extension
85 image_format -- the format of the image (qcow2, raw etc)
86 """
lmr90b9fd52009-08-17 20:48:18 +000087 image_filename = get_image_filename(params, root_dir)
lmr6f669ce2009-05-31 19:02:42 +000088 logging.debug("Removing image file %s..." % image_filename)
89 if os.path.exists(image_filename):
90 os.unlink(image_filename)
91 else:
92 logging.debug("Image file %s not found")
93
94
95class VM:
96 """
97 This class handles all basic VM operations.
98 """
99
Eric Li7edb3042011-01-06 17:57:17 -0800100 def __init__(self, name, params, root_dir, address_cache, state=None):
lmr6f669ce2009-05-31 19:02:42 +0000101 """
102 Initialize the object and set a few attributes.
103
104 @param name: The name of the object
105 @param params: A dict containing VM params
106 (see method make_qemu_command for a full description)
lmr90b9fd52009-08-17 20:48:18 +0000107 @param root_dir: Base directory for relative filenames
lmree90dd92009-08-13 04:13:39 +0000108 @param address_cache: A dict that maps MAC addresses to IP addresses
Eric Li7edb3042011-01-06 17:57:17 -0800109 @param state: If provided, use this as self.__dict__
lmr6f669ce2009-05-31 19:02:42 +0000110 """
Eric Li7edb3042011-01-06 17:57:17 -0800111 if state:
112 self.__dict__ = state
113 else:
114 self.process = None
115 self.serial_console = None
116 self.redirs = {}
117 self.vnc_port = 5900
118 self.monitors = []
119 self.pci_assignable = None
120 self.netdev_id = []
121 self.uuid = None
122
123 # Find a unique identifier for this VM
124 while True:
125 self.instance = (time.strftime("%Y%m%d-%H%M%S-") +
126 kvm_utils.generate_random_string(4))
127 if not glob.glob("/tmp/*%s" % self.instance):
128 break
lmr6f669ce2009-05-31 19:02:42 +0000129
130 self.name = name
131 self.params = params
lmr90b9fd52009-08-17 20:48:18 +0000132 self.root_dir = root_dir
lmree90dd92009-08-13 04:13:39 +0000133 self.address_cache = address_cache
lmr6f669ce2009-05-31 19:02:42 +0000134
lmr8b134f92009-06-08 14:47:31 +0000135
Eric Li7edb3042011-01-06 17:57:17 -0800136 def clone(self, name=None, params=None, root_dir=None, address_cache=None,
137 copy_state=False):
lmr2c241172009-06-08 15:11:29 +0000138 """
139 Return a clone of the VM object with optionally modified parameters.
140 The clone is initially not alive and needs to be started using create().
141 Any parameters not passed to this function are copied from the source
142 VM.
143
144 @param name: Optional new VM name
145 @param params: Optional new VM creation parameters
lmr90b9fd52009-08-17 20:48:18 +0000146 @param root_dir: Optional new base directory for relative filenames
lmree90dd92009-08-13 04:13:39 +0000147 @param address_cache: A dict that maps MAC addresses to IP addresses
Eric Li7edb3042011-01-06 17:57:17 -0800148 @param copy_state: If True, copy the original VM's state to the clone.
149 Mainly useful for make_qemu_command().
lmr2c241172009-06-08 15:11:29 +0000150 """
lmre45a1f22009-11-10 16:35:08 +0000151 if name is None:
lmr2c241172009-06-08 15:11:29 +0000152 name = self.name
lmre45a1f22009-11-10 16:35:08 +0000153 if params is None:
lmr2c241172009-06-08 15:11:29 +0000154 params = self.params.copy()
lmre45a1f22009-11-10 16:35:08 +0000155 if root_dir is None:
lmr90b9fd52009-08-17 20:48:18 +0000156 root_dir = self.root_dir
lmre45a1f22009-11-10 16:35:08 +0000157 if address_cache is None:
lmree90dd92009-08-13 04:13:39 +0000158 address_cache = self.address_cache
Eric Li7edb3042011-01-06 17:57:17 -0800159 if copy_state:
160 state = self.__dict__.copy()
161 else:
162 state = None
163 return VM(name, params, root_dir, address_cache, state)
lmr2c241172009-06-08 15:11:29 +0000164
165
lmr52800ba2009-08-17 20:49:58 +0000166 def make_qemu_command(self, name=None, params=None, root_dir=None):
lmr6f669ce2009-05-31 19:02:42 +0000167 """
168 Generate a qemu command line. All parameters are optional. If a
169 parameter is not supplied, the corresponding value stored in the
170 class attributes is used.
171
lmr6f669ce2009-05-31 19:02:42 +0000172 @param name: The name of the object
173 @param params: A dict containing VM params
lmr90b9fd52009-08-17 20:48:18 +0000174 @param root_dir: Base directory for relative filenames
lmr6f669ce2009-05-31 19:02:42 +0000175
176 @note: The params dict should contain:
177 mem -- memory size in MBs
178 cdrom -- ISO filename to use with the qemu -cdrom parameter
lmr6f669ce2009-05-31 19:02:42 +0000179 extra_params -- a string to append to the qemu command
lmr912c74b2009-08-17 20:43:27 +0000180 shell_port -- port of the remote shell daemon on the guest
181 (SSH, Telnet or the home-made Remote Shell Server)
182 shell_client -- client program to use for connecting to the
183 remote shell daemon on the guest (ssh, telnet or nc)
lmreeff0eb2009-06-10 19:19:15 +0000184 x11_display -- if specified, the DISPLAY environment variable
185 will be be set to this value for the qemu process (useful for
186 SDL rendering)
lmr6f669ce2009-05-31 19:02:42 +0000187 images -- a list of image object names, separated by spaces
188 nics -- a list of NIC object names, separated by spaces
189
190 For each image in images:
191 drive_format -- string to pass as 'if' parameter for this
192 image (e.g. ide, scsi)
193 image_snapshot -- if yes, pass 'snapshot=on' to qemu for
194 this image
195 image_boot -- if yes, pass 'boot=on' to qemu for this image
196 In addition, all parameters required by get_image_filename.
197
198 For each NIC in nics:
199 nic_model -- string to pass as 'model' parameter for this
200 NIC (e.g. e1000)
201 """
lmr48abd7d2010-05-26 13:48:04 +0000202 # Helper function for command line option wrappers
203 def has_option(help, option):
204 return bool(re.search(r"^-%s(\s|$)" % option, help, re.MULTILINE))
205
206 # Wrappers for all supported qemu command line parameters.
207 # This is meant to allow support for multiple qemu versions.
208 # Each of these functions receives the output of 'qemu -help' as a
209 # parameter, and should add the requested command line option
210 # accordingly.
211
212 def add_name(help, name):
213 return " -name '%s'" % name
214
lmr9e964a02010-06-18 03:46:21 +0000215 def add_human_monitor(help, filename):
lmr09a78162010-06-14 16:29:23 +0000216 return " -monitor unix:'%s',server,nowait" % filename
lmr48abd7d2010-05-26 13:48:04 +0000217
lmr9e964a02010-06-18 03:46:21 +0000218 def add_qmp_monitor(help, filename):
219 return " -qmp unix:'%s',server,nowait" % filename
220
lmr2b06f332010-06-22 02:03:41 +0000221 def add_serial(help, filename):
222 return " -serial unix:'%s',server,nowait" % filename
223
lmr48abd7d2010-05-26 13:48:04 +0000224 def add_mem(help, mem):
225 return " -m %s" % mem
226
227 def add_smp(help, smp):
228 return " -smp %s" % smp
229
lmraf709702010-07-20 00:56:33 +0000230 def add_cdrom(help, filename, index=None):
lmr48abd7d2010-05-26 13:48:04 +0000231 if has_option(help, "drive"):
lmraf709702010-07-20 00:56:33 +0000232 cmd = " -drive file='%s',media=cdrom" % filename
233 if index is not None: cmd += ",index=%s" % index
234 return cmd
lmr48abd7d2010-05-26 13:48:04 +0000235 else:
lmr09a78162010-06-14 16:29:23 +0000236 return " -cdrom '%s'" % filename
lmr48abd7d2010-05-26 13:48:04 +0000237
lmraf709702010-07-20 00:56:33 +0000238 def add_drive(help, filename, index=None, format=None, cache=None,
239 werror=None, serial=None, snapshot=False, boot=False):
lmr09a78162010-06-14 16:29:23 +0000240 cmd = " -drive file='%s'" % filename
lmraf709702010-07-20 00:56:33 +0000241 if index is not None: cmd += ",index=%s" % index
lmr48abd7d2010-05-26 13:48:04 +0000242 if format: cmd += ",if=%s" % format
243 if cache: cmd += ",cache=%s" % cache
244 if werror: cmd += ",werror=%s" % werror
lmr09a78162010-06-14 16:29:23 +0000245 if serial: cmd += ",serial='%s'" % serial
lmr48abd7d2010-05-26 13:48:04 +0000246 if snapshot: cmd += ",snapshot=on"
247 if boot: cmd += ",boot=on"
248 return cmd
249
Eric Lie0493a42010-11-15 13:05:43 -0800250 def add_nic(help, vlan, model=None, mac=None, netdev_id=None,
251 nic_extra_params=None):
Eric Li7edb3042011-01-06 17:57:17 -0800252 if has_option(help, "netdev"):
253 netdev_vlan_str = ",netdev=%s" % netdev_id
254 else:
255 netdev_vlan_str = ",vlan=%d" % vlan
Eric Lie0493a42010-11-15 13:05:43 -0800256 if has_option(help, "device"):
Eric Lie0493a42010-11-15 13:05:43 -0800257 if not model:
Eric Li7edb3042011-01-06 17:57:17 -0800258 model = "rtl8139"
259 elif model == "virtio":
260 model = "virtio-net-pci"
261 cmd = " -device %s" % model + netdev_vlan_str
Eric Lie0493a42010-11-15 13:05:43 -0800262 if mac:
Eric Li7edb3042011-01-06 17:57:17 -0800263 cmd += ",mac='%s'" % mac
Eric Lie0493a42010-11-15 13:05:43 -0800264 if nic_extra_params:
265 cmd += ",%s" % nic_extra_params
Eric Li6f27d4f2010-09-29 10:55:17 -0700266 else:
Eric Li7edb3042011-01-06 17:57:17 -0800267 cmd = " -net nic" + netdev_vlan_str
Eric Lie0493a42010-11-15 13:05:43 -0800268 if model:
269 cmd += ",model=%s" % model
270 if mac:
271 cmd += ",macaddr='%s'" % mac
lmr48abd7d2010-05-26 13:48:04 +0000272 return cmd
273
274 def add_net(help, vlan, mode, ifname=None, script=None,
lmr6976faa2010-07-09 21:11:06 +0000275 downscript=None, tftp=None, bootfile=None, hostfwd=[],
Eric Li7edb3042011-01-06 17:57:17 -0800276 netdev_id=None, netdev_extra_params=None):
lmrb1cad1e2010-06-17 17:36:09 +0000277 if has_option(help, "netdev"):
278 cmd = " -netdev %s,id=%s" % (mode, netdev_id)
Eric Li7edb3042011-01-06 17:57:17 -0800279 if netdev_extra_params:
280 cmd += ",%s" % netdev_extra_params
lmrb1cad1e2010-06-17 17:36:09 +0000281 else:
282 cmd = " -net %s,vlan=%d" % (mode, vlan)
lmr48abd7d2010-05-26 13:48:04 +0000283 if mode == "tap":
lmr09a78162010-06-14 16:29:23 +0000284 if ifname: cmd += ",ifname='%s'" % ifname
285 if script: cmd += ",script='%s'" % script
286 cmd += ",downscript='%s'" % (downscript or "no")
lmr6976faa2010-07-09 21:11:06 +0000287 elif mode == "user":
288 if tftp and "[,tftp=" in help:
289 cmd += ",tftp='%s'" % tftp
290 if bootfile and "[,bootfile=" in help:
291 cmd += ",bootfile='%s'" % bootfile
292 if "[,hostfwd=" in help:
293 for host_port, guest_port in hostfwd:
294 cmd += ",hostfwd=tcp::%s-:%s" % (host_port, guest_port)
lmr48abd7d2010-05-26 13:48:04 +0000295 return cmd
296
297 def add_floppy(help, filename):
lmr09a78162010-06-14 16:29:23 +0000298 return " -fda '%s'" % filename
lmr48abd7d2010-05-26 13:48:04 +0000299
300 def add_tftp(help, filename):
lmr6976faa2010-07-09 21:11:06 +0000301 # If the new syntax is supported, don't add -tftp
302 if "[,tftp=" in help:
303 return ""
304 else:
305 return " -tftp '%s'" % filename
306
307 def add_bootp(help, filename):
308 # If the new syntax is supported, don't add -bootp
309 if "[,bootfile=" in help:
310 return ""
311 else:
312 return " -bootp '%s'" % filename
lmr48abd7d2010-05-26 13:48:04 +0000313
314 def add_tcp_redir(help, host_port, guest_port):
lmr6976faa2010-07-09 21:11:06 +0000315 # If the new syntax is supported, don't add -redir
316 if "[,hostfwd=" in help:
317 return ""
318 else:
319 return " -redir tcp:%s::%s" % (host_port, guest_port)
lmr48abd7d2010-05-26 13:48:04 +0000320
321 def add_vnc(help, vnc_port):
322 return " -vnc :%d" % (vnc_port - 5900)
323
324 def add_sdl(help):
325 if has_option(help, "sdl"):
326 return " -sdl"
327 else:
328 return ""
329
330 def add_nographic(help):
331 return " -nographic"
332
333 def add_uuid(help, uuid):
lmr09a78162010-06-14 16:29:23 +0000334 return " -uuid '%s'" % uuid
lmr48abd7d2010-05-26 13:48:04 +0000335
336 def add_pcidevice(help, host):
lmr09a78162010-06-14 16:29:23 +0000337 return " -pcidevice host='%s'" % host
lmr48abd7d2010-05-26 13:48:04 +0000338
lmr41cb8fc2010-06-10 15:30:45 +0000339 def add_kernel(help, filename):
lmr09a78162010-06-14 16:29:23 +0000340 return " -kernel '%s'" % filename
lmr41cb8fc2010-06-10 15:30:45 +0000341
342 def add_initrd(help, filename):
lmr09a78162010-06-14 16:29:23 +0000343 return " -initrd '%s'" % filename
lmr41cb8fc2010-06-10 15:30:45 +0000344
lmre0474e32010-06-29 14:10:09 +0000345 def add_kernel_cmdline(help, cmdline):
346 return " -append %s" % cmdline
347
lmr71024552010-06-29 14:12:35 +0000348 def add_testdev(help, filename):
349 return (" -chardev file,id=testlog,path=%s"
350 " -device testdev,chardev=testlog" % filename)
351
lmrce5c9252010-06-30 17:41:00 +0000352 def add_no_hpet(help):
353 if has_option(help, "no-hpet"):
354 return " -no-hpet"
355 else:
356 return ""
357
lmr48abd7d2010-05-26 13:48:04 +0000358 # End of command line option wrappers
359
360 if name is None: name = self.name
361 if params is None: params = self.params
362 if root_dir is None: root_dir = self.root_dir
363
Eric Li7edb3042011-01-06 17:57:17 -0800364 # Clone this VM using the new params
365 vm = self.clone(name, params, root_dir, copy_state=True)
366
lmr48abd7d2010-05-26 13:48:04 +0000367 qemu_binary = kvm_utils.get_path(root_dir, params.get("qemu_binary",
368 "qemu"))
369 # Get the output of 'qemu -help' (log a message in case this call never
370 # returns or causes some other kind of trouble)
371 logging.debug("Getting output of 'qemu -help'")
372 help = commands.getoutput("%s -help" % qemu_binary)
lmr6f669ce2009-05-31 19:02:42 +0000373
lmreeff0eb2009-06-10 19:19:15 +0000374 # Start constructing the qemu command
375 qemu_cmd = ""
376 # Set the X11 display parameter if requested
377 if params.get("x11_display"):
378 qemu_cmd += "DISPLAY=%s " % params.get("x11_display")
379 # Add the qemu binary
lmr48abd7d2010-05-26 13:48:04 +0000380 qemu_cmd += qemu_binary
lmreeff0eb2009-06-10 19:19:15 +0000381 # Add the VM's name
lmr48abd7d2010-05-26 13:48:04 +0000382 qemu_cmd += add_name(help, name)
lmr9e964a02010-06-18 03:46:21 +0000383 # Add monitors
Eric Li7edb3042011-01-06 17:57:17 -0800384 for monitor_name in params.objects("monitors"):
385 monitor_params = params.object_params(monitor_name)
386 monitor_filename = vm.get_monitor_filename(monitor_name)
lmr9e964a02010-06-18 03:46:21 +0000387 if monitor_params.get("monitor_type") == "qmp":
388 qemu_cmd += add_qmp_monitor(help, monitor_filename)
389 else:
390 qemu_cmd += add_human_monitor(help, monitor_filename)
lmr6f669ce2009-05-31 19:02:42 +0000391
lmr2b06f332010-06-22 02:03:41 +0000392 # Add serial console redirection
Eric Li7edb3042011-01-06 17:57:17 -0800393 qemu_cmd += add_serial(help, vm.get_serial_console_filename())
lmr2b06f332010-06-22 02:03:41 +0000394
Eric Li7edb3042011-01-06 17:57:17 -0800395 for image_name in params.objects("images"):
396 image_params = params.object_params(image_name)
lmr9d75ee32009-09-29 13:14:13 +0000397 if image_params.get("boot_drive") == "no":
398 continue
lmr48abd7d2010-05-26 13:48:04 +0000399 qemu_cmd += add_drive(help,
400 get_image_filename(image_params, root_dir),
lmraf709702010-07-20 00:56:33 +0000401 image_params.get("drive_index"),
lmr48abd7d2010-05-26 13:48:04 +0000402 image_params.get("drive_format"),
403 image_params.get("drive_cache"),
404 image_params.get("drive_werror"),
405 image_params.get("drive_serial"),
406 image_params.get("image_snapshot") == "yes",
407 image_params.get("image_boot") == "yes")
lmr6f669ce2009-05-31 19:02:42 +0000408
lmr6976faa2010-07-09 21:11:06 +0000409 redirs = []
Eric Li7edb3042011-01-06 17:57:17 -0800410 for redir_name in params.objects("redirs"):
411 redir_params = params.object_params(redir_name)
lmr6976faa2010-07-09 21:11:06 +0000412 guest_port = int(redir_params.get("guest_port"))
Eric Li7edb3042011-01-06 17:57:17 -0800413 host_port = vm.redirs.get(guest_port)
lmr6976faa2010-07-09 21:11:06 +0000414 redirs += [(host_port, guest_port)]
415
lmr6f669ce2009-05-31 19:02:42 +0000416 vlan = 0
Eric Li7edb3042011-01-06 17:57:17 -0800417 for nic_name in params.objects("nics"):
418 nic_params = params.object_params(nic_name)
419 try:
420 netdev_id = vm.netdev_id[vlan]
421 except IndexError:
422 netdev_id = None
lmrf4696342009-08-13 04:06:33 +0000423 # Handle the '-net nic' part
Eric Li7edb3042011-01-06 17:57:17 -0800424 mac = vm.get_mac_address(vlan)
lmrb1cad1e2010-06-17 17:36:09 +0000425 qemu_cmd += add_nic(help, vlan, nic_params.get("nic_model"), mac,
Eric Li7edb3042011-01-06 17:57:17 -0800426 netdev_id, nic_params.get("nic_extra_params"))
lmrf4696342009-08-13 04:06:33 +0000427 # Handle the '-net tap' or '-net user' part
lmre4eaa862010-06-01 19:15:14 +0000428 script = nic_params.get("nic_script")
429 downscript = nic_params.get("nic_downscript")
lmr6976faa2010-07-09 21:11:06 +0000430 tftp = nic_params.get("tftp")
lmr48abd7d2010-05-26 13:48:04 +0000431 if script:
432 script = kvm_utils.get_path(root_dir, script)
433 if downscript:
434 downscript = kvm_utils.get_path(root_dir, downscript)
lmr6976faa2010-07-09 21:11:06 +0000435 if tftp:
436 tftp = kvm_utils.get_path(root_dir, tftp)
lmr48abd7d2010-05-26 13:48:04 +0000437 qemu_cmd += add_net(help, vlan, nic_params.get("nic_mode", "user"),
Eric Li7edb3042011-01-06 17:57:17 -0800438 vm.get_ifname(vlan),
lmr6976faa2010-07-09 21:11:06 +0000439 script, downscript, tftp,
Eric Li7edb3042011-01-06 17:57:17 -0800440 nic_params.get("bootp"), redirs, netdev_id,
441 nic_params.get("netdev_extra_params"))
lmrf4696342009-08-13 04:06:33 +0000442 # Proceed to next NIC
lmr6f669ce2009-05-31 19:02:42 +0000443 vlan += 1
444
445 mem = params.get("mem")
446 if mem:
lmr48abd7d2010-05-26 13:48:04 +0000447 qemu_cmd += add_mem(help, mem)
lmr6f669ce2009-05-31 19:02:42 +0000448
lmrc43bf372009-11-10 13:19:00 +0000449 smp = params.get("smp")
450 if smp:
lmrdb3fe612010-06-14 16:19:28 +0000451 qemu_cmd += add_smp(help, smp)
lmrc43bf372009-11-10 13:19:00 +0000452
Eric Li7edb3042011-01-06 17:57:17 -0800453 for cdrom in params.objects("cdroms"):
454 cdrom_params = params.object_params(cdrom)
lmrac5dce72010-07-20 00:58:25 +0000455 iso = cdrom_params.get("cdrom")
456 if iso:
457 qemu_cmd += add_cdrom(help, kvm_utils.get_path(root_dir, iso),
458 cdrom_params.get("drive_index"))
lmr6f669ce2009-05-31 19:02:42 +0000459
lmrb0a9b762009-10-09 20:43:30 +0000460 # We may want to add {floppy_otps} parameter for -fda
lmr48abd7d2010-05-26 13:48:04 +0000461 # {fat:floppy:}/path/. However vvfat is not usually recommended.
lmrb0a9b762009-10-09 20:43:30 +0000462 floppy = params.get("floppy")
463 if floppy:
lmrf69f6b12009-11-10 16:33:44 +0000464 floppy = kvm_utils.get_path(root_dir, floppy)
lmr48abd7d2010-05-26 13:48:04 +0000465 qemu_cmd += add_floppy(help, floppy)
lmrb0a9b762009-10-09 20:43:30 +0000466
467 tftp = params.get("tftp")
lmr62fc2bb2010-07-08 23:45:11 +0000468 if tftp:
lmrf69f6b12009-11-10 16:33:44 +0000469 tftp = kvm_utils.get_path(root_dir, tftp)
lmr48abd7d2010-05-26 13:48:04 +0000470 qemu_cmd += add_tftp(help, tftp)
lmr6f669ce2009-05-31 19:02:42 +0000471
lmr6976faa2010-07-09 21:11:06 +0000472 bootp = params.get("bootp")
473 if bootp:
474 qemu_cmd += add_bootp(help, bootp)
475
lmr41cb8fc2010-06-10 15:30:45 +0000476 kernel = params.get("kernel")
477 if kernel:
478 kernel = kvm_utils.get_path(root_dir, kernel)
479 qemu_cmd += add_kernel(help, kernel)
480
lmre0474e32010-06-29 14:10:09 +0000481 kernel_cmdline = params.get("kernel_cmdline")
482 if kernel_cmdline:
483 qemu_cmd += add_kernel_cmdline(help, kernel_cmdline)
484
lmr41cb8fc2010-06-10 15:30:45 +0000485 initrd = params.get("initrd")
486 if initrd:
487 initrd = kvm_utils.get_path(root_dir, initrd)
488 qemu_cmd += add_initrd(help, initrd)
489
lmr6976faa2010-07-09 21:11:06 +0000490 for host_port, guest_port in redirs:
lmr48abd7d2010-05-26 13:48:04 +0000491 qemu_cmd += add_tcp_redir(help, host_port, guest_port)
lmr6f669ce2009-05-31 19:02:42 +0000492
493 if params.get("display") == "vnc":
Eric Li7edb3042011-01-06 17:57:17 -0800494 qemu_cmd += add_vnc(help, vm.vnc_port)
lmr6f669ce2009-05-31 19:02:42 +0000495 elif params.get("display") == "sdl":
lmr48abd7d2010-05-26 13:48:04 +0000496 qemu_cmd += add_sdl(help)
lmr6f669ce2009-05-31 19:02:42 +0000497 elif params.get("display") == "nographic":
lmr48abd7d2010-05-26 13:48:04 +0000498 qemu_cmd += add_nographic(help)
lmr6f669ce2009-05-31 19:02:42 +0000499
lmra2533222009-07-20 12:43:46 +0000500 if params.get("uuid") == "random":
Eric Li7edb3042011-01-06 17:57:17 -0800501 qemu_cmd += add_uuid(help, vm.uuid)
lmra2533222009-07-20 12:43:46 +0000502 elif params.get("uuid"):
lmr48abd7d2010-05-26 13:48:04 +0000503 qemu_cmd += add_uuid(help, params.get("uuid"))
lmra2533222009-07-20 12:43:46 +0000504
lmr71024552010-06-29 14:12:35 +0000505 if params.get("testdev") == "yes":
Eric Li7edb3042011-01-06 17:57:17 -0800506 qemu_cmd += add_testdev(help, vm.get_testlog_filename())
lmr71024552010-06-29 14:12:35 +0000507
lmrce5c9252010-06-30 17:41:00 +0000508 if params.get("disable_hpet") == "yes":
509 qemu_cmd += add_no_hpet(help)
510
lmr31af3a12010-01-18 16:46:52 +0000511 # If the PCI assignment step went OK, add each one of the PCI assigned
512 # devices to the qemu command line.
Eric Li7edb3042011-01-06 17:57:17 -0800513 if vm.pci_assignable:
514 for pci_id in vm.pa_pci_ids:
lmr48abd7d2010-05-26 13:48:04 +0000515 qemu_cmd += add_pcidevice(help, pci_id)
516
517 extra_params = params.get("extra_params")
518 if extra_params:
519 qemu_cmd += " %s" % extra_params
lmr31af3a12010-01-18 16:46:52 +0000520
lmr6f669ce2009-05-31 19:02:42 +0000521 return qemu_cmd
522
523
Eric Lie0493a42010-11-15 13:05:43 -0800524 def create(self, name=None, params=None, root_dir=None, timeout=5.0,
Eric Li7edb3042011-01-06 17:57:17 -0800525 migration_mode=None, mac_source=None):
lmr6f669ce2009-05-31 19:02:42 +0000526 """
527 Start the VM by running a qemu command.
Eric Lie0493a42010-11-15 13:05:43 -0800528 All parameters are optional. If name, params or root_dir are not
529 supplied, the respective values stored as class attributes are used.
lmr6f669ce2009-05-31 19:02:42 +0000530
531 @param name: The name of the object
532 @param params: A dict containing VM params
lmr90b9fd52009-08-17 20:48:18 +0000533 @param root_dir: Base directory for relative filenames
Eric Lie0493a42010-11-15 13:05:43 -0800534 @param migration_mode: If supplied, start VM for incoming migration
535 using this protocol (either 'tcp', 'unix' or 'exec')
536 @param migration_exec_cmd: Command to embed in '-incoming "exec: ..."'
537 (e.g. 'gzip -c -d filename') if migration_mode is 'exec'
538 @param mac_source: A VM object from which to copy MAC addresses. If not
539 specified, new addresses will be generated.
lmr6f669ce2009-05-31 19:02:42 +0000540 """
lmr135b5e62009-06-10 19:22:31 +0000541 self.destroy()
542
lmre45a1f22009-11-10 16:35:08 +0000543 if name is not None:
lmr6f669ce2009-05-31 19:02:42 +0000544 self.name = name
lmre45a1f22009-11-10 16:35:08 +0000545 if params is not None:
lmr6f669ce2009-05-31 19:02:42 +0000546 self.params = params
lmre45a1f22009-11-10 16:35:08 +0000547 if root_dir is not None:
lmr90b9fd52009-08-17 20:48:18 +0000548 self.root_dir = root_dir
lmr6f669ce2009-05-31 19:02:42 +0000549 name = self.name
550 params = self.params
lmr90b9fd52009-08-17 20:48:18 +0000551 root_dir = self.root_dir
lmr6f669ce2009-05-31 19:02:42 +0000552
Eric Li7edb3042011-01-06 17:57:17 -0800553 # Verify the md5sum of the ISO images
554 for cdrom in params.objects("cdroms"):
555 cdrom_params = params.object_params(cdrom)
556 iso = cdrom_params.get("cdrom")
557 if iso:
558 iso = kvm_utils.get_path(root_dir, iso)
559 if not os.path.exists(iso):
560 logging.error("ISO file not found: %s" % iso)
lmr6f669ce2009-05-31 19:02:42 +0000561 return False
Eric Li7edb3042011-01-06 17:57:17 -0800562 compare = False
563 if cdrom_params.get("md5sum_1m"):
564 logging.debug("Comparing expected MD5 sum with MD5 sum of "
565 "first MB of ISO file...")
566 actual_hash = utils.hash_file(iso, 1048576, method="md5")
567 expected_hash = cdrom_params.get("md5sum_1m")
568 compare = True
569 elif cdrom_params.get("md5sum"):
570 logging.debug("Comparing expected MD5 sum with MD5 sum of "
571 "ISO file...")
572 actual_hash = utils.hash_file(iso, method="md5")
573 expected_hash = cdrom_params.get("md5sum")
574 compare = True
575 elif cdrom_params.get("sha1sum"):
576 logging.debug("Comparing expected SHA1 sum with SHA1 sum "
577 "of ISO file...")
578 actual_hash = utils.hash_file(iso, method="sha1")
579 expected_hash = cdrom_params.get("sha1sum")
580 compare = True
581 if compare:
582 if actual_hash == expected_hash:
583 logging.debug("Hashes match")
584 else:
585 logging.error("Actual hash differs from expected one")
586 return False
lmr6f669ce2009-05-31 19:02:42 +0000587
lmrdc2ac6a2009-06-10 19:15:49 +0000588 # Make sure the following code is not executed by more than one thread
589 # at the same time
590 lockfile = open("/tmp/kvm-autotest-vm-create.lock", "w+")
591 fcntl.lockf(lockfile, fcntl.LOCK_EX)
lmr6f669ce2009-05-31 19:02:42 +0000592
lmrdc2ac6a2009-06-10 19:15:49 +0000593 try:
594 # Handle port redirections
Eric Li7edb3042011-01-06 17:57:17 -0800595 redir_names = params.objects("redirs")
lmrdc2ac6a2009-06-10 19:15:49 +0000596 host_ports = kvm_utils.find_free_ports(5000, 6000, len(redir_names))
597 self.redirs = {}
598 for i in range(len(redir_names)):
Eric Li7edb3042011-01-06 17:57:17 -0800599 redir_params = params.object_params(redir_names[i])
lmrdc2ac6a2009-06-10 19:15:49 +0000600 guest_port = int(redir_params.get("guest_port"))
601 self.redirs[guest_port] = host_ports[i]
lmr6f669ce2009-05-31 19:02:42 +0000602
Eric Li7edb3042011-01-06 17:57:17 -0800603 # Generate netdev IDs for all NICs
604 self.netdev_id = []
605 for nic in params.objects("nics"):
lmr48349072010-06-29 14:14:55 +0000606 self.netdev_id.append(kvm_utils.generate_random_id())
607
lmrdc2ac6a2009-06-10 19:15:49 +0000608 # Find available VNC port, if needed
609 if params.get("display") == "vnc":
lmrc0da8902010-05-17 20:31:36 +0000610 self.vnc_port = kvm_utils.find_free_port(5900, 6100)
lmr6f669ce2009-05-31 19:02:42 +0000611
lmra2533222009-07-20 12:43:46 +0000612 # Find random UUID if specified 'uuid = random' in config file
613 if params.get("uuid") == "random":
614 f = open("/proc/sys/kernel/random/uuid")
615 self.uuid = f.read().strip()
616 f.close()
617
Eric Lie0493a42010-11-15 13:05:43 -0800618 # Generate or copy MAC addresses for all NICs
Eric Li7edb3042011-01-06 17:57:17 -0800619 num_nics = len(params.objects("nics"))
Eric Lie0493a42010-11-15 13:05:43 -0800620 for vlan in range(num_nics):
Eric Li7edb3042011-01-06 17:57:17 -0800621 nic_name = params.objects("nics")[vlan]
622 nic_params = params.object_params(nic_name)
623 if nic_params.get("nic_mac", None):
624 mac = nic_params.get("nic_mac")
Eric Lie0493a42010-11-15 13:05:43 -0800625 kvm_utils.set_mac_address(self.instance, vlan, mac)
626 else:
Eric Li7edb3042011-01-06 17:57:17 -0800627 mac = mac_source and mac_source.get_mac_address(vlan)
628 if mac:
629 kvm_utils.set_mac_address(self.instance, vlan, mac)
630 else:
631 kvm_utils.generate_mac_address(self.instance, vlan)
Eric Lie0493a42010-11-15 13:05:43 -0800632
lmr31ed61d2010-06-07 13:21:38 +0000633 # Assign a PCI assignable device
634 self.pci_assignable = None
635 pa_type = params.get("pci_assignable")
636 if pa_type in ["vf", "pf", "mixed"]:
lmr31af3a12010-01-18 16:46:52 +0000637 pa_devices_requested = params.get("devices_requested")
638
639 # Virtual Functions (VF) assignable devices
640 if pa_type == "vf":
lmr31ed61d2010-06-07 13:21:38 +0000641 self.pci_assignable = kvm_utils.PciAssignable(
642 type=pa_type,
643 driver=params.get("driver"),
644 driver_option=params.get("driver_option"),
645 devices_requested=pa_devices_requested)
lmr31af3a12010-01-18 16:46:52 +0000646 # Physical NIC (PF) assignable devices
647 elif pa_type == "pf":
lmr31ed61d2010-06-07 13:21:38 +0000648 self.pci_assignable = kvm_utils.PciAssignable(
649 type=pa_type,
650 names=params.get("device_names"),
651 devices_requested=pa_devices_requested)
lmr31af3a12010-01-18 16:46:52 +0000652 # Working with both VF and PF
653 elif pa_type == "mixed":
lmr31ed61d2010-06-07 13:21:38 +0000654 self.pci_assignable = kvm_utils.PciAssignable(
655 type=pa_type,
656 driver=params.get("driver"),
657 driver_option=params.get("driver_option"),
658 names=params.get("device_names"),
659 devices_requested=pa_devices_requested)
lmr31af3a12010-01-18 16:46:52 +0000660
661 self.pa_pci_ids = self.pci_assignable.request_devs()
662
663 if self.pa_pci_ids:
lmr31ed61d2010-06-07 13:21:38 +0000664 logging.debug("Successfuly assigned devices: %s",
lmr31af3a12010-01-18 16:46:52 +0000665 self.pa_pci_ids)
666 else:
667 logging.error("No PCI assignable devices were assigned "
668 "and 'pci_assignable' is defined to %s "
lmr31ed61d2010-06-07 13:21:38 +0000669 "on your config file. Aborting VM creation.",
lmr31af3a12010-01-18 16:46:52 +0000670 pa_type)
671 return False
672
lmr856d58c2010-06-08 18:29:31 +0000673 elif pa_type and pa_type != "no":
lmr31ed61d2010-06-07 13:21:38 +0000674 logging.warn("Unsupported pci_assignable type: %s", pa_type)
lmr31af3a12010-01-18 16:46:52 +0000675
lmrdc2ac6a2009-06-10 19:15:49 +0000676 # Make qemu command
677 qemu_command = self.make_qemu_command()
lmr6f669ce2009-05-31 19:02:42 +0000678
Eric Lie0493a42010-11-15 13:05:43 -0800679 # Add migration parameters if required
680 if migration_mode == "tcp":
681 self.migration_port = kvm_utils.find_free_port(5200, 6000)
682 qemu_command += " -incoming tcp:0:%d" % self.migration_port
683 elif migration_mode == "unix":
684 self.migration_file = "/tmp/migration-unix-%s" % self.instance
685 qemu_command += " -incoming unix:%s" % self.migration_file
686 elif migration_mode == "exec":
Eric Li7edb3042011-01-06 17:57:17 -0800687 self.migration_port = kvm_utils.find_free_port(5200, 6000)
688 qemu_command += (' -incoming "exec:nc -l %s"' %
689 self.migration_port)
lmr6f669ce2009-05-31 19:02:42 +0000690
lmrdc2ac6a2009-06-10 19:15:49 +0000691 logging.debug("Running qemu command:\n%s", qemu_command)
lmra4967622009-07-23 01:36:32 +0000692 self.process = kvm_subprocess.run_bg(qemu_command, None,
693 logging.debug, "(qemu) ")
lmr6f669ce2009-05-31 19:02:42 +0000694
lmr9e964a02010-06-18 03:46:21 +0000695 # Make sure the process was started successfully
lmra4967622009-07-23 01:36:32 +0000696 if not self.process.is_alive():
697 logging.error("VM could not be created; "
698 "qemu command failed:\n%s" % qemu_command)
699 logging.error("Status: %s" % self.process.get_status())
700 logging.error("Output:" + kvm_utils.format_str_for_message(
701 self.process.get_output()))
lmrdc2ac6a2009-06-10 19:15:49 +0000702 self.destroy()
703 return False
lmr6f669ce2009-05-31 19:02:42 +0000704
lmr9e964a02010-06-18 03:46:21 +0000705 # Establish monitor connections
706 self.monitors = []
Eric Li7edb3042011-01-06 17:57:17 -0800707 for monitor_name in params.objects("monitors"):
708 monitor_params = params.object_params(monitor_name)
lmr9e964a02010-06-18 03:46:21 +0000709 # Wait for monitor connection to succeed
710 end_time = time.time() + timeout
711 while time.time() < end_time:
712 try:
713 if monitor_params.get("monitor_type") == "qmp":
lmr449d2252010-06-18 03:48:23 +0000714 # Add a QMP monitor
715 monitor = kvm_monitor.QMPMonitor(
716 monitor_name,
717 self.get_monitor_filename(monitor_name))
lmr9e964a02010-06-18 03:46:21 +0000718 else:
719 # Add a "human" monitor
720 monitor = kvm_monitor.HumanMonitor(
721 monitor_name,
722 self.get_monitor_filename(monitor_name))
723 except kvm_monitor.MonitorError, e:
724 logging.warn(e)
725 else:
lmr449d2252010-06-18 03:48:23 +0000726 if monitor.is_responsive():
lmr9e964a02010-06-18 03:46:21 +0000727 break
728 time.sleep(1)
729 else:
730 logging.error("Could not connect to monitor '%s'" %
731 monitor_name)
732 self.destroy()
733 return False
734 # Add this monitor to the list
735 self.monitors += [monitor]
lmra4967622009-07-23 01:36:32 +0000736
lmrfe6515e2009-07-29 13:01:17 +0000737 # Get the output so far, to see if we have any problems with
lmrb306bf82010-07-08 23:47:00 +0000738 # KVM modules or with hugepage setup.
lmrfe6515e2009-07-29 13:01:17 +0000739 output = self.process.get_output()
740
lmrb306bf82010-07-08 23:47:00 +0000741 if re.search("Could not initialize KVM", output, re.IGNORECASE):
742 logging.error("Could not initialize KVM; "
743 "qemu command:\n%s" % qemu_command)
744 logging.error("Output:" + kvm_utils.format_str_for_message(
745 self.process.get_output()))
746 self.destroy()
747 return False
748
lmrfe6515e2009-07-29 13:01:17 +0000749 if "alloc_mem_area" in output:
750 logging.error("Could not allocate hugepage memory; "
751 "qemu command:\n%s" % qemu_command)
752 logging.error("Output:" + kvm_utils.format_str_for_message(
753 self.process.get_output()))
lmr090cd7a2010-04-01 02:18:52 +0000754 self.destroy()
lmrfe6515e2009-07-29 13:01:17 +0000755 return False
756
lmr71fa4de2010-06-14 15:54:55 +0000757 logging.debug("VM appears to be alive with PID %s", self.get_pid())
lmraa380a22010-06-22 02:05:29 +0000758
759 # Establish a session with the serial console -- requires a version
760 # of netcat that supports -U
Eric Li7edb3042011-01-06 17:57:17 -0800761 self.serial_console = kvm_subprocess.ShellSession(
lmraa380a22010-06-22 02:05:29 +0000762 "nc -U %s" % self.get_serial_console_filename(),
763 auto_close=False,
764 output_func=kvm_utils.log_line,
765 output_params=("serial-%s.log" % name,))
766
lmrdc2ac6a2009-06-10 19:15:49 +0000767 return True
768
769 finally:
770 fcntl.lockf(lockfile, fcntl.LOCK_UN)
771 lockfile.close()
lmr6f669ce2009-05-31 19:02:42 +0000772
773
lmr6f669ce2009-05-31 19:02:42 +0000774 def destroy(self, gracefully=True):
775 """
776 Destroy the VM.
777
lmr912c74b2009-08-17 20:43:27 +0000778 If gracefully is True, first attempt to shutdown the VM with a shell
779 command. Then, attempt to destroy the VM via the monitor with a 'quit'
780 command. If that fails, send SIGKILL to the qemu process.
lmr6f669ce2009-05-31 19:02:42 +0000781
782 @param gracefully: Whether an attempt will be made to end the VM
lmr912c74b2009-08-17 20:43:27 +0000783 using a shell command before trying to end the qemu process
784 with a 'quit' or a kill signal.
lmr6f669ce2009-05-31 19:02:42 +0000785 """
lmrf320b042009-09-15 05:48:06 +0000786 try:
787 # Is it already dead?
788 if self.is_dead():
789 logging.debug("VM is already down")
790 return
lmr6f669ce2009-05-31 19:02:42 +0000791
lmr71fa4de2010-06-14 15:54:55 +0000792 logging.debug("Destroying VM with PID %s...", self.get_pid())
lmr6f669ce2009-05-31 19:02:42 +0000793
lmrf320b042009-09-15 05:48:06 +0000794 if gracefully and self.params.get("shutdown_command"):
795 # Try to destroy with shell command
796 logging.debug("Trying to shutdown VM with shell command...")
797 session = self.remote_login()
798 if session:
799 try:
800 # Send the shutdown command
801 session.sendline(self.params.get("shutdown_command"))
802 logging.debug("Shutdown command sent; waiting for VM "
803 "to go down...")
804 if kvm_utils.wait_for(self.is_dead, 60, 1, 1):
Eric Lie0493a42010-11-15 13:05:43 -0800805 logging.debug("VM is down, freeing mac address.")
lmrf320b042009-09-15 05:48:06 +0000806 return
807 finally:
808 session.close()
lmr6f669ce2009-05-31 19:02:42 +0000809
lmr9e964a02010-06-18 03:46:21 +0000810 if self.monitor:
811 # Try to destroy with a monitor command
812 logging.debug("Trying to kill VM with monitor command...")
813 try:
814 self.monitor.quit()
815 except kvm_monitor.MonitorError, e:
816 logging.warn(e)
817 else:
818 # Wait for the VM to be really dead
819 if kvm_utils.wait_for(self.is_dead, 5, 0.5, 0.5):
820 logging.debug("VM is down")
821 return
lmrf320b042009-09-15 05:48:06 +0000822
823 # If the VM isn't dead yet...
824 logging.debug("Cannot quit normally; sending a kill to close the "
825 "deal...")
826 kvm_utils.kill_process_tree(self.process.get_pid(), 9)
lmr6f669ce2009-05-31 19:02:42 +0000827 # Wait for the VM to be really dead
828 if kvm_utils.wait_for(self.is_dead, 5, 0.5, 0.5):
829 logging.debug("VM is down")
lmr6f669ce2009-05-31 19:02:42 +0000830 return
831
lmrf320b042009-09-15 05:48:06 +0000832 logging.error("Process %s is a zombie!" % self.process.get_pid())
lmr6f669ce2009-05-31 19:02:42 +0000833
lmrf320b042009-09-15 05:48:06 +0000834 finally:
lmr9e964a02010-06-18 03:46:21 +0000835 self.monitors = []
lmr4513c432010-02-03 11:59:03 +0000836 if self.pci_assignable:
837 self.pci_assignable.release_devs()
lmrf320b042009-09-15 05:48:06 +0000838 if self.process:
839 self.process.close()
lmraa380a22010-06-22 02:05:29 +0000840 if self.serial_console:
841 self.serial_console.close()
lmr84546f22010-06-29 23:03:34 +0000842 for f in ([self.get_testlog_filename(),
843 self.get_serial_console_filename()] +
lmr9e964a02010-06-18 03:46:21 +0000844 self.get_monitor_filenames()):
845 try:
846 os.unlink(f)
847 except OSError:
848 pass
Eric Lie0493a42010-11-15 13:05:43 -0800849 if hasattr(self, "migration_file"):
850 try:
851 os.unlink(self.migration_file)
852 except OSError:
853 pass
Eric Li7edb3042011-01-06 17:57:17 -0800854 num_nics = len(self.params.objects("nics"))
Eric Lie0493a42010-11-15 13:05:43 -0800855 for vlan in range(num_nics):
856 self.free_mac_address(vlan)
lmr9e964a02010-06-18 03:46:21 +0000857
858
859 @property
860 def monitor(self):
861 """
862 Return the main monitor object, selected by the parameter main_monitor.
863 If main_monitor isn't defined, return the first monitor.
864 If no monitors exist, or if main_monitor refers to a nonexistent
865 monitor, return None.
866 """
867 for m in self.monitors:
868 if m.name == self.params.get("main_monitor"):
869 return m
870 if self.monitors and not self.params.get("main_monitor"):
871 return self.monitors[0]
lmr6f669ce2009-05-31 19:02:42 +0000872
873
874 def is_alive(self):
875 """
lmr9e964a02010-06-18 03:46:21 +0000876 Return True if the VM is alive and its monitor is responsive.
lmr6f669ce2009-05-31 19:02:42 +0000877 """
lmra4967622009-07-23 01:36:32 +0000878 # Check if the process is running
879 if self.is_dead():
lmr6f669ce2009-05-31 19:02:42 +0000880 return False
881 # Try sending a monitor command
lmr9e964a02010-06-18 03:46:21 +0000882 return bool(self.monitor) and self.monitor.is_responsive()
lmr6f669ce2009-05-31 19:02:42 +0000883
884
885 def is_dead(self):
886 """
lmra4967622009-07-23 01:36:32 +0000887 Return True if the qemu process is dead.
lmr6f669ce2009-05-31 19:02:42 +0000888 """
lmra4967622009-07-23 01:36:32 +0000889 return not self.process or not self.process.is_alive()
lmr6f669ce2009-05-31 19:02:42 +0000890
891
892 def get_params(self):
893 """
894 Return the VM's params dict. Most modified params take effect only
895 upon VM.create().
896 """
897 return self.params
898
899
lmr9e964a02010-06-18 03:46:21 +0000900 def get_monitor_filename(self, monitor_name):
901 """
902 Return the filename corresponding to a given monitor name.
903 """
904 return "/tmp/monitor-%s-%s" % (monitor_name, self.instance)
905
906
907 def get_monitor_filenames(self):
908 """
909 Return a list of all monitor filenames (as specified in the VM's
910 params).
911 """
912 return [self.get_monitor_filename(m) for m in
Eric Li7edb3042011-01-06 17:57:17 -0800913 self.params.objects("monitors")]
lmr9e964a02010-06-18 03:46:21 +0000914
915
lmr2b06f332010-06-22 02:03:41 +0000916 def get_serial_console_filename(self):
917 """
918 Return the serial console filename.
919 """
920 return "/tmp/serial-%s" % self.instance
921
922
lmr9e964a02010-06-18 03:46:21 +0000923 def get_testlog_filename(self):
924 """
925 Return the testlog filename.
926 """
927 return "/tmp/testlog-%s" % self.instance
928
929
lmrf4696342009-08-13 04:06:33 +0000930 def get_address(self, index=0):
lmr6f669ce2009-05-31 19:02:42 +0000931 """
lmrf4696342009-08-13 04:06:33 +0000932 Return the address of a NIC of the guest, in host space.
lmr6f669ce2009-05-31 19:02:42 +0000933
lmrf4696342009-08-13 04:06:33 +0000934 If port redirection is used, return 'localhost' (the NIC has no IP
935 address of its own). Otherwise return the NIC's IP address.
936
937 @param index: Index of the NIC whose address is requested.
lmr6f669ce2009-05-31 19:02:42 +0000938 """
Eric Li7edb3042011-01-06 17:57:17 -0800939 nics = self.params.objects("nics")
lmree90dd92009-08-13 04:13:39 +0000940 nic_name = nics[index]
Eric Li7edb3042011-01-06 17:57:17 -0800941 nic_params = self.params.object_params(nic_name)
lmrf4696342009-08-13 04:06:33 +0000942 if nic_params.get("nic_mode") == "tap":
Eric Lie0493a42010-11-15 13:05:43 -0800943 mac = self.get_mac_address(index)
lmree90dd92009-08-13 04:13:39 +0000944 if not mac:
945 logging.debug("MAC address unavailable")
946 return None
Eric Lie0493a42010-11-15 13:05:43 -0800947 mac = mac.lower()
948 # Get the IP address from the cache
949 ip = self.address_cache.get(mac)
950 if not ip:
951 logging.debug("Could not find IP address for MAC address: %s" %
952 mac)
953 return None
954 # Make sure the IP address is assigned to this guest
955 macs = [self.get_mac_address(i) for i in range(len(nics))]
956 if not kvm_utils.verify_ip_address_ownership(ip, macs):
957 logging.debug("Could not verify MAC-IP address mapping: "
958 "%s ---> %s" % (mac, ip))
959 return None
lmrf4696342009-08-13 04:06:33 +0000960 return ip
961 else:
962 return "localhost"
lmr6f669ce2009-05-31 19:02:42 +0000963
964
lmree90dd92009-08-13 04:13:39 +0000965 def get_port(self, port, nic_index=0):
lmr6f669ce2009-05-31 19:02:42 +0000966 """
967 Return the port in host space corresponding to port in guest space.
968
969 @param port: Port number in host space.
lmree90dd92009-08-13 04:13:39 +0000970 @param nic_index: Index of the NIC.
lmr6f669ce2009-05-31 19:02:42 +0000971 @return: If port redirection is used, return the host port redirected
972 to guest port port. Otherwise return port.
973 """
Eric Li7edb3042011-01-06 17:57:17 -0800974 nic_name = self.params.objects("nics")[nic_index]
975 nic_params = self.params.object_params(nic_name)
lmrf4696342009-08-13 04:06:33 +0000976 if nic_params.get("nic_mode") == "tap":
977 return port
lmr6f669ce2009-05-31 19:02:42 +0000978 else:
lmrf4696342009-08-13 04:06:33 +0000979 if not self.redirs.has_key(port):
980 logging.warn("Warning: guest port %s requested but not "
981 "redirected" % port)
982 return self.redirs.get(port)
lmr6f669ce2009-05-31 19:02:42 +0000983
984
Eric Lie0493a42010-11-15 13:05:43 -0800985 def get_ifname(self, nic_index=0):
986 """
987 Return the ifname of a tap device associated with a NIC.
988
989 @param nic_index: Index of the NIC
990 """
Eric Li7edb3042011-01-06 17:57:17 -0800991 nics = self.params.objects("nics")
Eric Lie0493a42010-11-15 13:05:43 -0800992 nic_name = nics[nic_index]
Eric Li7edb3042011-01-06 17:57:17 -0800993 nic_params = self.params.object_params(nic_name)
Eric Lie0493a42010-11-15 13:05:43 -0800994 if nic_params.get("nic_ifname"):
995 return nic_params.get("nic_ifname")
996 else:
997 return "t%d-%s" % (nic_index, self.instance[-11:])
998
999
1000 def get_mac_address(self, nic_index=0):
1001 """
1002 Return the MAC address of a NIC.
1003
1004 @param nic_index: Index of the NIC
1005 """
1006 return kvm_utils.get_mac_address(self.instance, nic_index)
1007
1008
1009 def free_mac_address(self, nic_index=0):
1010 """
1011 Free a NIC's MAC address.
1012
1013 @param nic_index: Index of the NIC
1014 """
1015 kvm_utils.free_mac_address(self.instance, nic_index)
1016
1017
lmra4967622009-07-23 01:36:32 +00001018 def get_pid(self):
1019 """
lmr71fa4de2010-06-14 15:54:55 +00001020 Return the VM's PID. If the VM is dead return None.
1021
1022 @note: This works under the assumption that self.process.get_pid()
1023 returns the PID of the parent shell process.
1024 """
1025 try:
1026 children = commands.getoutput("ps --ppid=%d -o pid=" %
1027 self.process.get_pid()).split()
1028 return int(children[0])
1029 except (TypeError, IndexError, ValueError):
1030 return None
1031
1032
1033 def get_shell_pid(self):
1034 """
1035 Return the PID of the parent shell process.
1036
1037 @note: This works under the assumption that self.process.get_pid()
1038 returns the PID of the parent shell process.
lmra4967622009-07-23 01:36:32 +00001039 """
1040 return self.process.get_pid()
1041
1042
lmr0bee2342010-02-24 00:01:37 +00001043 def get_shared_meminfo(self):
1044 """
1045 Returns the VM's shared memory information.
1046
1047 @return: Shared memory used by VM (MB)
1048 """
1049 if self.is_dead():
1050 logging.error("Could not get shared memory info from dead VM.")
1051 return None
1052
lmr983ecdf2010-06-14 15:57:12 +00001053 filename = "/proc/%d/statm" % self.get_pid()
1054 shm = int(open(filename).read().split()[2])
lmr0bee2342010-02-24 00:01:37 +00001055 # statm stores informations in pages, translate it to MB
lmr983ecdf2010-06-14 15:57:12 +00001056 return shm * 4.0 / 1024
lmr0bee2342010-02-24 00:01:37 +00001057
1058
lmr912c74b2009-08-17 20:43:27 +00001059 def remote_login(self, nic_index=0, timeout=10):
lmr6f669ce2009-05-31 19:02:42 +00001060 """
lmr912c74b2009-08-17 20:43:27 +00001061 Log into the guest via SSH/Telnet/Netcat.
lmr6f669ce2009-05-31 19:02:42 +00001062 If timeout expires while waiting for output from the guest (e.g. a
1063 password prompt or a shell prompt) -- fail.
1064
lmree90dd92009-08-13 04:13:39 +00001065 @param nic_index: The index of the NIC to connect to.
lmr6f669ce2009-05-31 19:02:42 +00001066 @param timeout: Time (seconds) before giving up logging into the
1067 guest.
Eric Li7edb3042011-01-06 17:57:17 -08001068 @return: ShellSession object on success and None on failure.
lmr6f669ce2009-05-31 19:02:42 +00001069 """
1070 username = self.params.get("username", "")
1071 password = self.params.get("password", "")
lmr912c74b2009-08-17 20:43:27 +00001072 prompt = self.params.get("shell_prompt", "[\#\$]")
lmr59f9e2d2009-10-05 18:47:16 +00001073 linesep = eval("'%s'" % self.params.get("shell_linesep", r"\n"))
lmr912c74b2009-08-17 20:43:27 +00001074 client = self.params.get("shell_client")
lmree90dd92009-08-13 04:13:39 +00001075 address = self.get_address(nic_index)
lmr912c74b2009-08-17 20:43:27 +00001076 port = self.get_port(int(self.params.get("shell_port")))
lmre56903f2010-06-22 02:09:35 +00001077 log_filename = ("session-%s-%s.log" %
1078 (self.name, kvm_utils.generate_random_string(4)))
lmr912c74b2009-08-17 20:43:27 +00001079
lmree90dd92009-08-13 04:13:39 +00001080 if not address or not port:
1081 logging.debug("IP address or port unavailable")
lmr6f669ce2009-05-31 19:02:42 +00001082 return None
1083
lmr158604f2010-06-22 01:57:34 +00001084 session = kvm_utils.remote_login(client, address, port, username,
lmre56903f2010-06-22 02:09:35 +00001085 password, prompt, linesep,
1086 log_filename, timeout)
lmr912c74b2009-08-17 20:43:27 +00001087
lmr6f669ce2009-05-31 19:02:42 +00001088 if session:
lmr912c74b2009-08-17 20:43:27 +00001089 session.set_status_test_command(self.params.get("status_test_"
lmr6f669ce2009-05-31 19:02:42 +00001090 "command", ""))
1091 return session
1092
1093
lmrc196d492010-05-07 14:14:26 +00001094 def copy_files_to(self, local_path, remote_path, nic_index=0, timeout=600):
lmr6f669ce2009-05-31 19:02:42 +00001095 """
Eric Li7edb3042011-01-06 17:57:17 -08001096 Transfer files to the remote host(guest).
lmr6f669ce2009-05-31 19:02:42 +00001097
1098 @param local_path: Host path
1099 @param remote_path: Guest path
lmr912c74b2009-08-17 20:43:27 +00001100 @param nic_index: The index of the NIC to connect to.
lmr6f669ce2009-05-31 19:02:42 +00001101 @param timeout: Time (seconds) before giving up on doing the remote
1102 copy.
1103 """
1104 username = self.params.get("username", "")
1105 password = self.params.get("password", "")
lmr912c74b2009-08-17 20:43:27 +00001106 client = self.params.get("file_transfer_client")
lmree90dd92009-08-13 04:13:39 +00001107 address = self.get_address(nic_index)
lmr912c74b2009-08-17 20:43:27 +00001108 port = self.get_port(int(self.params.get("file_transfer_port")))
1109
Eric Li7edb3042011-01-06 17:57:17 -08001110 log_filename = ("transfer-%s-to-%s-%s.log" %
1111 (self.name, address,
1112 kvm_utils.generate_random_string(4)))
1113 return kvm_utils.copy_files_to(address, client, username, password,
1114 port, local_path, remote_path,
1115 log_filename, timeout)
lmr6f669ce2009-05-31 19:02:42 +00001116
1117
lmrc196d492010-05-07 14:14:26 +00001118 def copy_files_from(self, remote_path, local_path, nic_index=0, timeout=600):
lmr6f669ce2009-05-31 19:02:42 +00001119 """
lmr912c74b2009-08-17 20:43:27 +00001120 Transfer files from the guest.
lmr6f669ce2009-05-31 19:02:42 +00001121
1122 @param local_path: Guest path
1123 @param remote_path: Host path
lmr912c74b2009-08-17 20:43:27 +00001124 @param nic_index: The index of the NIC to connect to.
lmr6f669ce2009-05-31 19:02:42 +00001125 @param timeout: Time (seconds) before giving up on doing the remote
1126 copy.
1127 """
1128 username = self.params.get("username", "")
1129 password = self.params.get("password", "")
lmr912c74b2009-08-17 20:43:27 +00001130 client = self.params.get("file_transfer_client")
lmree90dd92009-08-13 04:13:39 +00001131 address = self.get_address(nic_index)
lmr912c74b2009-08-17 20:43:27 +00001132 port = self.get_port(int(self.params.get("file_transfer_port")))
1133
Eric Li7edb3042011-01-06 17:57:17 -08001134 log_filename = ("transfer-%s-from-%s-%s.log" %
1135 (self.name, address,
1136 kvm_utils.generate_random_string(4)))
1137 return kvm_utils.copy_files_from(address, client, username, password,
1138 port, local_path, remote_path, log_filename, timeout)
lmr6f669ce2009-05-31 19:02:42 +00001139
1140
lmraa380a22010-06-22 02:05:29 +00001141 def serial_login(self, timeout=10):
1142 """
1143 Log into the guest via the serial console.
1144 If timeout expires while waiting for output from the guest (e.g. a
1145 password prompt or a shell prompt) -- fail.
1146
1147 @param timeout: Time (seconds) before giving up logging into the guest.
Eric Li7edb3042011-01-06 17:57:17 -08001148 @return: ShellSession object on success and None on failure.
lmraa380a22010-06-22 02:05:29 +00001149 """
1150 username = self.params.get("username", "")
1151 password = self.params.get("password", "")
1152 prompt = self.params.get("shell_prompt", "[\#\$]")
1153 linesep = eval("'%s'" % self.params.get("shell_linesep", r"\n"))
1154 status_test_command = self.params.get("status_test_command", "")
1155
1156 if self.serial_console:
1157 self.serial_console.set_linesep(linesep)
1158 self.serial_console.set_status_test_command(status_test_command)
1159 else:
1160 return None
1161
1162 # Make sure we get a login prompt
1163 self.serial_console.sendline()
1164
1165 if kvm_utils._remote_login(self.serial_console, username, password,
1166 prompt, timeout):
1167 return self.serial_console
1168
1169
lmr6f669ce2009-05-31 19:02:42 +00001170 def send_key(self, keystr):
1171 """
1172 Send a key event to the VM.
1173
1174 @param: keystr: A key event string (e.g. "ctrl-alt-delete")
1175 """
1176 # For compatibility with versions of QEMU that do not recognize all
1177 # key names: replace keyname with the hex value from the dict, which
1178 # QEMU will definitely accept
lmr9e964a02010-06-18 03:46:21 +00001179 dict = {"comma": "0x33",
1180 "dot": "0x34",
1181 "slash": "0x35"}
1182 for key, value in dict.items():
1183 keystr = keystr.replace(key, value)
1184 self.monitor.sendkey(keystr)
lmr6f669ce2009-05-31 19:02:42 +00001185 time.sleep(0.2)
1186
1187
1188 def send_string(self, str):
1189 """
1190 Send a string to the VM.
1191
1192 @param str: String, that must consist of alphanumeric characters only.
1193 Capital letters are allowed.
1194 """
1195 for char in str:
1196 if char.isupper():
1197 self.send_key("shift-%s" % char.lower())
1198 else:
1199 self.send_key(char)
lmra2533222009-07-20 12:43:46 +00001200
mbligh1ef218d2009-08-03 16:57:56 +00001201
lmra2533222009-07-20 12:43:46 +00001202 def get_uuid(self):
1203 """
1204 Catch UUID of the VM.
1205
1206 @return: None,if not specified in config file
1207 """
1208 if self.params.get("uuid") == "random":
1209 return self.uuid
1210 else:
1211 return self.params.get("uuid", None)
lmrdd2ff922009-12-01 23:39:12 +00001212
1213
1214 def get_cpu_count(self):
1215 """
1216 Get the cpu count of the VM.
1217 """
lmr13426552010-01-17 15:38:41 +00001218 session = self.remote_login()
1219 if not session:
1220 return None
lmrdd2ff922009-12-01 23:39:12 +00001221 try:
Eric Li7edb3042011-01-06 17:57:17 -08001222 return int(session.cmd(self.params.get("cpu_chk_cmd")))
lmrdd2ff922009-12-01 23:39:12 +00001223 finally:
1224 session.close()
1225
1226
lmr28426c82010-04-16 06:02:58 +00001227 def get_memory_size(self, cmd=None):
lmrdd2ff922009-12-01 23:39:12 +00001228 """
lmr28426c82010-04-16 06:02:58 +00001229 Get bootup memory size of the VM.
1230
1231 @param check_cmd: Command used to check memory. If not provided,
1232 self.params.get("mem_chk_cmd") will be used.
lmrdd2ff922009-12-01 23:39:12 +00001233 """
lmr13426552010-01-17 15:38:41 +00001234 session = self.remote_login()
1235 if not session:
lmrdd2ff922009-12-01 23:39:12 +00001236 return None
lmr13426552010-01-17 15:38:41 +00001237 try:
lmr28426c82010-04-16 06:02:58 +00001238 if not cmd:
1239 cmd = self.params.get("mem_chk_cmd")
Eric Li7edb3042011-01-06 17:57:17 -08001240 mem_str = session.cmd(cmd)
lmr6d69f4d2010-02-12 11:35:55 +00001241 mem = re.findall("([0-9]+)", mem_str)
lmr13426552010-01-17 15:38:41 +00001242 mem_size = 0
1243 for m in mem:
1244 mem_size += int(m)
1245 if "GB" in mem_str:
1246 mem_size *= 1024
1247 elif "MB" in mem_str:
1248 pass
1249 else:
1250 mem_size /= 1024
1251 return int(mem_size)
lmrdd2ff922009-12-01 23:39:12 +00001252 finally:
1253 session.close()
lmr28426c82010-04-16 06:02:58 +00001254
1255
1256 def get_current_memory_size(self):
1257 """
1258 Get current memory size of the VM, rather than bootup memory.
1259 """
1260 cmd = self.params.get("mem_chk_cur_cmd")
1261 return self.get_memory_size(cmd)
Eric Li7edb3042011-01-06 17:57:17 -08001262
1263
1264 def save_to_file(self, path):
1265 """
1266 Save the state of virtual machine to a file through migrate to
1267 exec
1268 """
1269 # Make sure we only get one iteration
1270 self.monitor.cmd("migrate_set_speed 1000g")
1271 self.monitor.cmd("migrate_set_downtime 100000000")
1272 self.monitor.migrate('"exec:cat>%s"' % path)