blob: 87b037feb09c7675d35122ea4abc3352cc8ee015 [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 = []
121 for nic in params.get("nics").split():
lmr42b16662010-06-22 11:55:23 +0000122 self.netdev_id.append(kvm_utils.generate_random_id())
lmr6f669ce2009-05-31 19:02:42 +0000123
lmr9e964a02010-06-18 03:46:21 +0000124 # Find a unique identifier for this VM
lmr8b134f92009-06-08 14:47:31 +0000125 while True:
lmrd16a67d2009-06-10 19:52:59 +0000126 self.instance = (time.strftime("%Y%m%d-%H%M%S-") +
127 kvm_utils.generate_random_string(4))
lmr9e964a02010-06-18 03:46:21 +0000128 if not glob.glob("/tmp/*%s" % self.instance):
lmr8b134f92009-06-08 14:47:31 +0000129 break
130
131
lmr52800ba2009-08-17 20:49:58 +0000132 def clone(self, name=None, params=None, root_dir=None, address_cache=None):
lmr2c241172009-06-08 15:11:29 +0000133 """
134 Return a clone of the VM object with optionally modified parameters.
135 The clone is initially not alive and needs to be started using create().
136 Any parameters not passed to this function are copied from the source
137 VM.
138
139 @param name: Optional new VM name
140 @param params: Optional new VM creation parameters
lmr90b9fd52009-08-17 20:48:18 +0000141 @param root_dir: Optional new base directory for relative filenames
lmree90dd92009-08-13 04:13:39 +0000142 @param address_cache: A dict that maps MAC addresses to IP addresses
lmr2c241172009-06-08 15:11:29 +0000143 """
lmre45a1f22009-11-10 16:35:08 +0000144 if name is None:
lmr2c241172009-06-08 15:11:29 +0000145 name = self.name
lmre45a1f22009-11-10 16:35:08 +0000146 if params is None:
lmr2c241172009-06-08 15:11:29 +0000147 params = self.params.copy()
lmre45a1f22009-11-10 16:35:08 +0000148 if root_dir is None:
lmr90b9fd52009-08-17 20:48:18 +0000149 root_dir = self.root_dir
lmre45a1f22009-11-10 16:35:08 +0000150 if address_cache is None:
lmree90dd92009-08-13 04:13:39 +0000151 address_cache = self.address_cache
lmr52800ba2009-08-17 20:49:58 +0000152 return VM(name, params, root_dir, address_cache)
lmr2c241172009-06-08 15:11:29 +0000153
154
lmr52800ba2009-08-17 20:49:58 +0000155 def make_qemu_command(self, name=None, params=None, root_dir=None):
lmr6f669ce2009-05-31 19:02:42 +0000156 """
157 Generate a qemu command line. All parameters are optional. If a
158 parameter is not supplied, the corresponding value stored in the
159 class attributes is used.
160
lmr6f669ce2009-05-31 19:02:42 +0000161 @param name: The name of the object
162 @param params: A dict containing VM params
lmr90b9fd52009-08-17 20:48:18 +0000163 @param root_dir: Base directory for relative filenames
lmr6f669ce2009-05-31 19:02:42 +0000164
165 @note: The params dict should contain:
166 mem -- memory size in MBs
167 cdrom -- ISO filename to use with the qemu -cdrom parameter
lmr6f669ce2009-05-31 19:02:42 +0000168 extra_params -- a string to append to the qemu command
lmr912c74b2009-08-17 20:43:27 +0000169 shell_port -- port of the remote shell daemon on the guest
170 (SSH, Telnet or the home-made Remote Shell Server)
171 shell_client -- client program to use for connecting to the
172 remote shell daemon on the guest (ssh, telnet or nc)
lmreeff0eb2009-06-10 19:19:15 +0000173 x11_display -- if specified, the DISPLAY environment variable
174 will be be set to this value for the qemu process (useful for
175 SDL rendering)
lmr6f669ce2009-05-31 19:02:42 +0000176 images -- a list of image object names, separated by spaces
177 nics -- a list of NIC object names, separated by spaces
178
179 For each image in images:
180 drive_format -- string to pass as 'if' parameter for this
181 image (e.g. ide, scsi)
182 image_snapshot -- if yes, pass 'snapshot=on' to qemu for
183 this image
184 image_boot -- if yes, pass 'boot=on' to qemu for this image
185 In addition, all parameters required by get_image_filename.
186
187 For each NIC in nics:
188 nic_model -- string to pass as 'model' parameter for this
189 NIC (e.g. e1000)
190 """
lmr48abd7d2010-05-26 13:48:04 +0000191 # Helper function for command line option wrappers
192 def has_option(help, option):
193 return bool(re.search(r"^-%s(\s|$)" % option, help, re.MULTILINE))
194
195 # Wrappers for all supported qemu command line parameters.
196 # This is meant to allow support for multiple qemu versions.
197 # Each of these functions receives the output of 'qemu -help' as a
198 # parameter, and should add the requested command line option
199 # accordingly.
200
201 def add_name(help, name):
202 return " -name '%s'" % name
203
lmr9e964a02010-06-18 03:46:21 +0000204 def add_human_monitor(help, filename):
lmr09a78162010-06-14 16:29:23 +0000205 return " -monitor unix:'%s',server,nowait" % filename
lmr48abd7d2010-05-26 13:48:04 +0000206
lmr9e964a02010-06-18 03:46:21 +0000207 def add_qmp_monitor(help, filename):
208 return " -qmp unix:'%s',server,nowait" % filename
209
lmr2b06f332010-06-22 02:03:41 +0000210 def add_serial(help, filename):
211 return " -serial unix:'%s',server,nowait" % filename
212
lmr48abd7d2010-05-26 13:48:04 +0000213 def add_mem(help, mem):
214 return " -m %s" % mem
215
216 def add_smp(help, smp):
217 return " -smp %s" % smp
218
219 def add_cdrom(help, filename, index=2):
220 if has_option(help, "drive"):
lmr09a78162010-06-14 16:29:23 +0000221 return " -drive file='%s',index=%d,media=cdrom" % (filename,
222 index)
lmr48abd7d2010-05-26 13:48:04 +0000223 else:
lmr09a78162010-06-14 16:29:23 +0000224 return " -cdrom '%s'" % filename
lmr48abd7d2010-05-26 13:48:04 +0000225
226 def add_drive(help, filename, format=None, cache=None, werror=None,
227 serial=None, snapshot=False, boot=False):
lmr09a78162010-06-14 16:29:23 +0000228 cmd = " -drive file='%s'" % filename
lmr48abd7d2010-05-26 13:48:04 +0000229 if format: cmd += ",if=%s" % format
230 if cache: cmd += ",cache=%s" % cache
231 if werror: cmd += ",werror=%s" % werror
lmr09a78162010-06-14 16:29:23 +0000232 if serial: cmd += ",serial='%s'" % serial
lmr48abd7d2010-05-26 13:48:04 +0000233 if snapshot: cmd += ",snapshot=on"
234 if boot: cmd += ",boot=on"
235 return cmd
236
lmrb1cad1e2010-06-17 17:36:09 +0000237 def add_nic(help, vlan, model=None, mac=None, netdev_id=None):
lmr48abd7d2010-05-26 13:48:04 +0000238 cmd = " -net nic,vlan=%d" % vlan
lmrb1cad1e2010-06-17 17:36:09 +0000239 if has_option(help, "netdev"):
240 cmd +=",netdev=%s" % netdev_id
lmr48abd7d2010-05-26 13:48:04 +0000241 if model: cmd += ",model=%s" % model
lmr09a78162010-06-14 16:29:23 +0000242 if mac: cmd += ",macaddr='%s'" % mac
lmr48abd7d2010-05-26 13:48:04 +0000243 return cmd
244
245 def add_net(help, vlan, mode, ifname=None, script=None,
lmrb1cad1e2010-06-17 17:36:09 +0000246 downscript=None, netdev_id=None):
247 if has_option(help, "netdev"):
248 cmd = " -netdev %s,id=%s" % (mode, netdev_id)
249 else:
250 cmd = " -net %s,vlan=%d" % (mode, vlan)
lmr48abd7d2010-05-26 13:48:04 +0000251 if mode == "tap":
lmr09a78162010-06-14 16:29:23 +0000252 if ifname: cmd += ",ifname='%s'" % ifname
253 if script: cmd += ",script='%s'" % script
254 cmd += ",downscript='%s'" % (downscript or "no")
lmr48abd7d2010-05-26 13:48:04 +0000255 return cmd
256
257 def add_floppy(help, filename):
lmr09a78162010-06-14 16:29:23 +0000258 return " -fda '%s'" % filename
lmr48abd7d2010-05-26 13:48:04 +0000259
260 def add_tftp(help, filename):
lmr09a78162010-06-14 16:29:23 +0000261 return " -tftp '%s'" % filename
lmr48abd7d2010-05-26 13:48:04 +0000262
263 def add_tcp_redir(help, host_port, guest_port):
264 return " -redir tcp:%s::%s" % (host_port, guest_port)
265
266 def add_vnc(help, vnc_port):
267 return " -vnc :%d" % (vnc_port - 5900)
268
269 def add_sdl(help):
270 if has_option(help, "sdl"):
271 return " -sdl"
272 else:
273 return ""
274
275 def add_nographic(help):
276 return " -nographic"
277
278 def add_uuid(help, uuid):
lmr09a78162010-06-14 16:29:23 +0000279 return " -uuid '%s'" % uuid
lmr48abd7d2010-05-26 13:48:04 +0000280
281 def add_pcidevice(help, host):
lmr09a78162010-06-14 16:29:23 +0000282 return " -pcidevice host='%s'" % host
lmr48abd7d2010-05-26 13:48:04 +0000283
lmr41cb8fc2010-06-10 15:30:45 +0000284 def add_kernel(help, filename):
lmr09a78162010-06-14 16:29:23 +0000285 return " -kernel '%s'" % filename
lmr41cb8fc2010-06-10 15:30:45 +0000286
287 def add_initrd(help, filename):
lmr09a78162010-06-14 16:29:23 +0000288 return " -initrd '%s'" % filename
lmr41cb8fc2010-06-10 15:30:45 +0000289
lmre0474e32010-06-29 14:10:09 +0000290 def add_kernel_cmdline(help, cmdline):
291 return " -append %s" % cmdline
292
lmr48abd7d2010-05-26 13:48:04 +0000293 # End of command line option wrappers
294
295 if name is None: name = self.name
296 if params is None: params = self.params
297 if root_dir is None: root_dir = self.root_dir
298
299 qemu_binary = kvm_utils.get_path(root_dir, params.get("qemu_binary",
300 "qemu"))
301 # Get the output of 'qemu -help' (log a message in case this call never
302 # returns or causes some other kind of trouble)
303 logging.debug("Getting output of 'qemu -help'")
304 help = commands.getoutput("%s -help" % qemu_binary)
lmr6f669ce2009-05-31 19:02:42 +0000305
lmreeff0eb2009-06-10 19:19:15 +0000306 # Start constructing the qemu command
307 qemu_cmd = ""
308 # Set the X11 display parameter if requested
309 if params.get("x11_display"):
310 qemu_cmd += "DISPLAY=%s " % params.get("x11_display")
311 # Add the qemu binary
lmr48abd7d2010-05-26 13:48:04 +0000312 qemu_cmd += qemu_binary
lmreeff0eb2009-06-10 19:19:15 +0000313 # Add the VM's name
lmr48abd7d2010-05-26 13:48:04 +0000314 qemu_cmd += add_name(help, name)
lmr9e964a02010-06-18 03:46:21 +0000315 # Add monitors
316 for monitor_name in kvm_utils.get_sub_dict_names(params, "monitors"):
317 monitor_params = kvm_utils.get_sub_dict(params, monitor_name)
318 monitor_filename = self.get_monitor_filename(monitor_name)
319 if monitor_params.get("monitor_type") == "qmp":
320 qemu_cmd += add_qmp_monitor(help, monitor_filename)
321 else:
322 qemu_cmd += add_human_monitor(help, monitor_filename)
lmr6f669ce2009-05-31 19:02:42 +0000323
lmr2b06f332010-06-22 02:03:41 +0000324 # Add serial console redirection
325 qemu_cmd += add_serial(help, self.get_serial_console_filename())
326
lmr6f669ce2009-05-31 19:02:42 +0000327 for image_name in kvm_utils.get_sub_dict_names(params, "images"):
328 image_params = kvm_utils.get_sub_dict(params, image_name)
lmr9d75ee32009-09-29 13:14:13 +0000329 if image_params.get("boot_drive") == "no":
330 continue
lmr48abd7d2010-05-26 13:48:04 +0000331 qemu_cmd += add_drive(help,
332 get_image_filename(image_params, root_dir),
333 image_params.get("drive_format"),
334 image_params.get("drive_cache"),
335 image_params.get("drive_werror"),
336 image_params.get("drive_serial"),
337 image_params.get("image_snapshot") == "yes",
338 image_params.get("image_boot") == "yes")
lmr6f669ce2009-05-31 19:02:42 +0000339
340 vlan = 0
341 for nic_name in kvm_utils.get_sub_dict_names(params, "nics"):
342 nic_params = kvm_utils.get_sub_dict(params, nic_name)
lmrf4696342009-08-13 04:06:33 +0000343 # Handle the '-net nic' part
lmr48abd7d2010-05-26 13:48:04 +0000344 mac = None
345 if "address_index" in nic_params:
346 mac = kvm_utils.get_mac_ip_pair_from_dict(nic_params)[0]
lmrb1cad1e2010-06-17 17:36:09 +0000347 qemu_cmd += add_nic(help, vlan, nic_params.get("nic_model"), mac,
348 self.netdev_id[vlan])
lmrf4696342009-08-13 04:06:33 +0000349 # Handle the '-net tap' or '-net user' part
lmre4eaa862010-06-01 19:15:14 +0000350 script = nic_params.get("nic_script")
351 downscript = nic_params.get("nic_downscript")
lmr48abd7d2010-05-26 13:48:04 +0000352 if script:
353 script = kvm_utils.get_path(root_dir, script)
354 if downscript:
355 downscript = kvm_utils.get_path(root_dir, downscript)
356 qemu_cmd += add_net(help, vlan, nic_params.get("nic_mode", "user"),
357 nic_params.get("nic_ifname"),
lmrb1cad1e2010-06-17 17:36:09 +0000358 script, downscript, self.netdev_id[vlan])
lmrf4696342009-08-13 04:06:33 +0000359 # Proceed to next NIC
lmr6f669ce2009-05-31 19:02:42 +0000360 vlan += 1
361
362 mem = params.get("mem")
363 if mem:
lmr48abd7d2010-05-26 13:48:04 +0000364 qemu_cmd += add_mem(help, mem)
lmr6f669ce2009-05-31 19:02:42 +0000365
lmrc43bf372009-11-10 13:19:00 +0000366 smp = params.get("smp")
367 if smp:
lmrdb3fe612010-06-14 16:19:28 +0000368 qemu_cmd += add_smp(help, smp)
lmrc43bf372009-11-10 13:19:00 +0000369
lmr6f669ce2009-05-31 19:02:42 +0000370 iso = params.get("cdrom")
371 if iso:
lmr90b9fd52009-08-17 20:48:18 +0000372 iso = kvm_utils.get_path(root_dir, iso)
lmr48abd7d2010-05-26 13:48:04 +0000373 qemu_cmd += add_cdrom(help, iso)
lmr89fd6412010-01-18 02:42:57 +0000374
375 # Even though this is not a really scalable approach,
376 # it doesn't seem like we are going to need more than
377 # 2 CDs active on the same VM.
378 iso_extra = params.get("cdrom_extra")
379 if iso_extra:
380 iso_extra = kvm_utils.get_path(root_dir, iso_extra)
lmr48abd7d2010-05-26 13:48:04 +0000381 qemu_cmd += add_cdrom(help, iso_extra, 3)
lmr6f669ce2009-05-31 19:02:42 +0000382
lmrb0a9b762009-10-09 20:43:30 +0000383 # We may want to add {floppy_otps} parameter for -fda
lmr48abd7d2010-05-26 13:48:04 +0000384 # {fat:floppy:}/path/. However vvfat is not usually recommended.
lmrb0a9b762009-10-09 20:43:30 +0000385 floppy = params.get("floppy")
386 if floppy:
lmrf69f6b12009-11-10 16:33:44 +0000387 floppy = kvm_utils.get_path(root_dir, floppy)
lmr48abd7d2010-05-26 13:48:04 +0000388 qemu_cmd += add_floppy(help, floppy)
lmrb0a9b762009-10-09 20:43:30 +0000389
390 tftp = params.get("tftp")
391 if tftp:
lmrf69f6b12009-11-10 16:33:44 +0000392 tftp = kvm_utils.get_path(root_dir, tftp)
lmr48abd7d2010-05-26 13:48:04 +0000393 qemu_cmd += add_tftp(help, tftp)
lmr6f669ce2009-05-31 19:02:42 +0000394
lmr41cb8fc2010-06-10 15:30:45 +0000395 kernel = params.get("kernel")
396 if kernel:
397 kernel = kvm_utils.get_path(root_dir, kernel)
398 qemu_cmd += add_kernel(help, kernel)
399
lmre0474e32010-06-29 14:10:09 +0000400 kernel_cmdline = params.get("kernel_cmdline")
401 if kernel_cmdline:
402 qemu_cmd += add_kernel_cmdline(help, kernel_cmdline)
403
lmr41cb8fc2010-06-10 15:30:45 +0000404 initrd = params.get("initrd")
405 if initrd:
406 initrd = kvm_utils.get_path(root_dir, initrd)
407 qemu_cmd += add_initrd(help, initrd)
408
lmr6f669ce2009-05-31 19:02:42 +0000409 for redir_name in kvm_utils.get_sub_dict_names(params, "redirs"):
410 redir_params = kvm_utils.get_sub_dict(params, redir_name)
411 guest_port = int(redir_params.get("guest_port"))
lmrf4696342009-08-13 04:06:33 +0000412 host_port = self.redirs.get(guest_port)
lmr48abd7d2010-05-26 13:48:04 +0000413 qemu_cmd += add_tcp_redir(help, host_port, guest_port)
lmr6f669ce2009-05-31 19:02:42 +0000414
415 if params.get("display") == "vnc":
lmr48abd7d2010-05-26 13:48:04 +0000416 qemu_cmd += add_vnc(help, self.vnc_port)
lmr6f669ce2009-05-31 19:02:42 +0000417 elif params.get("display") == "sdl":
lmr48abd7d2010-05-26 13:48:04 +0000418 qemu_cmd += add_sdl(help)
lmr6f669ce2009-05-31 19:02:42 +0000419 elif params.get("display") == "nographic":
lmr48abd7d2010-05-26 13:48:04 +0000420 qemu_cmd += add_nographic(help)
lmr6f669ce2009-05-31 19:02:42 +0000421
lmra2533222009-07-20 12:43:46 +0000422 if params.get("uuid") == "random":
lmr48abd7d2010-05-26 13:48:04 +0000423 qemu_cmd += add_uuid(help, self.uuid)
lmra2533222009-07-20 12:43:46 +0000424 elif params.get("uuid"):
lmr48abd7d2010-05-26 13:48:04 +0000425 qemu_cmd += add_uuid(help, params.get("uuid"))
lmra2533222009-07-20 12:43:46 +0000426
lmr31af3a12010-01-18 16:46:52 +0000427 # If the PCI assignment step went OK, add each one of the PCI assigned
428 # devices to the qemu command line.
429 if self.pci_assignable:
430 for pci_id in self.pa_pci_ids:
lmr48abd7d2010-05-26 13:48:04 +0000431 qemu_cmd += add_pcidevice(help, pci_id)
432
433 extra_params = params.get("extra_params")
434 if extra_params:
435 qemu_cmd += " %s" % extra_params
lmr31af3a12010-01-18 16:46:52 +0000436
lmr6f669ce2009-05-31 19:02:42 +0000437 return qemu_cmd
438
439
lmr52800ba2009-08-17 20:49:58 +0000440 def create(self, name=None, params=None, root_dir=None,
lmr1424f3e2010-06-17 13:57:09 +0000441 for_migration=False, timeout=5.0, extra_params=None):
lmr6f669ce2009-05-31 19:02:42 +0000442 """
443 Start the VM by running a qemu command.
444 All parameters are optional. The following applies to all parameters
445 but for_migration: If a parameter is not supplied, the corresponding
446 value stored in the class attributes is used, and if it is supplied,
447 it is stored for later use.
448
449 @param name: The name of the object
450 @param params: A dict containing VM params
lmr90b9fd52009-08-17 20:48:18 +0000451 @param root_dir: Base directory for relative filenames
lmr6f669ce2009-05-31 19:02:42 +0000452 @param for_migration: If True, start the VM with the -incoming
453 option
lmr1424f3e2010-06-17 13:57:09 +0000454 @param extra_params: extra params for qemu command.e.g -incoming option
455 Please use this parameter instead of for_migration.
lmr6f669ce2009-05-31 19:02:42 +0000456 """
lmr135b5e62009-06-10 19:22:31 +0000457 self.destroy()
458
lmre45a1f22009-11-10 16:35:08 +0000459 if name is not None:
lmr6f669ce2009-05-31 19:02:42 +0000460 self.name = name
lmre45a1f22009-11-10 16:35:08 +0000461 if params is not None:
lmr6f669ce2009-05-31 19:02:42 +0000462 self.params = params
lmre45a1f22009-11-10 16:35:08 +0000463 if root_dir is not None:
lmr90b9fd52009-08-17 20:48:18 +0000464 self.root_dir = root_dir
lmr6f669ce2009-05-31 19:02:42 +0000465 name = self.name
466 params = self.params
lmr90b9fd52009-08-17 20:48:18 +0000467 root_dir = self.root_dir
lmr6f669ce2009-05-31 19:02:42 +0000468
469 # Verify the md5sum of the ISO image
470 iso = params.get("cdrom")
471 if iso:
lmr90b9fd52009-08-17 20:48:18 +0000472 iso = kvm_utils.get_path(root_dir, iso)
lmr6f669ce2009-05-31 19:02:42 +0000473 if not os.path.exists(iso):
474 logging.error("ISO file not found: %s" % iso)
475 return False
476 compare = False
477 if params.get("md5sum_1m"):
lmrf4696342009-08-13 04:06:33 +0000478 logging.debug("Comparing expected MD5 sum with MD5 sum of "
479 "first MB of ISO file...")
lmrd60882f2010-02-04 03:26:36 +0000480 actual_hash = utils.hash_file(iso, 1048576, method="md5")
lmr03ba22e2009-10-23 12:07:44 +0000481 expected_hash = params.get("md5sum_1m")
lmr6f669ce2009-05-31 19:02:42 +0000482 compare = True
483 elif params.get("md5sum"):
lmrf4696342009-08-13 04:06:33 +0000484 logging.debug("Comparing expected MD5 sum with MD5 sum of ISO "
485 "file...")
lmrd60882f2010-02-04 03:26:36 +0000486 actual_hash = utils.hash_file(iso, method="md5")
lmr03ba22e2009-10-23 12:07:44 +0000487 expected_hash = params.get("md5sum")
488 compare = True
489 elif params.get("sha1sum"):
490 logging.debug("Comparing expected SHA1 sum with SHA1 sum of "
491 "ISO file...")
lmrd60882f2010-02-04 03:26:36 +0000492 actual_hash = utils.hash_file(iso, method="sha1")
lmrea1266e2009-11-10 16:41:08 +0000493 expected_hash = params.get("sha1sum")
lmr6f669ce2009-05-31 19:02:42 +0000494 compare = True
495 if compare:
lmr03ba22e2009-10-23 12:07:44 +0000496 if actual_hash == expected_hash:
497 logging.debug("Hashes match")
lmr6f669ce2009-05-31 19:02:42 +0000498 else:
lmr03ba22e2009-10-23 12:07:44 +0000499 logging.error("Actual hash differs from expected one")
lmr6f669ce2009-05-31 19:02:42 +0000500 return False
501
lmrdc2ac6a2009-06-10 19:15:49 +0000502 # Make sure the following code is not executed by more than one thread
503 # at the same time
504 lockfile = open("/tmp/kvm-autotest-vm-create.lock", "w+")
505 fcntl.lockf(lockfile, fcntl.LOCK_EX)
lmr6f669ce2009-05-31 19:02:42 +0000506
lmrdc2ac6a2009-06-10 19:15:49 +0000507 try:
508 # Handle port redirections
509 redir_names = kvm_utils.get_sub_dict_names(params, "redirs")
510 host_ports = kvm_utils.find_free_ports(5000, 6000, len(redir_names))
511 self.redirs = {}
512 for i in range(len(redir_names)):
513 redir_params = kvm_utils.get_sub_dict(params, redir_names[i])
514 guest_port = int(redir_params.get("guest_port"))
515 self.redirs[guest_port] = host_ports[i]
lmr6f669ce2009-05-31 19:02:42 +0000516
lmrdc2ac6a2009-06-10 19:15:49 +0000517 # Find available VNC port, if needed
518 if params.get("display") == "vnc":
lmrc0da8902010-05-17 20:31:36 +0000519 self.vnc_port = kvm_utils.find_free_port(5900, 6100)
lmr6f669ce2009-05-31 19:02:42 +0000520
lmra2533222009-07-20 12:43:46 +0000521 # Find random UUID if specified 'uuid = random' in config file
522 if params.get("uuid") == "random":
523 f = open("/proc/sys/kernel/random/uuid")
524 self.uuid = f.read().strip()
525 f.close()
526
lmr31ed61d2010-06-07 13:21:38 +0000527 # Assign a PCI assignable device
528 self.pci_assignable = None
529 pa_type = params.get("pci_assignable")
530 if pa_type in ["vf", "pf", "mixed"]:
lmr31af3a12010-01-18 16:46:52 +0000531 pa_devices_requested = params.get("devices_requested")
532
533 # Virtual Functions (VF) assignable devices
534 if pa_type == "vf":
lmr31ed61d2010-06-07 13:21:38 +0000535 self.pci_assignable = kvm_utils.PciAssignable(
536 type=pa_type,
537 driver=params.get("driver"),
538 driver_option=params.get("driver_option"),
539 devices_requested=pa_devices_requested)
lmr31af3a12010-01-18 16:46:52 +0000540 # Physical NIC (PF) assignable devices
541 elif pa_type == "pf":
lmr31ed61d2010-06-07 13:21:38 +0000542 self.pci_assignable = kvm_utils.PciAssignable(
543 type=pa_type,
544 names=params.get("device_names"),
545 devices_requested=pa_devices_requested)
lmr31af3a12010-01-18 16:46:52 +0000546 # Working with both VF and PF
547 elif pa_type == "mixed":
lmr31ed61d2010-06-07 13:21:38 +0000548 self.pci_assignable = kvm_utils.PciAssignable(
549 type=pa_type,
550 driver=params.get("driver"),
551 driver_option=params.get("driver_option"),
552 names=params.get("device_names"),
553 devices_requested=pa_devices_requested)
lmr31af3a12010-01-18 16:46:52 +0000554
555 self.pa_pci_ids = self.pci_assignable.request_devs()
556
557 if self.pa_pci_ids:
lmr31ed61d2010-06-07 13:21:38 +0000558 logging.debug("Successfuly assigned devices: %s",
lmr31af3a12010-01-18 16:46:52 +0000559 self.pa_pci_ids)
560 else:
561 logging.error("No PCI assignable devices were assigned "
562 "and 'pci_assignable' is defined to %s "
lmr31ed61d2010-06-07 13:21:38 +0000563 "on your config file. Aborting VM creation.",
lmr31af3a12010-01-18 16:46:52 +0000564 pa_type)
565 return False
566
lmr856d58c2010-06-08 18:29:31 +0000567 elif pa_type and pa_type != "no":
lmr31ed61d2010-06-07 13:21:38 +0000568 logging.warn("Unsupported pci_assignable type: %s", pa_type)
lmr31af3a12010-01-18 16:46:52 +0000569
lmrdc2ac6a2009-06-10 19:15:49 +0000570 # Make qemu command
571 qemu_command = self.make_qemu_command()
lmr6f669ce2009-05-31 19:02:42 +0000572
lmr1424f3e2010-06-17 13:57:09 +0000573 # Enable migration support for VM by adding extra_params.
574 if extra_params is not None:
575 if " -incoming tcp:0:%d" == extra_params:
576 self.migration_port = kvm_utils.find_free_port(5200, 6000)
577 qemu_command += extra_params % self.migration_port
578 elif " -incoming unix:%s" == extra_params:
579 self.migration_file = os.path.join("/tmp/", "unix-" +
580 time.strftime("%Y%m%d-%H%M%S"))
581 qemu_command += extra_params % self.migration_file
582 else:
583 qemu_command += extra_params
lmr6f669ce2009-05-31 19:02:42 +0000584
lmrdc2ac6a2009-06-10 19:15:49 +0000585 logging.debug("Running qemu command:\n%s", qemu_command)
lmra4967622009-07-23 01:36:32 +0000586 self.process = kvm_subprocess.run_bg(qemu_command, None,
587 logging.debug, "(qemu) ")
lmr6f669ce2009-05-31 19:02:42 +0000588
lmr9e964a02010-06-18 03:46:21 +0000589 # Make sure the process was started successfully
lmra4967622009-07-23 01:36:32 +0000590 if not self.process.is_alive():
591 logging.error("VM could not be created; "
592 "qemu command failed:\n%s" % qemu_command)
593 logging.error("Status: %s" % self.process.get_status())
594 logging.error("Output:" + kvm_utils.format_str_for_message(
595 self.process.get_output()))
lmrdc2ac6a2009-06-10 19:15:49 +0000596 self.destroy()
597 return False
lmr6f669ce2009-05-31 19:02:42 +0000598
lmr9e964a02010-06-18 03:46:21 +0000599 # Establish monitor connections
600 self.monitors = []
601 for monitor_name in kvm_utils.get_sub_dict_names(params,
602 "monitors"):
603 monitor_params = kvm_utils.get_sub_dict(params, monitor_name)
604 # Wait for monitor connection to succeed
605 end_time = time.time() + timeout
606 while time.time() < end_time:
607 try:
608 if monitor_params.get("monitor_type") == "qmp":
lmr449d2252010-06-18 03:48:23 +0000609 # Add a QMP monitor
610 monitor = kvm_monitor.QMPMonitor(
611 monitor_name,
612 self.get_monitor_filename(monitor_name))
lmr9e964a02010-06-18 03:46:21 +0000613 else:
614 # Add a "human" monitor
615 monitor = kvm_monitor.HumanMonitor(
616 monitor_name,
617 self.get_monitor_filename(monitor_name))
618 except kvm_monitor.MonitorError, e:
619 logging.warn(e)
620 else:
lmr449d2252010-06-18 03:48:23 +0000621 if monitor.is_responsive():
lmr9e964a02010-06-18 03:46:21 +0000622 break
623 time.sleep(1)
624 else:
625 logging.error("Could not connect to monitor '%s'" %
626 monitor_name)
627 self.destroy()
628 return False
629 # Add this monitor to the list
630 self.monitors += [monitor]
lmra4967622009-07-23 01:36:32 +0000631
lmrfe6515e2009-07-29 13:01:17 +0000632 # Get the output so far, to see if we have any problems with
633 # hugepage setup.
634 output = self.process.get_output()
635
636 if "alloc_mem_area" in output:
637 logging.error("Could not allocate hugepage memory; "
638 "qemu command:\n%s" % qemu_command)
639 logging.error("Output:" + kvm_utils.format_str_for_message(
640 self.process.get_output()))
lmr090cd7a2010-04-01 02:18:52 +0000641 self.destroy()
lmrfe6515e2009-07-29 13:01:17 +0000642 return False
643
lmr71fa4de2010-06-14 15:54:55 +0000644 logging.debug("VM appears to be alive with PID %s", self.get_pid())
lmraa380a22010-06-22 02:05:29 +0000645
646 # Establish a session with the serial console -- requires a version
647 # of netcat that supports -U
648 self.serial_console = kvm_subprocess.kvm_shell_session(
649 "nc -U %s" % self.get_serial_console_filename(),
650 auto_close=False,
651 output_func=kvm_utils.log_line,
652 output_params=("serial-%s.log" % name,))
653
lmrdc2ac6a2009-06-10 19:15:49 +0000654 return True
655
656 finally:
657 fcntl.lockf(lockfile, fcntl.LOCK_UN)
658 lockfile.close()
lmr6f669ce2009-05-31 19:02:42 +0000659
660
lmr6f669ce2009-05-31 19:02:42 +0000661 def destroy(self, gracefully=True):
662 """
663 Destroy the VM.
664
lmr912c74b2009-08-17 20:43:27 +0000665 If gracefully is True, first attempt to shutdown the VM with a shell
666 command. Then, attempt to destroy the VM via the monitor with a 'quit'
667 command. If that fails, send SIGKILL to the qemu process.
lmr6f669ce2009-05-31 19:02:42 +0000668
669 @param gracefully: Whether an attempt will be made to end the VM
lmr912c74b2009-08-17 20:43:27 +0000670 using a shell command before trying to end the qemu process
671 with a 'quit' or a kill signal.
lmr6f669ce2009-05-31 19:02:42 +0000672 """
lmrf320b042009-09-15 05:48:06 +0000673 try:
674 # Is it already dead?
675 if self.is_dead():
676 logging.debug("VM is already down")
677 return
lmr6f669ce2009-05-31 19:02:42 +0000678
lmr71fa4de2010-06-14 15:54:55 +0000679 logging.debug("Destroying VM with PID %s...", self.get_pid())
lmr6f669ce2009-05-31 19:02:42 +0000680
lmrf320b042009-09-15 05:48:06 +0000681 if gracefully and self.params.get("shutdown_command"):
682 # Try to destroy with shell command
683 logging.debug("Trying to shutdown VM with shell command...")
684 session = self.remote_login()
685 if session:
686 try:
687 # Send the shutdown command
688 session.sendline(self.params.get("shutdown_command"))
689 logging.debug("Shutdown command sent; waiting for VM "
690 "to go down...")
691 if kvm_utils.wait_for(self.is_dead, 60, 1, 1):
692 logging.debug("VM is down")
693 return
694 finally:
695 session.close()
lmr6f669ce2009-05-31 19:02:42 +0000696
lmr9e964a02010-06-18 03:46:21 +0000697 if self.monitor:
698 # Try to destroy with a monitor command
699 logging.debug("Trying to kill VM with monitor command...")
700 try:
701 self.monitor.quit()
702 except kvm_monitor.MonitorError, e:
703 logging.warn(e)
704 else:
705 # Wait for the VM to be really dead
706 if kvm_utils.wait_for(self.is_dead, 5, 0.5, 0.5):
707 logging.debug("VM is down")
708 return
lmrf320b042009-09-15 05:48:06 +0000709
710 # If the VM isn't dead yet...
711 logging.debug("Cannot quit normally; sending a kill to close the "
712 "deal...")
713 kvm_utils.kill_process_tree(self.process.get_pid(), 9)
lmr6f669ce2009-05-31 19:02:42 +0000714 # Wait for the VM to be really dead
715 if kvm_utils.wait_for(self.is_dead, 5, 0.5, 0.5):
716 logging.debug("VM is down")
lmr6f669ce2009-05-31 19:02:42 +0000717 return
718
lmrf320b042009-09-15 05:48:06 +0000719 logging.error("Process %s is a zombie!" % self.process.get_pid())
lmr6f669ce2009-05-31 19:02:42 +0000720
lmrf320b042009-09-15 05:48:06 +0000721 finally:
lmr9e964a02010-06-18 03:46:21 +0000722 self.monitors = []
lmr4513c432010-02-03 11:59:03 +0000723 if self.pci_assignable:
724 self.pci_assignable.release_devs()
lmrf320b042009-09-15 05:48:06 +0000725 if self.process:
726 self.process.close()
lmraa380a22010-06-22 02:05:29 +0000727 if self.serial_console:
728 self.serial_console.close()
lmr9e964a02010-06-18 03:46:21 +0000729 for f in ([self.get_testlog_filename()] +
730 self.get_monitor_filenames()):
731 try:
732 os.unlink(f)
733 except OSError:
734 pass
735
736
737 @property
738 def monitor(self):
739 """
740 Return the main monitor object, selected by the parameter main_monitor.
741 If main_monitor isn't defined, return the first monitor.
742 If no monitors exist, or if main_monitor refers to a nonexistent
743 monitor, return None.
744 """
745 for m in self.monitors:
746 if m.name == self.params.get("main_monitor"):
747 return m
748 if self.monitors and not self.params.get("main_monitor"):
749 return self.monitors[0]
lmr6f669ce2009-05-31 19:02:42 +0000750
751
752 def is_alive(self):
753 """
lmr9e964a02010-06-18 03:46:21 +0000754 Return True if the VM is alive and its monitor is responsive.
lmr6f669ce2009-05-31 19:02:42 +0000755 """
lmra4967622009-07-23 01:36:32 +0000756 # Check if the process is running
757 if self.is_dead():
lmr6f669ce2009-05-31 19:02:42 +0000758 return False
759 # Try sending a monitor command
lmr9e964a02010-06-18 03:46:21 +0000760 return bool(self.monitor) and self.monitor.is_responsive()
lmr6f669ce2009-05-31 19:02:42 +0000761
762
763 def is_dead(self):
764 """
lmra4967622009-07-23 01:36:32 +0000765 Return True if the qemu process is dead.
lmr6f669ce2009-05-31 19:02:42 +0000766 """
lmra4967622009-07-23 01:36:32 +0000767 return not self.process or not self.process.is_alive()
lmr6f669ce2009-05-31 19:02:42 +0000768
769
lmra4197002009-08-13 05:00:51 +0000770 def kill_tail_thread(self):
771 """
772 Stop the tailing thread which reports the output of qemu.
773 """
774 if self.process:
775 self.process.kill_tail_thread()
776
777
lmr6f669ce2009-05-31 19:02:42 +0000778 def get_params(self):
779 """
780 Return the VM's params dict. Most modified params take effect only
781 upon VM.create().
782 """
783 return self.params
784
785
lmr9e964a02010-06-18 03:46:21 +0000786 def get_monitor_filename(self, monitor_name):
787 """
788 Return the filename corresponding to a given monitor name.
789 """
790 return "/tmp/monitor-%s-%s" % (monitor_name, self.instance)
791
792
793 def get_monitor_filenames(self):
794 """
795 Return a list of all monitor filenames (as specified in the VM's
796 params).
797 """
798 return [self.get_monitor_filename(m) for m in
799 kvm_utils.get_sub_dict_names(self.params, "monitors")]
800
801
lmr2b06f332010-06-22 02:03:41 +0000802 def get_serial_console_filename(self):
803 """
804 Return the serial console filename.
805 """
806 return "/tmp/serial-%s" % self.instance
807
808
lmr9e964a02010-06-18 03:46:21 +0000809 def get_testlog_filename(self):
810 """
811 Return the testlog filename.
812 """
813 return "/tmp/testlog-%s" % self.instance
814
815
lmrf4696342009-08-13 04:06:33 +0000816 def get_address(self, index=0):
lmr6f669ce2009-05-31 19:02:42 +0000817 """
lmrf4696342009-08-13 04:06:33 +0000818 Return the address of a NIC of the guest, in host space.
lmr6f669ce2009-05-31 19:02:42 +0000819
lmrf4696342009-08-13 04:06:33 +0000820 If port redirection is used, return 'localhost' (the NIC has no IP
821 address of its own). Otherwise return the NIC's IP address.
822
823 @param index: Index of the NIC whose address is requested.
lmr6f669ce2009-05-31 19:02:42 +0000824 """
lmree90dd92009-08-13 04:13:39 +0000825 nics = kvm_utils.get_sub_dict_names(self.params, "nics")
826 nic_name = nics[index]
lmrf4696342009-08-13 04:06:33 +0000827 nic_params = kvm_utils.get_sub_dict(self.params, nic_name)
828 if nic_params.get("nic_mode") == "tap":
829 mac, ip = kvm_utils.get_mac_ip_pair_from_dict(nic_params)
lmree90dd92009-08-13 04:13:39 +0000830 if not mac:
831 logging.debug("MAC address unavailable")
832 return None
833 if not ip or nic_params.get("always_use_tcpdump") == "yes":
834 # Get the IP address from the cache
835 ip = self.address_cache.get(mac)
836 if not ip:
837 logging.debug("Could not find IP address for MAC address: "
838 "%s" % mac)
839 return None
840 # Make sure the IP address is assigned to this guest
841 nic_dicts = [kvm_utils.get_sub_dict(self.params, nic)
842 for nic in nics]
843 macs = [kvm_utils.get_mac_ip_pair_from_dict(dict)[0]
844 for dict in nic_dicts]
845 if not kvm_utils.verify_ip_address_ownership(ip, macs):
846 logging.debug("Could not verify MAC-IP address mapping: "
847 "%s ---> %s" % (mac, ip))
848 return None
lmrf4696342009-08-13 04:06:33 +0000849 return ip
850 else:
851 return "localhost"
lmr6f669ce2009-05-31 19:02:42 +0000852
853
lmree90dd92009-08-13 04:13:39 +0000854 def get_port(self, port, nic_index=0):
lmr6f669ce2009-05-31 19:02:42 +0000855 """
856 Return the port in host space corresponding to port in guest space.
857
858 @param port: Port number in host space.
lmree90dd92009-08-13 04:13:39 +0000859 @param nic_index: Index of the NIC.
lmr6f669ce2009-05-31 19:02:42 +0000860 @return: If port redirection is used, return the host port redirected
861 to guest port port. Otherwise return port.
862 """
lmree90dd92009-08-13 04:13:39 +0000863 nic_name = kvm_utils.get_sub_dict_names(self.params, "nics")[nic_index]
lmrf4696342009-08-13 04:06:33 +0000864 nic_params = kvm_utils.get_sub_dict(self.params, nic_name)
865 if nic_params.get("nic_mode") == "tap":
866 return port
lmr6f669ce2009-05-31 19:02:42 +0000867 else:
lmrf4696342009-08-13 04:06:33 +0000868 if not self.redirs.has_key(port):
869 logging.warn("Warning: guest port %s requested but not "
870 "redirected" % port)
871 return self.redirs.get(port)
lmr6f669ce2009-05-31 19:02:42 +0000872
873
lmra4967622009-07-23 01:36:32 +0000874 def get_pid(self):
875 """
lmr71fa4de2010-06-14 15:54:55 +0000876 Return the VM's PID. If the VM is dead return None.
877
878 @note: This works under the assumption that self.process.get_pid()
879 returns the PID of the parent shell process.
880 """
881 try:
882 children = commands.getoutput("ps --ppid=%d -o pid=" %
883 self.process.get_pid()).split()
884 return int(children[0])
885 except (TypeError, IndexError, ValueError):
886 return None
887
888
889 def get_shell_pid(self):
890 """
891 Return the PID of the parent shell process.
892
893 @note: This works under the assumption that self.process.get_pid()
894 returns the PID of the parent shell process.
lmra4967622009-07-23 01:36:32 +0000895 """
896 return self.process.get_pid()
897
898
lmr0bee2342010-02-24 00:01:37 +0000899 def get_shared_meminfo(self):
900 """
901 Returns the VM's shared memory information.
902
903 @return: Shared memory used by VM (MB)
904 """
905 if self.is_dead():
906 logging.error("Could not get shared memory info from dead VM.")
907 return None
908
lmr983ecdf2010-06-14 15:57:12 +0000909 filename = "/proc/%d/statm" % self.get_pid()
910 shm = int(open(filename).read().split()[2])
lmr0bee2342010-02-24 00:01:37 +0000911 # statm stores informations in pages, translate it to MB
lmr983ecdf2010-06-14 15:57:12 +0000912 return shm * 4.0 / 1024
lmr0bee2342010-02-24 00:01:37 +0000913
914
lmr912c74b2009-08-17 20:43:27 +0000915 def remote_login(self, nic_index=0, timeout=10):
lmr6f669ce2009-05-31 19:02:42 +0000916 """
lmr912c74b2009-08-17 20:43:27 +0000917 Log into the guest via SSH/Telnet/Netcat.
lmr6f669ce2009-05-31 19:02:42 +0000918 If timeout expires while waiting for output from the guest (e.g. a
919 password prompt or a shell prompt) -- fail.
920
lmree90dd92009-08-13 04:13:39 +0000921 @param nic_index: The index of the NIC to connect to.
lmr6f669ce2009-05-31 19:02:42 +0000922 @param timeout: Time (seconds) before giving up logging into the
923 guest.
924 @return: kvm_spawn object on success and None on failure.
925 """
926 username = self.params.get("username", "")
927 password = self.params.get("password", "")
lmr912c74b2009-08-17 20:43:27 +0000928 prompt = self.params.get("shell_prompt", "[\#\$]")
lmr59f9e2d2009-10-05 18:47:16 +0000929 linesep = eval("'%s'" % self.params.get("shell_linesep", r"\n"))
lmr912c74b2009-08-17 20:43:27 +0000930 client = self.params.get("shell_client")
lmree90dd92009-08-13 04:13:39 +0000931 address = self.get_address(nic_index)
lmr912c74b2009-08-17 20:43:27 +0000932 port = self.get_port(int(self.params.get("shell_port")))
lmre56903f2010-06-22 02:09:35 +0000933 log_filename = ("session-%s-%s.log" %
934 (self.name, kvm_utils.generate_random_string(4)))
lmr912c74b2009-08-17 20:43:27 +0000935
lmree90dd92009-08-13 04:13:39 +0000936 if not address or not port:
937 logging.debug("IP address or port unavailable")
lmr6f669ce2009-05-31 19:02:42 +0000938 return None
939
lmr158604f2010-06-22 01:57:34 +0000940 session = kvm_utils.remote_login(client, address, port, username,
lmre56903f2010-06-22 02:09:35 +0000941 password, prompt, linesep,
942 log_filename, timeout)
lmr912c74b2009-08-17 20:43:27 +0000943
lmr6f669ce2009-05-31 19:02:42 +0000944 if session:
lmr912c74b2009-08-17 20:43:27 +0000945 session.set_status_test_command(self.params.get("status_test_"
lmr6f669ce2009-05-31 19:02:42 +0000946 "command", ""))
947 return session
948
949
lmrc196d492010-05-07 14:14:26 +0000950 def copy_files_to(self, local_path, remote_path, nic_index=0, timeout=600):
lmr6f669ce2009-05-31 19:02:42 +0000951 """
lmr912c74b2009-08-17 20:43:27 +0000952 Transfer files to the guest.
lmr6f669ce2009-05-31 19:02:42 +0000953
954 @param local_path: Host path
955 @param remote_path: Guest path
lmr912c74b2009-08-17 20:43:27 +0000956 @param nic_index: The index of the NIC to connect to.
lmr6f669ce2009-05-31 19:02:42 +0000957 @param timeout: Time (seconds) before giving up on doing the remote
958 copy.
959 """
960 username = self.params.get("username", "")
961 password = self.params.get("password", "")
lmr912c74b2009-08-17 20:43:27 +0000962 client = self.params.get("file_transfer_client")
lmree90dd92009-08-13 04:13:39 +0000963 address = self.get_address(nic_index)
lmr912c74b2009-08-17 20:43:27 +0000964 port = self.get_port(int(self.params.get("file_transfer_port")))
lmre56903f2010-06-22 02:09:35 +0000965 log_filename = ("scp-%s-%s.log" %
966 (self.name, kvm_utils.generate_random_string(4)))
lmr912c74b2009-08-17 20:43:27 +0000967
lmree90dd92009-08-13 04:13:39 +0000968 if not address or not port:
969 logging.debug("IP address or port unavailable")
lmr6f669ce2009-05-31 19:02:42 +0000970 return None
lmr912c74b2009-08-17 20:43:27 +0000971
972 if client == "scp":
973 return kvm_utils.scp_to_remote(address, port, username, password,
lmre56903f2010-06-22 02:09:35 +0000974 local_path, remote_path,
975 log_filename, timeout)
lmr6f669ce2009-05-31 19:02:42 +0000976
977
lmrc196d492010-05-07 14:14:26 +0000978 def copy_files_from(self, remote_path, local_path, nic_index=0, timeout=600):
lmr6f669ce2009-05-31 19:02:42 +0000979 """
lmr912c74b2009-08-17 20:43:27 +0000980 Transfer files from the guest.
lmr6f669ce2009-05-31 19:02:42 +0000981
982 @param local_path: Guest path
983 @param remote_path: Host path
lmr912c74b2009-08-17 20:43:27 +0000984 @param nic_index: The index of the NIC to connect to.
lmr6f669ce2009-05-31 19:02:42 +0000985 @param timeout: Time (seconds) before giving up on doing the remote
986 copy.
987 """
988 username = self.params.get("username", "")
989 password = self.params.get("password", "")
lmr912c74b2009-08-17 20:43:27 +0000990 client = self.params.get("file_transfer_client")
lmree90dd92009-08-13 04:13:39 +0000991 address = self.get_address(nic_index)
lmr912c74b2009-08-17 20:43:27 +0000992 port = self.get_port(int(self.params.get("file_transfer_port")))
lmre56903f2010-06-22 02:09:35 +0000993 log_filename = ("scp-%s-%s.log" %
994 (self.name, kvm_utils.generate_random_string(4)))
lmr912c74b2009-08-17 20:43:27 +0000995
lmree90dd92009-08-13 04:13:39 +0000996 if not address or not port:
997 logging.debug("IP address or port unavailable")
lmr6f669ce2009-05-31 19:02:42 +0000998 return None
lmr6f669ce2009-05-31 19:02:42 +0000999
lmr912c74b2009-08-17 20:43:27 +00001000 if client == "scp":
1001 return kvm_utils.scp_from_remote(address, port, username, password,
lmre56903f2010-06-22 02:09:35 +00001002 remote_path, local_path,
1003 log_filename, timeout)
lmr6f669ce2009-05-31 19:02:42 +00001004
1005
lmraa380a22010-06-22 02:05:29 +00001006 def serial_login(self, timeout=10):
1007 """
1008 Log into the guest via the serial console.
1009 If timeout expires while waiting for output from the guest (e.g. a
1010 password prompt or a shell prompt) -- fail.
1011
1012 @param timeout: Time (seconds) before giving up logging into the guest.
1013 @return: kvm_spawn object on success and None on failure.
1014 """
1015 username = self.params.get("username", "")
1016 password = self.params.get("password", "")
1017 prompt = self.params.get("shell_prompt", "[\#\$]")
1018 linesep = eval("'%s'" % self.params.get("shell_linesep", r"\n"))
1019 status_test_command = self.params.get("status_test_command", "")
1020
1021 if self.serial_console:
1022 self.serial_console.set_linesep(linesep)
1023 self.serial_console.set_status_test_command(status_test_command)
1024 else:
1025 return None
1026
1027 # Make sure we get a login prompt
1028 self.serial_console.sendline()
1029
1030 if kvm_utils._remote_login(self.serial_console, username, password,
1031 prompt, timeout):
1032 return self.serial_console
1033
1034
lmr6f669ce2009-05-31 19:02:42 +00001035 def send_key(self, keystr):
1036 """
1037 Send a key event to the VM.
1038
1039 @param: keystr: A key event string (e.g. "ctrl-alt-delete")
1040 """
1041 # For compatibility with versions of QEMU that do not recognize all
1042 # key names: replace keyname with the hex value from the dict, which
1043 # QEMU will definitely accept
lmr9e964a02010-06-18 03:46:21 +00001044 dict = {"comma": "0x33",
1045 "dot": "0x34",
1046 "slash": "0x35"}
1047 for key, value in dict.items():
1048 keystr = keystr.replace(key, value)
1049 self.monitor.sendkey(keystr)
lmr6f669ce2009-05-31 19:02:42 +00001050 time.sleep(0.2)
1051
1052
1053 def send_string(self, str):
1054 """
1055 Send a string to the VM.
1056
1057 @param str: String, that must consist of alphanumeric characters only.
1058 Capital letters are allowed.
1059 """
1060 for char in str:
1061 if char.isupper():
1062 self.send_key("shift-%s" % char.lower())
1063 else:
1064 self.send_key(char)
lmra2533222009-07-20 12:43:46 +00001065
mbligh1ef218d2009-08-03 16:57:56 +00001066
lmra2533222009-07-20 12:43:46 +00001067 def get_uuid(self):
1068 """
1069 Catch UUID of the VM.
1070
1071 @return: None,if not specified in config file
1072 """
1073 if self.params.get("uuid") == "random":
1074 return self.uuid
1075 else:
1076 return self.params.get("uuid", None)
lmrdd2ff922009-12-01 23:39:12 +00001077
1078
1079 def get_cpu_count(self):
1080 """
1081 Get the cpu count of the VM.
1082 """
lmr13426552010-01-17 15:38:41 +00001083 session = self.remote_login()
1084 if not session:
1085 return None
lmrdd2ff922009-12-01 23:39:12 +00001086 try:
lmr13426552010-01-17 15:38:41 +00001087 cmd = self.params.get("cpu_chk_cmd")
1088 s, count = session.get_command_status_output(cmd)
1089 if s == 0:
1090 return int(count)
lmrdd2ff922009-12-01 23:39:12 +00001091 return None
1092 finally:
1093 session.close()
1094
1095
lmr28426c82010-04-16 06:02:58 +00001096 def get_memory_size(self, cmd=None):
lmrdd2ff922009-12-01 23:39:12 +00001097 """
lmr28426c82010-04-16 06:02:58 +00001098 Get bootup memory size of the VM.
1099
1100 @param check_cmd: Command used to check memory. If not provided,
1101 self.params.get("mem_chk_cmd") will be used.
lmrdd2ff922009-12-01 23:39:12 +00001102 """
lmr13426552010-01-17 15:38:41 +00001103 session = self.remote_login()
1104 if not session:
lmrdd2ff922009-12-01 23:39:12 +00001105 return None
lmr13426552010-01-17 15:38:41 +00001106 try:
lmr28426c82010-04-16 06:02:58 +00001107 if not cmd:
1108 cmd = self.params.get("mem_chk_cmd")
lmr13426552010-01-17 15:38:41 +00001109 s, mem_str = session.get_command_status_output(cmd)
1110 if s != 0:
1111 return None
lmr6d69f4d2010-02-12 11:35:55 +00001112 mem = re.findall("([0-9]+)", mem_str)
lmr13426552010-01-17 15:38:41 +00001113 mem_size = 0
1114 for m in mem:
1115 mem_size += int(m)
1116 if "GB" in mem_str:
1117 mem_size *= 1024
1118 elif "MB" in mem_str:
1119 pass
1120 else:
1121 mem_size /= 1024
1122 return int(mem_size)
lmrdd2ff922009-12-01 23:39:12 +00001123 finally:
1124 session.close()
lmr28426c82010-04-16 06:02:58 +00001125
1126
1127 def get_current_memory_size(self):
1128 """
1129 Get current memory size of the VM, rather than bootup memory.
1130 """
1131 cmd = self.params.get("mem_chk_cur_cmd")
1132 return self.get_memory_size(cmd)