blob: a5555b9bdc2a3f42afe8046c7db22ce5c020f19a [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
lmr48abd7d2010-05-26 13:48:04 +0000295 # End of command line option wrappers
296
297 if name is None: name = self.name
298 if params is None: params = self.params
299 if root_dir is None: root_dir = self.root_dir
300
301 qemu_binary = kvm_utils.get_path(root_dir, params.get("qemu_binary",
302 "qemu"))
303 # Get the output of 'qemu -help' (log a message in case this call never
304 # returns or causes some other kind of trouble)
305 logging.debug("Getting output of 'qemu -help'")
306 help = commands.getoutput("%s -help" % qemu_binary)
lmr6f669ce2009-05-31 19:02:42 +0000307
lmreeff0eb2009-06-10 19:19:15 +0000308 # Start constructing the qemu command
309 qemu_cmd = ""
310 # Set the X11 display parameter if requested
311 if params.get("x11_display"):
312 qemu_cmd += "DISPLAY=%s " % params.get("x11_display")
313 # Add the qemu binary
lmr48abd7d2010-05-26 13:48:04 +0000314 qemu_cmd += qemu_binary
lmreeff0eb2009-06-10 19:19:15 +0000315 # Add the VM's name
lmr48abd7d2010-05-26 13:48:04 +0000316 qemu_cmd += add_name(help, name)
lmr9e964a02010-06-18 03:46:21 +0000317 # Add monitors
318 for monitor_name in kvm_utils.get_sub_dict_names(params, "monitors"):
319 monitor_params = kvm_utils.get_sub_dict(params, monitor_name)
320 monitor_filename = self.get_monitor_filename(monitor_name)
321 if monitor_params.get("monitor_type") == "qmp":
322 qemu_cmd += add_qmp_monitor(help, monitor_filename)
323 else:
324 qemu_cmd += add_human_monitor(help, monitor_filename)
lmr6f669ce2009-05-31 19:02:42 +0000325
lmr2b06f332010-06-22 02:03:41 +0000326 # Add serial console redirection
327 qemu_cmd += add_serial(help, self.get_serial_console_filename())
328
lmr6f669ce2009-05-31 19:02:42 +0000329 for image_name in kvm_utils.get_sub_dict_names(params, "images"):
330 image_params = kvm_utils.get_sub_dict(params, image_name)
lmr9d75ee32009-09-29 13:14:13 +0000331 if image_params.get("boot_drive") == "no":
332 continue
lmr48abd7d2010-05-26 13:48:04 +0000333 qemu_cmd += add_drive(help,
334 get_image_filename(image_params, root_dir),
335 image_params.get("drive_format"),
336 image_params.get("drive_cache"),
337 image_params.get("drive_werror"),
338 image_params.get("drive_serial"),
339 image_params.get("image_snapshot") == "yes",
340 image_params.get("image_boot") == "yes")
lmr6f669ce2009-05-31 19:02:42 +0000341
342 vlan = 0
343 for nic_name in kvm_utils.get_sub_dict_names(params, "nics"):
344 nic_params = kvm_utils.get_sub_dict(params, nic_name)
lmrf4696342009-08-13 04:06:33 +0000345 # Handle the '-net nic' part
lmr48abd7d2010-05-26 13:48:04 +0000346 mac = None
347 if "address_index" in nic_params:
348 mac = kvm_utils.get_mac_ip_pair_from_dict(nic_params)[0]
lmrb1cad1e2010-06-17 17:36:09 +0000349 qemu_cmd += add_nic(help, vlan, nic_params.get("nic_model"), mac,
350 self.netdev_id[vlan])
lmrf4696342009-08-13 04:06:33 +0000351 # Handle the '-net tap' or '-net user' part
lmre4eaa862010-06-01 19:15:14 +0000352 script = nic_params.get("nic_script")
353 downscript = nic_params.get("nic_downscript")
lmr48abd7d2010-05-26 13:48:04 +0000354 if script:
355 script = kvm_utils.get_path(root_dir, script)
356 if downscript:
357 downscript = kvm_utils.get_path(root_dir, downscript)
358 qemu_cmd += add_net(help, vlan, nic_params.get("nic_mode", "user"),
359 nic_params.get("nic_ifname"),
lmrb1cad1e2010-06-17 17:36:09 +0000360 script, downscript, self.netdev_id[vlan])
lmrf4696342009-08-13 04:06:33 +0000361 # Proceed to next NIC
lmr6f669ce2009-05-31 19:02:42 +0000362 vlan += 1
363
364 mem = params.get("mem")
365 if mem:
lmr48abd7d2010-05-26 13:48:04 +0000366 qemu_cmd += add_mem(help, mem)
lmr6f669ce2009-05-31 19:02:42 +0000367
lmrc43bf372009-11-10 13:19:00 +0000368 smp = params.get("smp")
369 if smp:
lmrdb3fe612010-06-14 16:19:28 +0000370 qemu_cmd += add_smp(help, smp)
lmrc43bf372009-11-10 13:19:00 +0000371
lmr6f669ce2009-05-31 19:02:42 +0000372 iso = params.get("cdrom")
373 if iso:
lmr90b9fd52009-08-17 20:48:18 +0000374 iso = kvm_utils.get_path(root_dir, iso)
lmr48abd7d2010-05-26 13:48:04 +0000375 qemu_cmd += add_cdrom(help, iso)
lmr89fd6412010-01-18 02:42:57 +0000376
377 # Even though this is not a really scalable approach,
378 # it doesn't seem like we are going to need more than
379 # 2 CDs active on the same VM.
380 iso_extra = params.get("cdrom_extra")
381 if iso_extra:
382 iso_extra = kvm_utils.get_path(root_dir, iso_extra)
lmr48abd7d2010-05-26 13:48:04 +0000383 qemu_cmd += add_cdrom(help, iso_extra, 3)
lmr6f669ce2009-05-31 19:02:42 +0000384
lmrb0a9b762009-10-09 20:43:30 +0000385 # We may want to add {floppy_otps} parameter for -fda
lmr48abd7d2010-05-26 13:48:04 +0000386 # {fat:floppy:}/path/. However vvfat is not usually recommended.
lmrb0a9b762009-10-09 20:43:30 +0000387 floppy = params.get("floppy")
388 if floppy:
lmrf69f6b12009-11-10 16:33:44 +0000389 floppy = kvm_utils.get_path(root_dir, floppy)
lmr48abd7d2010-05-26 13:48:04 +0000390 qemu_cmd += add_floppy(help, floppy)
lmrb0a9b762009-10-09 20:43:30 +0000391
392 tftp = params.get("tftp")
393 if tftp:
lmrf69f6b12009-11-10 16:33:44 +0000394 tftp = kvm_utils.get_path(root_dir, tftp)
lmr48abd7d2010-05-26 13:48:04 +0000395 qemu_cmd += add_tftp(help, tftp)
lmr6f669ce2009-05-31 19:02:42 +0000396
lmr41cb8fc2010-06-10 15:30:45 +0000397 kernel = params.get("kernel")
398 if kernel:
399 kernel = kvm_utils.get_path(root_dir, kernel)
400 qemu_cmd += add_kernel(help, kernel)
401
lmre0474e32010-06-29 14:10:09 +0000402 kernel_cmdline = params.get("kernel_cmdline")
403 if kernel_cmdline:
404 qemu_cmd += add_kernel_cmdline(help, kernel_cmdline)
405
lmr41cb8fc2010-06-10 15:30:45 +0000406 initrd = params.get("initrd")
407 if initrd:
408 initrd = kvm_utils.get_path(root_dir, initrd)
409 qemu_cmd += add_initrd(help, initrd)
410
lmr6f669ce2009-05-31 19:02:42 +0000411 for redir_name in kvm_utils.get_sub_dict_names(params, "redirs"):
412 redir_params = kvm_utils.get_sub_dict(params, redir_name)
413 guest_port = int(redir_params.get("guest_port"))
lmrf4696342009-08-13 04:06:33 +0000414 host_port = self.redirs.get(guest_port)
lmr48abd7d2010-05-26 13:48:04 +0000415 qemu_cmd += add_tcp_redir(help, host_port, guest_port)
lmr6f669ce2009-05-31 19:02:42 +0000416
417 if params.get("display") == "vnc":
lmr48abd7d2010-05-26 13:48:04 +0000418 qemu_cmd += add_vnc(help, self.vnc_port)
lmr6f669ce2009-05-31 19:02:42 +0000419 elif params.get("display") == "sdl":
lmr48abd7d2010-05-26 13:48:04 +0000420 qemu_cmd += add_sdl(help)
lmr6f669ce2009-05-31 19:02:42 +0000421 elif params.get("display") == "nographic":
lmr48abd7d2010-05-26 13:48:04 +0000422 qemu_cmd += add_nographic(help)
lmr6f669ce2009-05-31 19:02:42 +0000423
lmra2533222009-07-20 12:43:46 +0000424 if params.get("uuid") == "random":
lmr48abd7d2010-05-26 13:48:04 +0000425 qemu_cmd += add_uuid(help, self.uuid)
lmra2533222009-07-20 12:43:46 +0000426 elif params.get("uuid"):
lmr48abd7d2010-05-26 13:48:04 +0000427 qemu_cmd += add_uuid(help, params.get("uuid"))
lmra2533222009-07-20 12:43:46 +0000428
lmr71024552010-06-29 14:12:35 +0000429 if params.get("testdev") == "yes":
430 qemu_cmd += add_testdev(help, self.get_testlog_filename())
431
lmr31af3a12010-01-18 16:46:52 +0000432 # If the PCI assignment step went OK, add each one of the PCI assigned
433 # devices to the qemu command line.
434 if self.pci_assignable:
435 for pci_id in self.pa_pci_ids:
lmr48abd7d2010-05-26 13:48:04 +0000436 qemu_cmd += add_pcidevice(help, pci_id)
437
438 extra_params = params.get("extra_params")
439 if extra_params:
440 qemu_cmd += " %s" % extra_params
lmr31af3a12010-01-18 16:46:52 +0000441
lmr6f669ce2009-05-31 19:02:42 +0000442 return qemu_cmd
443
444
lmr52800ba2009-08-17 20:49:58 +0000445 def create(self, name=None, params=None, root_dir=None,
lmr1424f3e2010-06-17 13:57:09 +0000446 for_migration=False, timeout=5.0, extra_params=None):
lmr6f669ce2009-05-31 19:02:42 +0000447 """
448 Start the VM by running a qemu command.
449 All parameters are optional. The following applies to all parameters
450 but for_migration: If a parameter is not supplied, the corresponding
451 value stored in the class attributes is used, and if it is supplied,
452 it is stored for later use.
453
454 @param name: The name of the object
455 @param params: A dict containing VM params
lmr90b9fd52009-08-17 20:48:18 +0000456 @param root_dir: Base directory for relative filenames
lmr6f669ce2009-05-31 19:02:42 +0000457 @param for_migration: If True, start the VM with the -incoming
458 option
lmr1424f3e2010-06-17 13:57:09 +0000459 @param extra_params: extra params for qemu command.e.g -incoming option
460 Please use this parameter instead of for_migration.
lmr6f669ce2009-05-31 19:02:42 +0000461 """
lmr135b5e62009-06-10 19:22:31 +0000462 self.destroy()
463
lmre45a1f22009-11-10 16:35:08 +0000464 if name is not None:
lmr6f669ce2009-05-31 19:02:42 +0000465 self.name = name
lmre45a1f22009-11-10 16:35:08 +0000466 if params is not None:
lmr6f669ce2009-05-31 19:02:42 +0000467 self.params = params
lmre45a1f22009-11-10 16:35:08 +0000468 if root_dir is not None:
lmr90b9fd52009-08-17 20:48:18 +0000469 self.root_dir = root_dir
lmr6f669ce2009-05-31 19:02:42 +0000470 name = self.name
471 params = self.params
lmr90b9fd52009-08-17 20:48:18 +0000472 root_dir = self.root_dir
lmr6f669ce2009-05-31 19:02:42 +0000473
474 # Verify the md5sum of the ISO image
475 iso = params.get("cdrom")
476 if iso:
lmr90b9fd52009-08-17 20:48:18 +0000477 iso = kvm_utils.get_path(root_dir, iso)
lmr6f669ce2009-05-31 19:02:42 +0000478 if not os.path.exists(iso):
479 logging.error("ISO file not found: %s" % iso)
480 return False
481 compare = False
482 if params.get("md5sum_1m"):
lmrf4696342009-08-13 04:06:33 +0000483 logging.debug("Comparing expected MD5 sum with MD5 sum of "
484 "first MB of ISO file...")
lmrd60882f2010-02-04 03:26:36 +0000485 actual_hash = utils.hash_file(iso, 1048576, method="md5")
lmr03ba22e2009-10-23 12:07:44 +0000486 expected_hash = params.get("md5sum_1m")
lmr6f669ce2009-05-31 19:02:42 +0000487 compare = True
488 elif params.get("md5sum"):
lmrf4696342009-08-13 04:06:33 +0000489 logging.debug("Comparing expected MD5 sum with MD5 sum of ISO "
490 "file...")
lmrd60882f2010-02-04 03:26:36 +0000491 actual_hash = utils.hash_file(iso, method="md5")
lmr03ba22e2009-10-23 12:07:44 +0000492 expected_hash = params.get("md5sum")
493 compare = True
494 elif params.get("sha1sum"):
495 logging.debug("Comparing expected SHA1 sum with SHA1 sum of "
496 "ISO file...")
lmrd60882f2010-02-04 03:26:36 +0000497 actual_hash = utils.hash_file(iso, method="sha1")
lmrea1266e2009-11-10 16:41:08 +0000498 expected_hash = params.get("sha1sum")
lmr6f669ce2009-05-31 19:02:42 +0000499 compare = True
500 if compare:
lmr03ba22e2009-10-23 12:07:44 +0000501 if actual_hash == expected_hash:
502 logging.debug("Hashes match")
lmr6f669ce2009-05-31 19:02:42 +0000503 else:
lmr03ba22e2009-10-23 12:07:44 +0000504 logging.error("Actual hash differs from expected one")
lmr6f669ce2009-05-31 19:02:42 +0000505 return False
506
lmrdc2ac6a2009-06-10 19:15:49 +0000507 # Make sure the following code is not executed by more than one thread
508 # at the same time
509 lockfile = open("/tmp/kvm-autotest-vm-create.lock", "w+")
510 fcntl.lockf(lockfile, fcntl.LOCK_EX)
lmr6f669ce2009-05-31 19:02:42 +0000511
lmrdc2ac6a2009-06-10 19:15:49 +0000512 try:
513 # Handle port redirections
514 redir_names = kvm_utils.get_sub_dict_names(params, "redirs")
515 host_ports = kvm_utils.find_free_ports(5000, 6000, len(redir_names))
516 self.redirs = {}
517 for i in range(len(redir_names)):
518 redir_params = kvm_utils.get_sub_dict(params, redir_names[i])
519 guest_port = int(redir_params.get("guest_port"))
520 self.redirs[guest_port] = host_ports[i]
lmr6f669ce2009-05-31 19:02:42 +0000521
lmr48349072010-06-29 14:14:55 +0000522 for nic in kvm_utils.get_sub_dict_names(params, "nics"):
523 self.netdev_id.append(kvm_utils.generate_random_id())
524
lmrdc2ac6a2009-06-10 19:15:49 +0000525 # Find available VNC port, if needed
526 if params.get("display") == "vnc":
lmrc0da8902010-05-17 20:31:36 +0000527 self.vnc_port = kvm_utils.find_free_port(5900, 6100)
lmr6f669ce2009-05-31 19:02:42 +0000528
lmra2533222009-07-20 12:43:46 +0000529 # Find random UUID if specified 'uuid = random' in config file
530 if params.get("uuid") == "random":
531 f = open("/proc/sys/kernel/random/uuid")
532 self.uuid = f.read().strip()
533 f.close()
534
lmr31ed61d2010-06-07 13:21:38 +0000535 # Assign a PCI assignable device
536 self.pci_assignable = None
537 pa_type = params.get("pci_assignable")
538 if pa_type in ["vf", "pf", "mixed"]:
lmr31af3a12010-01-18 16:46:52 +0000539 pa_devices_requested = params.get("devices_requested")
540
541 # Virtual Functions (VF) assignable devices
542 if pa_type == "vf":
lmr31ed61d2010-06-07 13:21:38 +0000543 self.pci_assignable = kvm_utils.PciAssignable(
544 type=pa_type,
545 driver=params.get("driver"),
546 driver_option=params.get("driver_option"),
547 devices_requested=pa_devices_requested)
lmr31af3a12010-01-18 16:46:52 +0000548 # Physical NIC (PF) assignable devices
549 elif pa_type == "pf":
lmr31ed61d2010-06-07 13:21:38 +0000550 self.pci_assignable = kvm_utils.PciAssignable(
551 type=pa_type,
552 names=params.get("device_names"),
553 devices_requested=pa_devices_requested)
lmr31af3a12010-01-18 16:46:52 +0000554 # Working with both VF and PF
555 elif pa_type == "mixed":
lmr31ed61d2010-06-07 13:21:38 +0000556 self.pci_assignable = kvm_utils.PciAssignable(
557 type=pa_type,
558 driver=params.get("driver"),
559 driver_option=params.get("driver_option"),
560 names=params.get("device_names"),
561 devices_requested=pa_devices_requested)
lmr31af3a12010-01-18 16:46:52 +0000562
563 self.pa_pci_ids = self.pci_assignable.request_devs()
564
565 if self.pa_pci_ids:
lmr31ed61d2010-06-07 13:21:38 +0000566 logging.debug("Successfuly assigned devices: %s",
lmr31af3a12010-01-18 16:46:52 +0000567 self.pa_pci_ids)
568 else:
569 logging.error("No PCI assignable devices were assigned "
570 "and 'pci_assignable' is defined to %s "
lmr31ed61d2010-06-07 13:21:38 +0000571 "on your config file. Aborting VM creation.",
lmr31af3a12010-01-18 16:46:52 +0000572 pa_type)
573 return False
574
lmr856d58c2010-06-08 18:29:31 +0000575 elif pa_type and pa_type != "no":
lmr31ed61d2010-06-07 13:21:38 +0000576 logging.warn("Unsupported pci_assignable type: %s", pa_type)
lmr31af3a12010-01-18 16:46:52 +0000577
lmrdc2ac6a2009-06-10 19:15:49 +0000578 # Make qemu command
579 qemu_command = self.make_qemu_command()
lmr6f669ce2009-05-31 19:02:42 +0000580
lmr1424f3e2010-06-17 13:57:09 +0000581 # Enable migration support for VM by adding extra_params.
582 if extra_params is not None:
583 if " -incoming tcp:0:%d" == extra_params:
584 self.migration_port = kvm_utils.find_free_port(5200, 6000)
585 qemu_command += extra_params % self.migration_port
586 elif " -incoming unix:%s" == extra_params:
587 self.migration_file = os.path.join("/tmp/", "unix-" +
588 time.strftime("%Y%m%d-%H%M%S"))
589 qemu_command += extra_params % self.migration_file
590 else:
591 qemu_command += extra_params
lmr6f669ce2009-05-31 19:02:42 +0000592
lmrdc2ac6a2009-06-10 19:15:49 +0000593 logging.debug("Running qemu command:\n%s", qemu_command)
lmra4967622009-07-23 01:36:32 +0000594 self.process = kvm_subprocess.run_bg(qemu_command, None,
595 logging.debug, "(qemu) ")
lmr6f669ce2009-05-31 19:02:42 +0000596
lmr9e964a02010-06-18 03:46:21 +0000597 # Make sure the process was started successfully
lmra4967622009-07-23 01:36:32 +0000598 if not self.process.is_alive():
599 logging.error("VM could not be created; "
600 "qemu command failed:\n%s" % qemu_command)
601 logging.error("Status: %s" % self.process.get_status())
602 logging.error("Output:" + kvm_utils.format_str_for_message(
603 self.process.get_output()))
lmrdc2ac6a2009-06-10 19:15:49 +0000604 self.destroy()
605 return False
lmr6f669ce2009-05-31 19:02:42 +0000606
lmr9e964a02010-06-18 03:46:21 +0000607 # Establish monitor connections
608 self.monitors = []
609 for monitor_name in kvm_utils.get_sub_dict_names(params,
610 "monitors"):
611 monitor_params = kvm_utils.get_sub_dict(params, monitor_name)
612 # Wait for monitor connection to succeed
613 end_time = time.time() + timeout
614 while time.time() < end_time:
615 try:
616 if monitor_params.get("monitor_type") == "qmp":
lmr449d2252010-06-18 03:48:23 +0000617 # Add a QMP monitor
618 monitor = kvm_monitor.QMPMonitor(
619 monitor_name,
620 self.get_monitor_filename(monitor_name))
lmr9e964a02010-06-18 03:46:21 +0000621 else:
622 # Add a "human" monitor
623 monitor = kvm_monitor.HumanMonitor(
624 monitor_name,
625 self.get_monitor_filename(monitor_name))
626 except kvm_monitor.MonitorError, e:
627 logging.warn(e)
628 else:
lmr449d2252010-06-18 03:48:23 +0000629 if monitor.is_responsive():
lmr9e964a02010-06-18 03:46:21 +0000630 break
631 time.sleep(1)
632 else:
633 logging.error("Could not connect to monitor '%s'" %
634 monitor_name)
635 self.destroy()
636 return False
637 # Add this monitor to the list
638 self.monitors += [monitor]
lmra4967622009-07-23 01:36:32 +0000639
lmrfe6515e2009-07-29 13:01:17 +0000640 # Get the output so far, to see if we have any problems with
641 # hugepage setup.
642 output = self.process.get_output()
643
644 if "alloc_mem_area" in output:
645 logging.error("Could not allocate hugepage memory; "
646 "qemu command:\n%s" % qemu_command)
647 logging.error("Output:" + kvm_utils.format_str_for_message(
648 self.process.get_output()))
lmr090cd7a2010-04-01 02:18:52 +0000649 self.destroy()
lmrfe6515e2009-07-29 13:01:17 +0000650 return False
651
lmr71fa4de2010-06-14 15:54:55 +0000652 logging.debug("VM appears to be alive with PID %s", self.get_pid())
lmraa380a22010-06-22 02:05:29 +0000653
654 # Establish a session with the serial console -- requires a version
655 # of netcat that supports -U
656 self.serial_console = kvm_subprocess.kvm_shell_session(
657 "nc -U %s" % self.get_serial_console_filename(),
658 auto_close=False,
659 output_func=kvm_utils.log_line,
660 output_params=("serial-%s.log" % name,))
661
lmrdc2ac6a2009-06-10 19:15:49 +0000662 return True
663
664 finally:
665 fcntl.lockf(lockfile, fcntl.LOCK_UN)
666 lockfile.close()
lmr6f669ce2009-05-31 19:02:42 +0000667
668
lmr6f669ce2009-05-31 19:02:42 +0000669 def destroy(self, gracefully=True):
670 """
671 Destroy the VM.
672
lmr912c74b2009-08-17 20:43:27 +0000673 If gracefully is True, first attempt to shutdown the VM with a shell
674 command. Then, attempt to destroy the VM via the monitor with a 'quit'
675 command. If that fails, send SIGKILL to the qemu process.
lmr6f669ce2009-05-31 19:02:42 +0000676
677 @param gracefully: Whether an attempt will be made to end the VM
lmr912c74b2009-08-17 20:43:27 +0000678 using a shell command before trying to end the qemu process
679 with a 'quit' or a kill signal.
lmr6f669ce2009-05-31 19:02:42 +0000680 """
lmrf320b042009-09-15 05:48:06 +0000681 try:
682 # Is it already dead?
683 if self.is_dead():
684 logging.debug("VM is already down")
685 return
lmr6f669ce2009-05-31 19:02:42 +0000686
lmr71fa4de2010-06-14 15:54:55 +0000687 logging.debug("Destroying VM with PID %s...", self.get_pid())
lmr6f669ce2009-05-31 19:02:42 +0000688
lmrf320b042009-09-15 05:48:06 +0000689 if gracefully and self.params.get("shutdown_command"):
690 # Try to destroy with shell command
691 logging.debug("Trying to shutdown VM with shell command...")
692 session = self.remote_login()
693 if session:
694 try:
695 # Send the shutdown command
696 session.sendline(self.params.get("shutdown_command"))
697 logging.debug("Shutdown command sent; waiting for VM "
698 "to go down...")
699 if kvm_utils.wait_for(self.is_dead, 60, 1, 1):
700 logging.debug("VM is down")
701 return
702 finally:
703 session.close()
lmr6f669ce2009-05-31 19:02:42 +0000704
lmr9e964a02010-06-18 03:46:21 +0000705 if self.monitor:
706 # Try to destroy with a monitor command
707 logging.debug("Trying to kill VM with monitor command...")
708 try:
709 self.monitor.quit()
710 except kvm_monitor.MonitorError, e:
711 logging.warn(e)
712 else:
713 # Wait for the VM to be really dead
714 if kvm_utils.wait_for(self.is_dead, 5, 0.5, 0.5):
715 logging.debug("VM is down")
716 return
lmrf320b042009-09-15 05:48:06 +0000717
718 # If the VM isn't dead yet...
719 logging.debug("Cannot quit normally; sending a kill to close the "
720 "deal...")
721 kvm_utils.kill_process_tree(self.process.get_pid(), 9)
lmr6f669ce2009-05-31 19:02:42 +0000722 # 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")
lmr6f669ce2009-05-31 19:02:42 +0000725 return
726
lmrf320b042009-09-15 05:48:06 +0000727 logging.error("Process %s is a zombie!" % self.process.get_pid())
lmr6f669ce2009-05-31 19:02:42 +0000728
lmrf320b042009-09-15 05:48:06 +0000729 finally:
lmr9e964a02010-06-18 03:46:21 +0000730 self.monitors = []
lmr4513c432010-02-03 11:59:03 +0000731 if self.pci_assignable:
732 self.pci_assignable.release_devs()
lmrf320b042009-09-15 05:48:06 +0000733 if self.process:
734 self.process.close()
lmraa380a22010-06-22 02:05:29 +0000735 if self.serial_console:
736 self.serial_console.close()
lmr84546f22010-06-29 23:03:34 +0000737 for f in ([self.get_testlog_filename(),
738 self.get_serial_console_filename()] +
lmr9e964a02010-06-18 03:46:21 +0000739 self.get_monitor_filenames()):
740 try:
741 os.unlink(f)
742 except OSError:
743 pass
744
745
746 @property
747 def monitor(self):
748 """
749 Return the main monitor object, selected by the parameter main_monitor.
750 If main_monitor isn't defined, return the first monitor.
751 If no monitors exist, or if main_monitor refers to a nonexistent
752 monitor, return None.
753 """
754 for m in self.monitors:
755 if m.name == self.params.get("main_monitor"):
756 return m
757 if self.monitors and not self.params.get("main_monitor"):
758 return self.monitors[0]
lmr6f669ce2009-05-31 19:02:42 +0000759
760
761 def is_alive(self):
762 """
lmr9e964a02010-06-18 03:46:21 +0000763 Return True if the VM is alive and its monitor is responsive.
lmr6f669ce2009-05-31 19:02:42 +0000764 """
lmra4967622009-07-23 01:36:32 +0000765 # Check if the process is running
766 if self.is_dead():
lmr6f669ce2009-05-31 19:02:42 +0000767 return False
768 # Try sending a monitor command
lmr9e964a02010-06-18 03:46:21 +0000769 return bool(self.monitor) and self.monitor.is_responsive()
lmr6f669ce2009-05-31 19:02:42 +0000770
771
772 def is_dead(self):
773 """
lmra4967622009-07-23 01:36:32 +0000774 Return True if the qemu process is dead.
lmr6f669ce2009-05-31 19:02:42 +0000775 """
lmra4967622009-07-23 01:36:32 +0000776 return not self.process or not self.process.is_alive()
lmr6f669ce2009-05-31 19:02:42 +0000777
778
lmra4197002009-08-13 05:00:51 +0000779 def kill_tail_thread(self):
780 """
781 Stop the tailing thread which reports the output of qemu.
782 """
783 if self.process:
784 self.process.kill_tail_thread()
785
786
lmr6f669ce2009-05-31 19:02:42 +0000787 def get_params(self):
788 """
789 Return the VM's params dict. Most modified params take effect only
790 upon VM.create().
791 """
792 return self.params
793
794
lmr9e964a02010-06-18 03:46:21 +0000795 def get_monitor_filename(self, monitor_name):
796 """
797 Return the filename corresponding to a given monitor name.
798 """
799 return "/tmp/monitor-%s-%s" % (monitor_name, self.instance)
800
801
802 def get_monitor_filenames(self):
803 """
804 Return a list of all monitor filenames (as specified in the VM's
805 params).
806 """
807 return [self.get_monitor_filename(m) for m in
808 kvm_utils.get_sub_dict_names(self.params, "monitors")]
809
810
lmr2b06f332010-06-22 02:03:41 +0000811 def get_serial_console_filename(self):
812 """
813 Return the serial console filename.
814 """
815 return "/tmp/serial-%s" % self.instance
816
817
lmr9e964a02010-06-18 03:46:21 +0000818 def get_testlog_filename(self):
819 """
820 Return the testlog filename.
821 """
822 return "/tmp/testlog-%s" % self.instance
823
824
lmrf4696342009-08-13 04:06:33 +0000825 def get_address(self, index=0):
lmr6f669ce2009-05-31 19:02:42 +0000826 """
lmrf4696342009-08-13 04:06:33 +0000827 Return the address of a NIC of the guest, in host space.
lmr6f669ce2009-05-31 19:02:42 +0000828
lmrf4696342009-08-13 04:06:33 +0000829 If port redirection is used, return 'localhost' (the NIC has no IP
830 address of its own). Otherwise return the NIC's IP address.
831
832 @param index: Index of the NIC whose address is requested.
lmr6f669ce2009-05-31 19:02:42 +0000833 """
lmree90dd92009-08-13 04:13:39 +0000834 nics = kvm_utils.get_sub_dict_names(self.params, "nics")
835 nic_name = nics[index]
lmrf4696342009-08-13 04:06:33 +0000836 nic_params = kvm_utils.get_sub_dict(self.params, nic_name)
837 if nic_params.get("nic_mode") == "tap":
838 mac, ip = kvm_utils.get_mac_ip_pair_from_dict(nic_params)
lmree90dd92009-08-13 04:13:39 +0000839 if not mac:
840 logging.debug("MAC address unavailable")
841 return None
842 if not ip or nic_params.get("always_use_tcpdump") == "yes":
843 # Get the IP address from the cache
844 ip = self.address_cache.get(mac)
845 if not ip:
846 logging.debug("Could not find IP address for MAC address: "
847 "%s" % mac)
848 return None
849 # Make sure the IP address is assigned to this guest
850 nic_dicts = [kvm_utils.get_sub_dict(self.params, nic)
851 for nic in nics]
852 macs = [kvm_utils.get_mac_ip_pair_from_dict(dict)[0]
853 for dict in nic_dicts]
854 if not kvm_utils.verify_ip_address_ownership(ip, macs):
855 logging.debug("Could not verify MAC-IP address mapping: "
856 "%s ---> %s" % (mac, ip))
857 return None
lmrf4696342009-08-13 04:06:33 +0000858 return ip
859 else:
860 return "localhost"
lmr6f669ce2009-05-31 19:02:42 +0000861
862
lmree90dd92009-08-13 04:13:39 +0000863 def get_port(self, port, nic_index=0):
lmr6f669ce2009-05-31 19:02:42 +0000864 """
865 Return the port in host space corresponding to port in guest space.
866
867 @param port: Port number in host space.
lmree90dd92009-08-13 04:13:39 +0000868 @param nic_index: Index of the NIC.
lmr6f669ce2009-05-31 19:02:42 +0000869 @return: If port redirection is used, return the host port redirected
870 to guest port port. Otherwise return port.
871 """
lmree90dd92009-08-13 04:13:39 +0000872 nic_name = kvm_utils.get_sub_dict_names(self.params, "nics")[nic_index]
lmrf4696342009-08-13 04:06:33 +0000873 nic_params = kvm_utils.get_sub_dict(self.params, nic_name)
874 if nic_params.get("nic_mode") == "tap":
875 return port
lmr6f669ce2009-05-31 19:02:42 +0000876 else:
lmrf4696342009-08-13 04:06:33 +0000877 if not self.redirs.has_key(port):
878 logging.warn("Warning: guest port %s requested but not "
879 "redirected" % port)
880 return self.redirs.get(port)
lmr6f669ce2009-05-31 19:02:42 +0000881
882
lmra4967622009-07-23 01:36:32 +0000883 def get_pid(self):
884 """
lmr71fa4de2010-06-14 15:54:55 +0000885 Return the VM's PID. If the VM is dead return None.
886
887 @note: This works under the assumption that self.process.get_pid()
888 returns the PID of the parent shell process.
889 """
890 try:
891 children = commands.getoutput("ps --ppid=%d -o pid=" %
892 self.process.get_pid()).split()
893 return int(children[0])
894 except (TypeError, IndexError, ValueError):
895 return None
896
897
898 def get_shell_pid(self):
899 """
900 Return the PID of the parent shell process.
901
902 @note: This works under the assumption that self.process.get_pid()
903 returns the PID of the parent shell process.
lmra4967622009-07-23 01:36:32 +0000904 """
905 return self.process.get_pid()
906
907
lmr0bee2342010-02-24 00:01:37 +0000908 def get_shared_meminfo(self):
909 """
910 Returns the VM's shared memory information.
911
912 @return: Shared memory used by VM (MB)
913 """
914 if self.is_dead():
915 logging.error("Could not get shared memory info from dead VM.")
916 return None
917
lmr983ecdf2010-06-14 15:57:12 +0000918 filename = "/proc/%d/statm" % self.get_pid()
919 shm = int(open(filename).read().split()[2])
lmr0bee2342010-02-24 00:01:37 +0000920 # statm stores informations in pages, translate it to MB
lmr983ecdf2010-06-14 15:57:12 +0000921 return shm * 4.0 / 1024
lmr0bee2342010-02-24 00:01:37 +0000922
923
lmr912c74b2009-08-17 20:43:27 +0000924 def remote_login(self, nic_index=0, timeout=10):
lmr6f669ce2009-05-31 19:02:42 +0000925 """
lmr912c74b2009-08-17 20:43:27 +0000926 Log into the guest via SSH/Telnet/Netcat.
lmr6f669ce2009-05-31 19:02:42 +0000927 If timeout expires while waiting for output from the guest (e.g. a
928 password prompt or a shell prompt) -- fail.
929
lmree90dd92009-08-13 04:13:39 +0000930 @param nic_index: The index of the NIC to connect to.
lmr6f669ce2009-05-31 19:02:42 +0000931 @param timeout: Time (seconds) before giving up logging into the
932 guest.
933 @return: kvm_spawn object on success and None on failure.
934 """
935 username = self.params.get("username", "")
936 password = self.params.get("password", "")
lmr912c74b2009-08-17 20:43:27 +0000937 prompt = self.params.get("shell_prompt", "[\#\$]")
lmr59f9e2d2009-10-05 18:47:16 +0000938 linesep = eval("'%s'" % self.params.get("shell_linesep", r"\n"))
lmr912c74b2009-08-17 20:43:27 +0000939 client = self.params.get("shell_client")
lmree90dd92009-08-13 04:13:39 +0000940 address = self.get_address(nic_index)
lmr912c74b2009-08-17 20:43:27 +0000941 port = self.get_port(int(self.params.get("shell_port")))
lmre56903f2010-06-22 02:09:35 +0000942 log_filename = ("session-%s-%s.log" %
943 (self.name, kvm_utils.generate_random_string(4)))
lmr912c74b2009-08-17 20:43:27 +0000944
lmree90dd92009-08-13 04:13:39 +0000945 if not address or not port:
946 logging.debug("IP address or port unavailable")
lmr6f669ce2009-05-31 19:02:42 +0000947 return None
948
lmr158604f2010-06-22 01:57:34 +0000949 session = kvm_utils.remote_login(client, address, port, username,
lmre56903f2010-06-22 02:09:35 +0000950 password, prompt, linesep,
951 log_filename, timeout)
lmr912c74b2009-08-17 20:43:27 +0000952
lmr6f669ce2009-05-31 19:02:42 +0000953 if session:
lmr912c74b2009-08-17 20:43:27 +0000954 session.set_status_test_command(self.params.get("status_test_"
lmr6f669ce2009-05-31 19:02:42 +0000955 "command", ""))
956 return session
957
958
lmrc196d492010-05-07 14:14:26 +0000959 def copy_files_to(self, local_path, remote_path, nic_index=0, timeout=600):
lmr6f669ce2009-05-31 19:02:42 +0000960 """
lmr912c74b2009-08-17 20:43:27 +0000961 Transfer files to the guest.
lmr6f669ce2009-05-31 19:02:42 +0000962
963 @param local_path: Host path
964 @param remote_path: Guest path
lmr912c74b2009-08-17 20:43:27 +0000965 @param nic_index: The index of the NIC to connect to.
lmr6f669ce2009-05-31 19:02:42 +0000966 @param timeout: Time (seconds) before giving up on doing the remote
967 copy.
968 """
969 username = self.params.get("username", "")
970 password = self.params.get("password", "")
lmr912c74b2009-08-17 20:43:27 +0000971 client = self.params.get("file_transfer_client")
lmree90dd92009-08-13 04:13:39 +0000972 address = self.get_address(nic_index)
lmr912c74b2009-08-17 20:43:27 +0000973 port = self.get_port(int(self.params.get("file_transfer_port")))
lmre56903f2010-06-22 02:09:35 +0000974 log_filename = ("scp-%s-%s.log" %
975 (self.name, kvm_utils.generate_random_string(4)))
lmr912c74b2009-08-17 20:43:27 +0000976
lmree90dd92009-08-13 04:13:39 +0000977 if not address or not port:
978 logging.debug("IP address or port unavailable")
lmr6f669ce2009-05-31 19:02:42 +0000979 return None
lmr912c74b2009-08-17 20:43:27 +0000980
981 if client == "scp":
982 return kvm_utils.scp_to_remote(address, port, username, password,
lmre56903f2010-06-22 02:09:35 +0000983 local_path, remote_path,
984 log_filename, timeout)
lmr6f669ce2009-05-31 19:02:42 +0000985
986
lmrc196d492010-05-07 14:14:26 +0000987 def copy_files_from(self, remote_path, local_path, nic_index=0, timeout=600):
lmr6f669ce2009-05-31 19:02:42 +0000988 """
lmr912c74b2009-08-17 20:43:27 +0000989 Transfer files from the guest.
lmr6f669ce2009-05-31 19:02:42 +0000990
991 @param local_path: Guest path
992 @param remote_path: Host path
lmr912c74b2009-08-17 20:43:27 +0000993 @param nic_index: The index of the NIC to connect to.
lmr6f669ce2009-05-31 19:02:42 +0000994 @param timeout: Time (seconds) before giving up on doing the remote
995 copy.
996 """
997 username = self.params.get("username", "")
998 password = self.params.get("password", "")
lmr912c74b2009-08-17 20:43:27 +0000999 client = self.params.get("file_transfer_client")
lmree90dd92009-08-13 04:13:39 +00001000 address = self.get_address(nic_index)
lmr912c74b2009-08-17 20:43:27 +00001001 port = self.get_port(int(self.params.get("file_transfer_port")))
lmre56903f2010-06-22 02:09:35 +00001002 log_filename = ("scp-%s-%s.log" %
1003 (self.name, kvm_utils.generate_random_string(4)))
lmr912c74b2009-08-17 20:43:27 +00001004
lmree90dd92009-08-13 04:13:39 +00001005 if not address or not port:
1006 logging.debug("IP address or port unavailable")
lmr6f669ce2009-05-31 19:02:42 +00001007 return None
lmr6f669ce2009-05-31 19:02:42 +00001008
lmr912c74b2009-08-17 20:43:27 +00001009 if client == "scp":
1010 return kvm_utils.scp_from_remote(address, port, username, password,
lmre56903f2010-06-22 02:09:35 +00001011 remote_path, local_path,
1012 log_filename, timeout)
lmr6f669ce2009-05-31 19:02:42 +00001013
1014
lmraa380a22010-06-22 02:05:29 +00001015 def serial_login(self, timeout=10):
1016 """
1017 Log into the guest via the serial console.
1018 If timeout expires while waiting for output from the guest (e.g. a
1019 password prompt or a shell prompt) -- fail.
1020
1021 @param timeout: Time (seconds) before giving up logging into the guest.
1022 @return: kvm_spawn object on success and None on failure.
1023 """
1024 username = self.params.get("username", "")
1025 password = self.params.get("password", "")
1026 prompt = self.params.get("shell_prompt", "[\#\$]")
1027 linesep = eval("'%s'" % self.params.get("shell_linesep", r"\n"))
1028 status_test_command = self.params.get("status_test_command", "")
1029
1030 if self.serial_console:
1031 self.serial_console.set_linesep(linesep)
1032 self.serial_console.set_status_test_command(status_test_command)
1033 else:
1034 return None
1035
1036 # Make sure we get a login prompt
1037 self.serial_console.sendline()
1038
1039 if kvm_utils._remote_login(self.serial_console, username, password,
1040 prompt, timeout):
1041 return self.serial_console
1042
1043
lmr6f669ce2009-05-31 19:02:42 +00001044 def send_key(self, keystr):
1045 """
1046 Send a key event to the VM.
1047
1048 @param: keystr: A key event string (e.g. "ctrl-alt-delete")
1049 """
1050 # For compatibility with versions of QEMU that do not recognize all
1051 # key names: replace keyname with the hex value from the dict, which
1052 # QEMU will definitely accept
lmr9e964a02010-06-18 03:46:21 +00001053 dict = {"comma": "0x33",
1054 "dot": "0x34",
1055 "slash": "0x35"}
1056 for key, value in dict.items():
1057 keystr = keystr.replace(key, value)
1058 self.monitor.sendkey(keystr)
lmr6f669ce2009-05-31 19:02:42 +00001059 time.sleep(0.2)
1060
1061
1062 def send_string(self, str):
1063 """
1064 Send a string to the VM.
1065
1066 @param str: String, that must consist of alphanumeric characters only.
1067 Capital letters are allowed.
1068 """
1069 for char in str:
1070 if char.isupper():
1071 self.send_key("shift-%s" % char.lower())
1072 else:
1073 self.send_key(char)
lmra2533222009-07-20 12:43:46 +00001074
mbligh1ef218d2009-08-03 16:57:56 +00001075
lmra2533222009-07-20 12:43:46 +00001076 def get_uuid(self):
1077 """
1078 Catch UUID of the VM.
1079
1080 @return: None,if not specified in config file
1081 """
1082 if self.params.get("uuid") == "random":
1083 return self.uuid
1084 else:
1085 return self.params.get("uuid", None)
lmrdd2ff922009-12-01 23:39:12 +00001086
1087
1088 def get_cpu_count(self):
1089 """
1090 Get the cpu count of the VM.
1091 """
lmr13426552010-01-17 15:38:41 +00001092 session = self.remote_login()
1093 if not session:
1094 return None
lmrdd2ff922009-12-01 23:39:12 +00001095 try:
lmr13426552010-01-17 15:38:41 +00001096 cmd = self.params.get("cpu_chk_cmd")
1097 s, count = session.get_command_status_output(cmd)
1098 if s == 0:
1099 return int(count)
lmrdd2ff922009-12-01 23:39:12 +00001100 return None
1101 finally:
1102 session.close()
1103
1104
lmr28426c82010-04-16 06:02:58 +00001105 def get_memory_size(self, cmd=None):
lmrdd2ff922009-12-01 23:39:12 +00001106 """
lmr28426c82010-04-16 06:02:58 +00001107 Get bootup memory size of the VM.
1108
1109 @param check_cmd: Command used to check memory. If not provided,
1110 self.params.get("mem_chk_cmd") will be used.
lmrdd2ff922009-12-01 23:39:12 +00001111 """
lmr13426552010-01-17 15:38:41 +00001112 session = self.remote_login()
1113 if not session:
lmrdd2ff922009-12-01 23:39:12 +00001114 return None
lmr13426552010-01-17 15:38:41 +00001115 try:
lmr28426c82010-04-16 06:02:58 +00001116 if not cmd:
1117 cmd = self.params.get("mem_chk_cmd")
lmr13426552010-01-17 15:38:41 +00001118 s, mem_str = session.get_command_status_output(cmd)
1119 if s != 0:
1120 return None
lmr6d69f4d2010-02-12 11:35:55 +00001121 mem = re.findall("([0-9]+)", mem_str)
lmr13426552010-01-17 15:38:41 +00001122 mem_size = 0
1123 for m in mem:
1124 mem_size += int(m)
1125 if "GB" in mem_str:
1126 mem_size *= 1024
1127 elif "MB" in mem_str:
1128 pass
1129 else:
1130 mem_size /= 1024
1131 return int(mem_size)
lmrdd2ff922009-12-01 23:39:12 +00001132 finally:
1133 session.close()
lmr28426c82010-04-16 06:02:58 +00001134
1135
1136 def get_current_memory_size(self):
1137 """
1138 Get current memory size of the VM, rather than bootup memory.
1139 """
1140 cmd = self.params.get("mem_chk_cur_cmd")
1141 return self.get_memory_size(cmd)