blob: 1edecb990285cc0745c03c4f982432df99fbdef8 [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
lmr953ffba2009-07-27 13:20:10 +0000109 self.redirs = {}
110 self.vnc_port = 5900
lmra2533222009-07-20 12:43:46 +0000111 self.uuid = None
lmr9e964a02010-06-18 03:46:21 +0000112 self.monitors = []
113 self.pci_assignable = None
lmr6f669ce2009-05-31 19:02:42 +0000114
115 self.name = name
116 self.params = params
lmr90b9fd52009-08-17 20:48:18 +0000117 self.root_dir = root_dir
lmree90dd92009-08-13 04:13:39 +0000118 self.address_cache = address_cache
lmrb1cad1e2010-06-17 17:36:09 +0000119 self.netdev_id = []
120 for nic in params.get("nics").split():
121 self.netdev_id.append(kvm_utils.generate_random_string(4))
lmr6f669ce2009-05-31 19:02:42 +0000122
lmr9e964a02010-06-18 03:46:21 +0000123 # Find a unique identifier for this VM
lmr8b134f92009-06-08 14:47:31 +0000124 while True:
lmrd16a67d2009-06-10 19:52:59 +0000125 self.instance = (time.strftime("%Y%m%d-%H%M%S-") +
126 kvm_utils.generate_random_string(4))
lmr9e964a02010-06-18 03:46:21 +0000127 if not glob.glob("/tmp/*%s" % self.instance):
lmr8b134f92009-06-08 14:47:31 +0000128 break
129
130
lmr52800ba2009-08-17 20:49:58 +0000131 def clone(self, name=None, params=None, root_dir=None, address_cache=None):
lmr2c241172009-06-08 15:11:29 +0000132 """
133 Return a clone of the VM object with optionally modified parameters.
134 The clone is initially not alive and needs to be started using create().
135 Any parameters not passed to this function are copied from the source
136 VM.
137
138 @param name: Optional new VM name
139 @param params: Optional new VM creation parameters
lmr90b9fd52009-08-17 20:48:18 +0000140 @param root_dir: Optional new base directory for relative filenames
lmree90dd92009-08-13 04:13:39 +0000141 @param address_cache: A dict that maps MAC addresses to IP addresses
lmr2c241172009-06-08 15:11:29 +0000142 """
lmre45a1f22009-11-10 16:35:08 +0000143 if name is None:
lmr2c241172009-06-08 15:11:29 +0000144 name = self.name
lmre45a1f22009-11-10 16:35:08 +0000145 if params is None:
lmr2c241172009-06-08 15:11:29 +0000146 params = self.params.copy()
lmre45a1f22009-11-10 16:35:08 +0000147 if root_dir is None:
lmr90b9fd52009-08-17 20:48:18 +0000148 root_dir = self.root_dir
lmre45a1f22009-11-10 16:35:08 +0000149 if address_cache is None:
lmree90dd92009-08-13 04:13:39 +0000150 address_cache = self.address_cache
lmr52800ba2009-08-17 20:49:58 +0000151 return VM(name, params, root_dir, address_cache)
lmr2c241172009-06-08 15:11:29 +0000152
153
lmr52800ba2009-08-17 20:49:58 +0000154 def make_qemu_command(self, name=None, params=None, root_dir=None):
lmr6f669ce2009-05-31 19:02:42 +0000155 """
156 Generate a qemu command line. All parameters are optional. If a
157 parameter is not supplied, the corresponding value stored in the
158 class attributes is used.
159
lmr6f669ce2009-05-31 19:02:42 +0000160 @param name: The name of the object
161 @param params: A dict containing VM params
lmr90b9fd52009-08-17 20:48:18 +0000162 @param root_dir: Base directory for relative filenames
lmr6f669ce2009-05-31 19:02:42 +0000163
164 @note: The params dict should contain:
165 mem -- memory size in MBs
166 cdrom -- ISO filename to use with the qemu -cdrom parameter
lmr6f669ce2009-05-31 19:02:42 +0000167 extra_params -- a string to append to the qemu command
lmr912c74b2009-08-17 20:43:27 +0000168 shell_port -- port of the remote shell daemon on the guest
169 (SSH, Telnet or the home-made Remote Shell Server)
170 shell_client -- client program to use for connecting to the
171 remote shell daemon on the guest (ssh, telnet or nc)
lmreeff0eb2009-06-10 19:19:15 +0000172 x11_display -- if specified, the DISPLAY environment variable
173 will be be set to this value for the qemu process (useful for
174 SDL rendering)
lmr6f669ce2009-05-31 19:02:42 +0000175 images -- a list of image object names, separated by spaces
176 nics -- a list of NIC object names, separated by spaces
177
178 For each image in images:
179 drive_format -- string to pass as 'if' parameter for this
180 image (e.g. ide, scsi)
181 image_snapshot -- if yes, pass 'snapshot=on' to qemu for
182 this image
183 image_boot -- if yes, pass 'boot=on' to qemu for this image
184 In addition, all parameters required by get_image_filename.
185
186 For each NIC in nics:
187 nic_model -- string to pass as 'model' parameter for this
188 NIC (e.g. e1000)
189 """
lmr48abd7d2010-05-26 13:48:04 +0000190 # Helper function for command line option wrappers
191 def has_option(help, option):
192 return bool(re.search(r"^-%s(\s|$)" % option, help, re.MULTILINE))
193
194 # Wrappers for all supported qemu command line parameters.
195 # This is meant to allow support for multiple qemu versions.
196 # Each of these functions receives the output of 'qemu -help' as a
197 # parameter, and should add the requested command line option
198 # accordingly.
199
200 def add_name(help, name):
201 return " -name '%s'" % name
202
lmr9e964a02010-06-18 03:46:21 +0000203 def add_human_monitor(help, filename):
lmr09a78162010-06-14 16:29:23 +0000204 return " -monitor unix:'%s',server,nowait" % filename
lmr48abd7d2010-05-26 13:48:04 +0000205
lmr9e964a02010-06-18 03:46:21 +0000206 def add_qmp_monitor(help, filename):
207 return " -qmp unix:'%s',server,nowait" % filename
208
lmr2b06f332010-06-22 02:03:41 +0000209 def add_serial(help, filename):
210 return " -serial unix:'%s',server,nowait" % filename
211
lmr48abd7d2010-05-26 13:48:04 +0000212 def add_mem(help, mem):
213 return " -m %s" % mem
214
215 def add_smp(help, smp):
216 return " -smp %s" % smp
217
218 def add_cdrom(help, filename, index=2):
219 if has_option(help, "drive"):
lmr09a78162010-06-14 16:29:23 +0000220 return " -drive file='%s',index=%d,media=cdrom" % (filename,
221 index)
lmr48abd7d2010-05-26 13:48:04 +0000222 else:
lmr09a78162010-06-14 16:29:23 +0000223 return " -cdrom '%s'" % filename
lmr48abd7d2010-05-26 13:48:04 +0000224
225 def add_drive(help, filename, format=None, cache=None, werror=None,
226 serial=None, snapshot=False, boot=False):
lmr09a78162010-06-14 16:29:23 +0000227 cmd = " -drive file='%s'" % filename
lmr48abd7d2010-05-26 13:48:04 +0000228 if format: cmd += ",if=%s" % format
229 if cache: cmd += ",cache=%s" % cache
230 if werror: cmd += ",werror=%s" % werror
lmr09a78162010-06-14 16:29:23 +0000231 if serial: cmd += ",serial='%s'" % serial
lmr48abd7d2010-05-26 13:48:04 +0000232 if snapshot: cmd += ",snapshot=on"
233 if boot: cmd += ",boot=on"
234 return cmd
235
lmrb1cad1e2010-06-17 17:36:09 +0000236 def add_nic(help, vlan, model=None, mac=None, netdev_id=None):
lmr48abd7d2010-05-26 13:48:04 +0000237 cmd = " -net nic,vlan=%d" % vlan
lmrb1cad1e2010-06-17 17:36:09 +0000238 if has_option(help, "netdev"):
239 cmd +=",netdev=%s" % netdev_id
lmr48abd7d2010-05-26 13:48:04 +0000240 if model: cmd += ",model=%s" % model
lmr09a78162010-06-14 16:29:23 +0000241 if mac: cmd += ",macaddr='%s'" % mac
lmr48abd7d2010-05-26 13:48:04 +0000242 return cmd
243
244 def add_net(help, vlan, mode, ifname=None, script=None,
lmrb1cad1e2010-06-17 17:36:09 +0000245 downscript=None, netdev_id=None):
246 if has_option(help, "netdev"):
247 cmd = " -netdev %s,id=%s" % (mode, netdev_id)
248 else:
249 cmd = " -net %s,vlan=%d" % (mode, vlan)
lmr48abd7d2010-05-26 13:48:04 +0000250 if mode == "tap":
lmr09a78162010-06-14 16:29:23 +0000251 if ifname: cmd += ",ifname='%s'" % ifname
252 if script: cmd += ",script='%s'" % script
253 cmd += ",downscript='%s'" % (downscript or "no")
lmr48abd7d2010-05-26 13:48:04 +0000254 return cmd
255
256 def add_floppy(help, filename):
lmr09a78162010-06-14 16:29:23 +0000257 return " -fda '%s'" % filename
lmr48abd7d2010-05-26 13:48:04 +0000258
259 def add_tftp(help, filename):
lmr09a78162010-06-14 16:29:23 +0000260 return " -tftp '%s'" % filename
lmr48abd7d2010-05-26 13:48:04 +0000261
262 def add_tcp_redir(help, host_port, guest_port):
263 return " -redir tcp:%s::%s" % (host_port, guest_port)
264
265 def add_vnc(help, vnc_port):
266 return " -vnc :%d" % (vnc_port - 5900)
267
268 def add_sdl(help):
269 if has_option(help, "sdl"):
270 return " -sdl"
271 else:
272 return ""
273
274 def add_nographic(help):
275 return " -nographic"
276
277 def add_uuid(help, uuid):
lmr09a78162010-06-14 16:29:23 +0000278 return " -uuid '%s'" % uuid
lmr48abd7d2010-05-26 13:48:04 +0000279
280 def add_pcidevice(help, host):
lmr09a78162010-06-14 16:29:23 +0000281 return " -pcidevice host='%s'" % host
lmr48abd7d2010-05-26 13:48:04 +0000282
lmr41cb8fc2010-06-10 15:30:45 +0000283 def add_kernel(help, filename):
lmr09a78162010-06-14 16:29:23 +0000284 return " -kernel '%s'" % filename
lmr41cb8fc2010-06-10 15:30:45 +0000285
286 def add_initrd(help, filename):
lmr09a78162010-06-14 16:29:23 +0000287 return " -initrd '%s'" % filename
lmr41cb8fc2010-06-10 15:30:45 +0000288
lmr48abd7d2010-05-26 13:48:04 +0000289 # End of command line option wrappers
290
291 if name is None: name = self.name
292 if params is None: params = self.params
293 if root_dir is None: root_dir = self.root_dir
294
295 qemu_binary = kvm_utils.get_path(root_dir, params.get("qemu_binary",
296 "qemu"))
297 # Get the output of 'qemu -help' (log a message in case this call never
298 # returns or causes some other kind of trouble)
299 logging.debug("Getting output of 'qemu -help'")
300 help = commands.getoutput("%s -help" % qemu_binary)
lmr6f669ce2009-05-31 19:02:42 +0000301
lmreeff0eb2009-06-10 19:19:15 +0000302 # Start constructing the qemu command
303 qemu_cmd = ""
304 # Set the X11 display parameter if requested
305 if params.get("x11_display"):
306 qemu_cmd += "DISPLAY=%s " % params.get("x11_display")
307 # Add the qemu binary
lmr48abd7d2010-05-26 13:48:04 +0000308 qemu_cmd += qemu_binary
lmreeff0eb2009-06-10 19:19:15 +0000309 # Add the VM's name
lmr48abd7d2010-05-26 13:48:04 +0000310 qemu_cmd += add_name(help, name)
lmr9e964a02010-06-18 03:46:21 +0000311 # Add monitors
312 for monitor_name in kvm_utils.get_sub_dict_names(params, "monitors"):
313 monitor_params = kvm_utils.get_sub_dict(params, monitor_name)
314 monitor_filename = self.get_monitor_filename(monitor_name)
315 if monitor_params.get("monitor_type") == "qmp":
316 qemu_cmd += add_qmp_monitor(help, monitor_filename)
317 else:
318 qemu_cmd += add_human_monitor(help, monitor_filename)
lmr6f669ce2009-05-31 19:02:42 +0000319
lmr2b06f332010-06-22 02:03:41 +0000320 # Add serial console redirection
321 qemu_cmd += add_serial(help, self.get_serial_console_filename())
322
lmr6f669ce2009-05-31 19:02:42 +0000323 for image_name in kvm_utils.get_sub_dict_names(params, "images"):
324 image_params = kvm_utils.get_sub_dict(params, image_name)
lmr9d75ee32009-09-29 13:14:13 +0000325 if image_params.get("boot_drive") == "no":
326 continue
lmr48abd7d2010-05-26 13:48:04 +0000327 qemu_cmd += add_drive(help,
328 get_image_filename(image_params, root_dir),
329 image_params.get("drive_format"),
330 image_params.get("drive_cache"),
331 image_params.get("drive_werror"),
332 image_params.get("drive_serial"),
333 image_params.get("image_snapshot") == "yes",
334 image_params.get("image_boot") == "yes")
lmr6f669ce2009-05-31 19:02:42 +0000335
336 vlan = 0
337 for nic_name in kvm_utils.get_sub_dict_names(params, "nics"):
338 nic_params = kvm_utils.get_sub_dict(params, nic_name)
lmrf4696342009-08-13 04:06:33 +0000339 # Handle the '-net nic' part
lmr48abd7d2010-05-26 13:48:04 +0000340 mac = None
341 if "address_index" in nic_params:
342 mac = kvm_utils.get_mac_ip_pair_from_dict(nic_params)[0]
lmrb1cad1e2010-06-17 17:36:09 +0000343 qemu_cmd += add_nic(help, vlan, nic_params.get("nic_model"), mac,
344 self.netdev_id[vlan])
lmrf4696342009-08-13 04:06:33 +0000345 # Handle the '-net tap' or '-net user' part
lmre4eaa862010-06-01 19:15:14 +0000346 script = nic_params.get("nic_script")
347 downscript = nic_params.get("nic_downscript")
lmr48abd7d2010-05-26 13:48:04 +0000348 if script:
349 script = kvm_utils.get_path(root_dir, script)
350 if downscript:
351 downscript = kvm_utils.get_path(root_dir, downscript)
352 qemu_cmd += add_net(help, vlan, nic_params.get("nic_mode", "user"),
353 nic_params.get("nic_ifname"),
lmrb1cad1e2010-06-17 17:36:09 +0000354 script, downscript, self.netdev_id[vlan])
lmrf4696342009-08-13 04:06:33 +0000355 # Proceed to next NIC
lmr6f669ce2009-05-31 19:02:42 +0000356 vlan += 1
357
358 mem = params.get("mem")
359 if mem:
lmr48abd7d2010-05-26 13:48:04 +0000360 qemu_cmd += add_mem(help, mem)
lmr6f669ce2009-05-31 19:02:42 +0000361
lmrc43bf372009-11-10 13:19:00 +0000362 smp = params.get("smp")
363 if smp:
lmrdb3fe612010-06-14 16:19:28 +0000364 qemu_cmd += add_smp(help, smp)
lmrc43bf372009-11-10 13:19:00 +0000365
lmr6f669ce2009-05-31 19:02:42 +0000366 iso = params.get("cdrom")
367 if iso:
lmr90b9fd52009-08-17 20:48:18 +0000368 iso = kvm_utils.get_path(root_dir, iso)
lmr48abd7d2010-05-26 13:48:04 +0000369 qemu_cmd += add_cdrom(help, iso)
lmr89fd6412010-01-18 02:42:57 +0000370
371 # Even though this is not a really scalable approach,
372 # it doesn't seem like we are going to need more than
373 # 2 CDs active on the same VM.
374 iso_extra = params.get("cdrom_extra")
375 if iso_extra:
376 iso_extra = kvm_utils.get_path(root_dir, iso_extra)
lmr48abd7d2010-05-26 13:48:04 +0000377 qemu_cmd += add_cdrom(help, iso_extra, 3)
lmr6f669ce2009-05-31 19:02:42 +0000378
lmrb0a9b762009-10-09 20:43:30 +0000379 # We may want to add {floppy_otps} parameter for -fda
lmr48abd7d2010-05-26 13:48:04 +0000380 # {fat:floppy:}/path/. However vvfat is not usually recommended.
lmrb0a9b762009-10-09 20:43:30 +0000381 floppy = params.get("floppy")
382 if floppy:
lmrf69f6b12009-11-10 16:33:44 +0000383 floppy = kvm_utils.get_path(root_dir, floppy)
lmr48abd7d2010-05-26 13:48:04 +0000384 qemu_cmd += add_floppy(help, floppy)
lmrb0a9b762009-10-09 20:43:30 +0000385
386 tftp = params.get("tftp")
387 if tftp:
lmrf69f6b12009-11-10 16:33:44 +0000388 tftp = kvm_utils.get_path(root_dir, tftp)
lmr48abd7d2010-05-26 13:48:04 +0000389 qemu_cmd += add_tftp(help, tftp)
lmr6f669ce2009-05-31 19:02:42 +0000390
lmr41cb8fc2010-06-10 15:30:45 +0000391 kernel = params.get("kernel")
392 if kernel:
393 kernel = kvm_utils.get_path(root_dir, kernel)
394 qemu_cmd += add_kernel(help, kernel)
395
396 initrd = params.get("initrd")
397 if initrd:
398 initrd = kvm_utils.get_path(root_dir, initrd)
399 qemu_cmd += add_initrd(help, initrd)
400
lmr6f669ce2009-05-31 19:02:42 +0000401 for redir_name in kvm_utils.get_sub_dict_names(params, "redirs"):
402 redir_params = kvm_utils.get_sub_dict(params, redir_name)
403 guest_port = int(redir_params.get("guest_port"))
lmrf4696342009-08-13 04:06:33 +0000404 host_port = self.redirs.get(guest_port)
lmr48abd7d2010-05-26 13:48:04 +0000405 qemu_cmd += add_tcp_redir(help, host_port, guest_port)
lmr6f669ce2009-05-31 19:02:42 +0000406
407 if params.get("display") == "vnc":
lmr48abd7d2010-05-26 13:48:04 +0000408 qemu_cmd += add_vnc(help, self.vnc_port)
lmr6f669ce2009-05-31 19:02:42 +0000409 elif params.get("display") == "sdl":
lmr48abd7d2010-05-26 13:48:04 +0000410 qemu_cmd += add_sdl(help)
lmr6f669ce2009-05-31 19:02:42 +0000411 elif params.get("display") == "nographic":
lmr48abd7d2010-05-26 13:48:04 +0000412 qemu_cmd += add_nographic(help)
lmr6f669ce2009-05-31 19:02:42 +0000413
lmra2533222009-07-20 12:43:46 +0000414 if params.get("uuid") == "random":
lmr48abd7d2010-05-26 13:48:04 +0000415 qemu_cmd += add_uuid(help, self.uuid)
lmra2533222009-07-20 12:43:46 +0000416 elif params.get("uuid"):
lmr48abd7d2010-05-26 13:48:04 +0000417 qemu_cmd += add_uuid(help, params.get("uuid"))
lmra2533222009-07-20 12:43:46 +0000418
lmr31af3a12010-01-18 16:46:52 +0000419 # If the PCI assignment step went OK, add each one of the PCI assigned
420 # devices to the qemu command line.
421 if self.pci_assignable:
422 for pci_id in self.pa_pci_ids:
lmr48abd7d2010-05-26 13:48:04 +0000423 qemu_cmd += add_pcidevice(help, pci_id)
424
425 extra_params = params.get("extra_params")
426 if extra_params:
427 qemu_cmd += " %s" % extra_params
lmr31af3a12010-01-18 16:46:52 +0000428
lmr6f669ce2009-05-31 19:02:42 +0000429 return qemu_cmd
430
431
lmr52800ba2009-08-17 20:49:58 +0000432 def create(self, name=None, params=None, root_dir=None,
lmr1424f3e2010-06-17 13:57:09 +0000433 for_migration=False, timeout=5.0, extra_params=None):
lmr6f669ce2009-05-31 19:02:42 +0000434 """
435 Start the VM by running a qemu command.
436 All parameters are optional. The following applies to all parameters
437 but for_migration: If a parameter is not supplied, the corresponding
438 value stored in the class attributes is used, and if it is supplied,
439 it is stored for later use.
440
441 @param name: The name of the object
442 @param params: A dict containing VM params
lmr90b9fd52009-08-17 20:48:18 +0000443 @param root_dir: Base directory for relative filenames
lmr6f669ce2009-05-31 19:02:42 +0000444 @param for_migration: If True, start the VM with the -incoming
445 option
lmr1424f3e2010-06-17 13:57:09 +0000446 @param extra_params: extra params for qemu command.e.g -incoming option
447 Please use this parameter instead of for_migration.
lmr6f669ce2009-05-31 19:02:42 +0000448 """
lmr135b5e62009-06-10 19:22:31 +0000449 self.destroy()
450
lmre45a1f22009-11-10 16:35:08 +0000451 if name is not None:
lmr6f669ce2009-05-31 19:02:42 +0000452 self.name = name
lmre45a1f22009-11-10 16:35:08 +0000453 if params is not None:
lmr6f669ce2009-05-31 19:02:42 +0000454 self.params = params
lmre45a1f22009-11-10 16:35:08 +0000455 if root_dir is not None:
lmr90b9fd52009-08-17 20:48:18 +0000456 self.root_dir = root_dir
lmr6f669ce2009-05-31 19:02:42 +0000457 name = self.name
458 params = self.params
lmr90b9fd52009-08-17 20:48:18 +0000459 root_dir = self.root_dir
lmr6f669ce2009-05-31 19:02:42 +0000460
461 # Verify the md5sum of the ISO image
462 iso = params.get("cdrom")
463 if iso:
lmr90b9fd52009-08-17 20:48:18 +0000464 iso = kvm_utils.get_path(root_dir, iso)
lmr6f669ce2009-05-31 19:02:42 +0000465 if not os.path.exists(iso):
466 logging.error("ISO file not found: %s" % iso)
467 return False
468 compare = False
469 if params.get("md5sum_1m"):
lmrf4696342009-08-13 04:06:33 +0000470 logging.debug("Comparing expected MD5 sum with MD5 sum of "
471 "first MB of ISO file...")
lmrd60882f2010-02-04 03:26:36 +0000472 actual_hash = utils.hash_file(iso, 1048576, method="md5")
lmr03ba22e2009-10-23 12:07:44 +0000473 expected_hash = params.get("md5sum_1m")
lmr6f669ce2009-05-31 19:02:42 +0000474 compare = True
475 elif params.get("md5sum"):
lmrf4696342009-08-13 04:06:33 +0000476 logging.debug("Comparing expected MD5 sum with MD5 sum of ISO "
477 "file...")
lmrd60882f2010-02-04 03:26:36 +0000478 actual_hash = utils.hash_file(iso, method="md5")
lmr03ba22e2009-10-23 12:07:44 +0000479 expected_hash = params.get("md5sum")
480 compare = True
481 elif params.get("sha1sum"):
482 logging.debug("Comparing expected SHA1 sum with SHA1 sum of "
483 "ISO file...")
lmrd60882f2010-02-04 03:26:36 +0000484 actual_hash = utils.hash_file(iso, method="sha1")
lmrea1266e2009-11-10 16:41:08 +0000485 expected_hash = params.get("sha1sum")
lmr6f669ce2009-05-31 19:02:42 +0000486 compare = True
487 if compare:
lmr03ba22e2009-10-23 12:07:44 +0000488 if actual_hash == expected_hash:
489 logging.debug("Hashes match")
lmr6f669ce2009-05-31 19:02:42 +0000490 else:
lmr03ba22e2009-10-23 12:07:44 +0000491 logging.error("Actual hash differs from expected one")
lmr6f669ce2009-05-31 19:02:42 +0000492 return False
493
lmrdc2ac6a2009-06-10 19:15:49 +0000494 # Make sure the following code is not executed by more than one thread
495 # at the same time
496 lockfile = open("/tmp/kvm-autotest-vm-create.lock", "w+")
497 fcntl.lockf(lockfile, fcntl.LOCK_EX)
lmr6f669ce2009-05-31 19:02:42 +0000498
lmrdc2ac6a2009-06-10 19:15:49 +0000499 try:
500 # Handle port redirections
501 redir_names = kvm_utils.get_sub_dict_names(params, "redirs")
502 host_ports = kvm_utils.find_free_ports(5000, 6000, len(redir_names))
503 self.redirs = {}
504 for i in range(len(redir_names)):
505 redir_params = kvm_utils.get_sub_dict(params, redir_names[i])
506 guest_port = int(redir_params.get("guest_port"))
507 self.redirs[guest_port] = host_ports[i]
lmr6f669ce2009-05-31 19:02:42 +0000508
lmrdc2ac6a2009-06-10 19:15:49 +0000509 # Find available VNC port, if needed
510 if params.get("display") == "vnc":
lmrc0da8902010-05-17 20:31:36 +0000511 self.vnc_port = kvm_utils.find_free_port(5900, 6100)
lmr6f669ce2009-05-31 19:02:42 +0000512
lmra2533222009-07-20 12:43:46 +0000513 # Find random UUID if specified 'uuid = random' in config file
514 if params.get("uuid") == "random":
515 f = open("/proc/sys/kernel/random/uuid")
516 self.uuid = f.read().strip()
517 f.close()
518
lmr31ed61d2010-06-07 13:21:38 +0000519 # Assign a PCI assignable device
520 self.pci_assignable = None
521 pa_type = params.get("pci_assignable")
522 if pa_type in ["vf", "pf", "mixed"]:
lmr31af3a12010-01-18 16:46:52 +0000523 pa_devices_requested = params.get("devices_requested")
524
525 # Virtual Functions (VF) assignable devices
526 if pa_type == "vf":
lmr31ed61d2010-06-07 13:21:38 +0000527 self.pci_assignable = kvm_utils.PciAssignable(
528 type=pa_type,
529 driver=params.get("driver"),
530 driver_option=params.get("driver_option"),
531 devices_requested=pa_devices_requested)
lmr31af3a12010-01-18 16:46:52 +0000532 # Physical NIC (PF) assignable devices
533 elif pa_type == "pf":
lmr31ed61d2010-06-07 13:21:38 +0000534 self.pci_assignable = kvm_utils.PciAssignable(
535 type=pa_type,
536 names=params.get("device_names"),
537 devices_requested=pa_devices_requested)
lmr31af3a12010-01-18 16:46:52 +0000538 # Working with both VF and PF
539 elif pa_type == "mixed":
lmr31ed61d2010-06-07 13:21:38 +0000540 self.pci_assignable = kvm_utils.PciAssignable(
541 type=pa_type,
542 driver=params.get("driver"),
543 driver_option=params.get("driver_option"),
544 names=params.get("device_names"),
545 devices_requested=pa_devices_requested)
lmr31af3a12010-01-18 16:46:52 +0000546
547 self.pa_pci_ids = self.pci_assignable.request_devs()
548
549 if self.pa_pci_ids:
lmr31ed61d2010-06-07 13:21:38 +0000550 logging.debug("Successfuly assigned devices: %s",
lmr31af3a12010-01-18 16:46:52 +0000551 self.pa_pci_ids)
552 else:
553 logging.error("No PCI assignable devices were assigned "
554 "and 'pci_assignable' is defined to %s "
lmr31ed61d2010-06-07 13:21:38 +0000555 "on your config file. Aborting VM creation.",
lmr31af3a12010-01-18 16:46:52 +0000556 pa_type)
557 return False
558
lmr856d58c2010-06-08 18:29:31 +0000559 elif pa_type and pa_type != "no":
lmr31ed61d2010-06-07 13:21:38 +0000560 logging.warn("Unsupported pci_assignable type: %s", pa_type)
lmr31af3a12010-01-18 16:46:52 +0000561
lmrdc2ac6a2009-06-10 19:15:49 +0000562 # Make qemu command
563 qemu_command = self.make_qemu_command()
lmr6f669ce2009-05-31 19:02:42 +0000564
lmr1424f3e2010-06-17 13:57:09 +0000565 # Enable migration support for VM by adding extra_params.
566 if extra_params is not None:
567 if " -incoming tcp:0:%d" == extra_params:
568 self.migration_port = kvm_utils.find_free_port(5200, 6000)
569 qemu_command += extra_params % self.migration_port
570 elif " -incoming unix:%s" == extra_params:
571 self.migration_file = os.path.join("/tmp/", "unix-" +
572 time.strftime("%Y%m%d-%H%M%S"))
573 qemu_command += extra_params % self.migration_file
574 else:
575 qemu_command += extra_params
lmr6f669ce2009-05-31 19:02:42 +0000576
lmrdc2ac6a2009-06-10 19:15:49 +0000577 logging.debug("Running qemu command:\n%s", qemu_command)
lmra4967622009-07-23 01:36:32 +0000578 self.process = kvm_subprocess.run_bg(qemu_command, None,
579 logging.debug, "(qemu) ")
lmr6f669ce2009-05-31 19:02:42 +0000580
lmr9e964a02010-06-18 03:46:21 +0000581 # Make sure the process was started successfully
lmra4967622009-07-23 01:36:32 +0000582 if not self.process.is_alive():
583 logging.error("VM could not be created; "
584 "qemu command failed:\n%s" % qemu_command)
585 logging.error("Status: %s" % self.process.get_status())
586 logging.error("Output:" + kvm_utils.format_str_for_message(
587 self.process.get_output()))
lmrdc2ac6a2009-06-10 19:15:49 +0000588 self.destroy()
589 return False
lmr6f669ce2009-05-31 19:02:42 +0000590
lmr9e964a02010-06-18 03:46:21 +0000591 # Establish monitor connections
592 self.monitors = []
593 for monitor_name in kvm_utils.get_sub_dict_names(params,
594 "monitors"):
595 monitor_params = kvm_utils.get_sub_dict(params, monitor_name)
596 # Wait for monitor connection to succeed
597 end_time = time.time() + timeout
598 while time.time() < end_time:
599 try:
600 if monitor_params.get("monitor_type") == "qmp":
lmr449d2252010-06-18 03:48:23 +0000601 # Add a QMP monitor
602 monitor = kvm_monitor.QMPMonitor(
603 monitor_name,
604 self.get_monitor_filename(monitor_name))
lmr9e964a02010-06-18 03:46:21 +0000605 else:
606 # Add a "human" monitor
607 monitor = kvm_monitor.HumanMonitor(
608 monitor_name,
609 self.get_monitor_filename(monitor_name))
610 except kvm_monitor.MonitorError, e:
611 logging.warn(e)
612 else:
lmr449d2252010-06-18 03:48:23 +0000613 if monitor.is_responsive():
lmr9e964a02010-06-18 03:46:21 +0000614 break
615 time.sleep(1)
616 else:
617 logging.error("Could not connect to monitor '%s'" %
618 monitor_name)
619 self.destroy()
620 return False
621 # Add this monitor to the list
622 self.monitors += [monitor]
lmra4967622009-07-23 01:36:32 +0000623
lmrfe6515e2009-07-29 13:01:17 +0000624 # Get the output so far, to see if we have any problems with
625 # hugepage setup.
626 output = self.process.get_output()
627
628 if "alloc_mem_area" in output:
629 logging.error("Could not allocate hugepage memory; "
630 "qemu command:\n%s" % qemu_command)
631 logging.error("Output:" + kvm_utils.format_str_for_message(
632 self.process.get_output()))
lmr090cd7a2010-04-01 02:18:52 +0000633 self.destroy()
lmrfe6515e2009-07-29 13:01:17 +0000634 return False
635
lmr71fa4de2010-06-14 15:54:55 +0000636 logging.debug("VM appears to be alive with PID %s", self.get_pid())
lmrdc2ac6a2009-06-10 19:15:49 +0000637 return True
638
639 finally:
640 fcntl.lockf(lockfile, fcntl.LOCK_UN)
641 lockfile.close()
lmr6f669ce2009-05-31 19:02:42 +0000642
643
lmr6f669ce2009-05-31 19:02:42 +0000644 def destroy(self, gracefully=True):
645 """
646 Destroy the VM.
647
lmr912c74b2009-08-17 20:43:27 +0000648 If gracefully is True, first attempt to shutdown the VM with a shell
649 command. Then, attempt to destroy the VM via the monitor with a 'quit'
650 command. If that fails, send SIGKILL to the qemu process.
lmr6f669ce2009-05-31 19:02:42 +0000651
652 @param gracefully: Whether an attempt will be made to end the VM
lmr912c74b2009-08-17 20:43:27 +0000653 using a shell command before trying to end the qemu process
654 with a 'quit' or a kill signal.
lmr6f669ce2009-05-31 19:02:42 +0000655 """
lmrf320b042009-09-15 05:48:06 +0000656 try:
657 # Is it already dead?
658 if self.is_dead():
659 logging.debug("VM is already down")
660 return
lmr6f669ce2009-05-31 19:02:42 +0000661
lmr71fa4de2010-06-14 15:54:55 +0000662 logging.debug("Destroying VM with PID %s...", self.get_pid())
lmr6f669ce2009-05-31 19:02:42 +0000663
lmrf320b042009-09-15 05:48:06 +0000664 if gracefully and self.params.get("shutdown_command"):
665 # Try to destroy with shell command
666 logging.debug("Trying to shutdown VM with shell command...")
667 session = self.remote_login()
668 if session:
669 try:
670 # Send the shutdown command
671 session.sendline(self.params.get("shutdown_command"))
672 logging.debug("Shutdown command sent; waiting for VM "
673 "to go down...")
674 if kvm_utils.wait_for(self.is_dead, 60, 1, 1):
675 logging.debug("VM is down")
676 return
677 finally:
678 session.close()
lmr6f669ce2009-05-31 19:02:42 +0000679
lmr9e964a02010-06-18 03:46:21 +0000680 if self.monitor:
681 # Try to destroy with a monitor command
682 logging.debug("Trying to kill VM with monitor command...")
683 try:
684 self.monitor.quit()
685 except kvm_monitor.MonitorError, e:
686 logging.warn(e)
687 else:
688 # Wait for the VM to be really dead
689 if kvm_utils.wait_for(self.is_dead, 5, 0.5, 0.5):
690 logging.debug("VM is down")
691 return
lmrf320b042009-09-15 05:48:06 +0000692
693 # If the VM isn't dead yet...
694 logging.debug("Cannot quit normally; sending a kill to close the "
695 "deal...")
696 kvm_utils.kill_process_tree(self.process.get_pid(), 9)
lmr6f669ce2009-05-31 19:02:42 +0000697 # Wait for the VM to be really dead
698 if kvm_utils.wait_for(self.is_dead, 5, 0.5, 0.5):
699 logging.debug("VM is down")
lmr6f669ce2009-05-31 19:02:42 +0000700 return
701
lmrf320b042009-09-15 05:48:06 +0000702 logging.error("Process %s is a zombie!" % self.process.get_pid())
lmr6f669ce2009-05-31 19:02:42 +0000703
lmrf320b042009-09-15 05:48:06 +0000704 finally:
lmr9e964a02010-06-18 03:46:21 +0000705 self.monitors = []
lmr4513c432010-02-03 11:59:03 +0000706 if self.pci_assignable:
707 self.pci_assignable.release_devs()
lmrf320b042009-09-15 05:48:06 +0000708 if self.process:
709 self.process.close()
lmr9e964a02010-06-18 03:46:21 +0000710 for f in ([self.get_testlog_filename()] +
711 self.get_monitor_filenames()):
712 try:
713 os.unlink(f)
714 except OSError:
715 pass
716
717
718 @property
719 def monitor(self):
720 """
721 Return the main monitor object, selected by the parameter main_monitor.
722 If main_monitor isn't defined, return the first monitor.
723 If no monitors exist, or if main_monitor refers to a nonexistent
724 monitor, return None.
725 """
726 for m in self.monitors:
727 if m.name == self.params.get("main_monitor"):
728 return m
729 if self.monitors and not self.params.get("main_monitor"):
730 return self.monitors[0]
lmr6f669ce2009-05-31 19:02:42 +0000731
732
733 def is_alive(self):
734 """
lmr9e964a02010-06-18 03:46:21 +0000735 Return True if the VM is alive and its monitor is responsive.
lmr6f669ce2009-05-31 19:02:42 +0000736 """
lmra4967622009-07-23 01:36:32 +0000737 # Check if the process is running
738 if self.is_dead():
lmr6f669ce2009-05-31 19:02:42 +0000739 return False
740 # Try sending a monitor command
lmr9e964a02010-06-18 03:46:21 +0000741 return bool(self.monitor) and self.monitor.is_responsive()
lmr6f669ce2009-05-31 19:02:42 +0000742
743
744 def is_dead(self):
745 """
lmra4967622009-07-23 01:36:32 +0000746 Return True if the qemu process is dead.
lmr6f669ce2009-05-31 19:02:42 +0000747 """
lmra4967622009-07-23 01:36:32 +0000748 return not self.process or not self.process.is_alive()
lmr6f669ce2009-05-31 19:02:42 +0000749
750
lmra4197002009-08-13 05:00:51 +0000751 def kill_tail_thread(self):
752 """
753 Stop the tailing thread which reports the output of qemu.
754 """
755 if self.process:
756 self.process.kill_tail_thread()
757
758
lmr6f669ce2009-05-31 19:02:42 +0000759 def get_params(self):
760 """
761 Return the VM's params dict. Most modified params take effect only
762 upon VM.create().
763 """
764 return self.params
765
766
lmr9e964a02010-06-18 03:46:21 +0000767 def get_monitor_filename(self, monitor_name):
768 """
769 Return the filename corresponding to a given monitor name.
770 """
771 return "/tmp/monitor-%s-%s" % (monitor_name, self.instance)
772
773
774 def get_monitor_filenames(self):
775 """
776 Return a list of all monitor filenames (as specified in the VM's
777 params).
778 """
779 return [self.get_monitor_filename(m) for m in
780 kvm_utils.get_sub_dict_names(self.params, "monitors")]
781
782
lmr2b06f332010-06-22 02:03:41 +0000783 def get_serial_console_filename(self):
784 """
785 Return the serial console filename.
786 """
787 return "/tmp/serial-%s" % self.instance
788
789
lmr9e964a02010-06-18 03:46:21 +0000790 def get_testlog_filename(self):
791 """
792 Return the testlog filename.
793 """
794 return "/tmp/testlog-%s" % self.instance
795
796
lmrf4696342009-08-13 04:06:33 +0000797 def get_address(self, index=0):
lmr6f669ce2009-05-31 19:02:42 +0000798 """
lmrf4696342009-08-13 04:06:33 +0000799 Return the address of a NIC of the guest, in host space.
lmr6f669ce2009-05-31 19:02:42 +0000800
lmrf4696342009-08-13 04:06:33 +0000801 If port redirection is used, return 'localhost' (the NIC has no IP
802 address of its own). Otherwise return the NIC's IP address.
803
804 @param index: Index of the NIC whose address is requested.
lmr6f669ce2009-05-31 19:02:42 +0000805 """
lmree90dd92009-08-13 04:13:39 +0000806 nics = kvm_utils.get_sub_dict_names(self.params, "nics")
807 nic_name = nics[index]
lmrf4696342009-08-13 04:06:33 +0000808 nic_params = kvm_utils.get_sub_dict(self.params, nic_name)
809 if nic_params.get("nic_mode") == "tap":
810 mac, ip = kvm_utils.get_mac_ip_pair_from_dict(nic_params)
lmree90dd92009-08-13 04:13:39 +0000811 if not mac:
812 logging.debug("MAC address unavailable")
813 return None
814 if not ip or nic_params.get("always_use_tcpdump") == "yes":
815 # Get the IP address from the cache
816 ip = self.address_cache.get(mac)
817 if not ip:
818 logging.debug("Could not find IP address for MAC address: "
819 "%s" % mac)
820 return None
821 # Make sure the IP address is assigned to this guest
822 nic_dicts = [kvm_utils.get_sub_dict(self.params, nic)
823 for nic in nics]
824 macs = [kvm_utils.get_mac_ip_pair_from_dict(dict)[0]
825 for dict in nic_dicts]
826 if not kvm_utils.verify_ip_address_ownership(ip, macs):
827 logging.debug("Could not verify MAC-IP address mapping: "
828 "%s ---> %s" % (mac, ip))
829 return None
lmrf4696342009-08-13 04:06:33 +0000830 return ip
831 else:
832 return "localhost"
lmr6f669ce2009-05-31 19:02:42 +0000833
834
lmree90dd92009-08-13 04:13:39 +0000835 def get_port(self, port, nic_index=0):
lmr6f669ce2009-05-31 19:02:42 +0000836 """
837 Return the port in host space corresponding to port in guest space.
838
839 @param port: Port number in host space.
lmree90dd92009-08-13 04:13:39 +0000840 @param nic_index: Index of the NIC.
lmr6f669ce2009-05-31 19:02:42 +0000841 @return: If port redirection is used, return the host port redirected
842 to guest port port. Otherwise return port.
843 """
lmree90dd92009-08-13 04:13:39 +0000844 nic_name = kvm_utils.get_sub_dict_names(self.params, "nics")[nic_index]
lmrf4696342009-08-13 04:06:33 +0000845 nic_params = kvm_utils.get_sub_dict(self.params, nic_name)
846 if nic_params.get("nic_mode") == "tap":
847 return port
lmr6f669ce2009-05-31 19:02:42 +0000848 else:
lmrf4696342009-08-13 04:06:33 +0000849 if not self.redirs.has_key(port):
850 logging.warn("Warning: guest port %s requested but not "
851 "redirected" % port)
852 return self.redirs.get(port)
lmr6f669ce2009-05-31 19:02:42 +0000853
854
lmra4967622009-07-23 01:36:32 +0000855 def get_pid(self):
856 """
lmr71fa4de2010-06-14 15:54:55 +0000857 Return the VM's PID. If the VM is dead return None.
858
859 @note: This works under the assumption that self.process.get_pid()
860 returns the PID of the parent shell process.
861 """
862 try:
863 children = commands.getoutput("ps --ppid=%d -o pid=" %
864 self.process.get_pid()).split()
865 return int(children[0])
866 except (TypeError, IndexError, ValueError):
867 return None
868
869
870 def get_shell_pid(self):
871 """
872 Return the PID of the parent shell process.
873
874 @note: This works under the assumption that self.process.get_pid()
875 returns the PID of the parent shell process.
lmra4967622009-07-23 01:36:32 +0000876 """
877 return self.process.get_pid()
878
879
lmr0bee2342010-02-24 00:01:37 +0000880 def get_shared_meminfo(self):
881 """
882 Returns the VM's shared memory information.
883
884 @return: Shared memory used by VM (MB)
885 """
886 if self.is_dead():
887 logging.error("Could not get shared memory info from dead VM.")
888 return None
889
lmr983ecdf2010-06-14 15:57:12 +0000890 filename = "/proc/%d/statm" % self.get_pid()
891 shm = int(open(filename).read().split()[2])
lmr0bee2342010-02-24 00:01:37 +0000892 # statm stores informations in pages, translate it to MB
lmr983ecdf2010-06-14 15:57:12 +0000893 return shm * 4.0 / 1024
lmr0bee2342010-02-24 00:01:37 +0000894
895
lmr912c74b2009-08-17 20:43:27 +0000896 def remote_login(self, nic_index=0, timeout=10):
lmr6f669ce2009-05-31 19:02:42 +0000897 """
lmr912c74b2009-08-17 20:43:27 +0000898 Log into the guest via SSH/Telnet/Netcat.
lmr6f669ce2009-05-31 19:02:42 +0000899 If timeout expires while waiting for output from the guest (e.g. a
900 password prompt or a shell prompt) -- fail.
901
lmree90dd92009-08-13 04:13:39 +0000902 @param nic_index: The index of the NIC to connect to.
lmr6f669ce2009-05-31 19:02:42 +0000903 @param timeout: Time (seconds) before giving up logging into the
904 guest.
905 @return: kvm_spawn object on success and None on failure.
906 """
907 username = self.params.get("username", "")
908 password = self.params.get("password", "")
lmr912c74b2009-08-17 20:43:27 +0000909 prompt = self.params.get("shell_prompt", "[\#\$]")
lmr59f9e2d2009-10-05 18:47:16 +0000910 linesep = eval("'%s'" % self.params.get("shell_linesep", r"\n"))
lmr912c74b2009-08-17 20:43:27 +0000911 client = self.params.get("shell_client")
lmree90dd92009-08-13 04:13:39 +0000912 address = self.get_address(nic_index)
lmr912c74b2009-08-17 20:43:27 +0000913 port = self.get_port(int(self.params.get("shell_port")))
914
lmree90dd92009-08-13 04:13:39 +0000915 if not address or not port:
916 logging.debug("IP address or port unavailable")
lmr6f669ce2009-05-31 19:02:42 +0000917 return None
918
lmr158604f2010-06-22 01:57:34 +0000919 session = kvm_utils.remote_login(client, address, port, username,
920 password, prompt, linesep, timeout)
lmr912c74b2009-08-17 20:43:27 +0000921
lmr6f669ce2009-05-31 19:02:42 +0000922 if session:
lmr912c74b2009-08-17 20:43:27 +0000923 session.set_status_test_command(self.params.get("status_test_"
lmr6f669ce2009-05-31 19:02:42 +0000924 "command", ""))
925 return session
926
927
lmrc196d492010-05-07 14:14:26 +0000928 def copy_files_to(self, local_path, remote_path, nic_index=0, timeout=600):
lmr6f669ce2009-05-31 19:02:42 +0000929 """
lmr912c74b2009-08-17 20:43:27 +0000930 Transfer files to the guest.
lmr6f669ce2009-05-31 19:02:42 +0000931
932 @param local_path: Host path
933 @param remote_path: Guest path
lmr912c74b2009-08-17 20:43:27 +0000934 @param nic_index: The index of the NIC to connect to.
lmr6f669ce2009-05-31 19:02:42 +0000935 @param timeout: Time (seconds) before giving up on doing the remote
936 copy.
937 """
938 username = self.params.get("username", "")
939 password = self.params.get("password", "")
lmr912c74b2009-08-17 20:43:27 +0000940 client = self.params.get("file_transfer_client")
lmree90dd92009-08-13 04:13:39 +0000941 address = self.get_address(nic_index)
lmr912c74b2009-08-17 20:43:27 +0000942 port = self.get_port(int(self.params.get("file_transfer_port")))
943
lmree90dd92009-08-13 04:13:39 +0000944 if not address or not port:
945 logging.debug("IP address or port unavailable")
lmr6f669ce2009-05-31 19:02:42 +0000946 return None
lmr912c74b2009-08-17 20:43:27 +0000947
948 if client == "scp":
949 return kvm_utils.scp_to_remote(address, port, username, password,
950 local_path, remote_path, timeout)
lmr6f669ce2009-05-31 19:02:42 +0000951
952
lmrc196d492010-05-07 14:14:26 +0000953 def copy_files_from(self, remote_path, local_path, nic_index=0, timeout=600):
lmr6f669ce2009-05-31 19:02:42 +0000954 """
lmr912c74b2009-08-17 20:43:27 +0000955 Transfer files from the guest.
lmr6f669ce2009-05-31 19:02:42 +0000956
957 @param local_path: Guest path
958 @param remote_path: Host path
lmr912c74b2009-08-17 20:43:27 +0000959 @param nic_index: The index of the NIC to connect to.
lmr6f669ce2009-05-31 19:02:42 +0000960 @param timeout: Time (seconds) before giving up on doing the remote
961 copy.
962 """
963 username = self.params.get("username", "")
964 password = self.params.get("password", "")
lmr912c74b2009-08-17 20:43:27 +0000965 client = self.params.get("file_transfer_client")
lmree90dd92009-08-13 04:13:39 +0000966 address = self.get_address(nic_index)
lmr912c74b2009-08-17 20:43:27 +0000967 port = self.get_port(int(self.params.get("file_transfer_port")))
968
lmree90dd92009-08-13 04:13:39 +0000969 if not address or not port:
970 logging.debug("IP address or port unavailable")
lmr6f669ce2009-05-31 19:02:42 +0000971 return None
lmr6f669ce2009-05-31 19:02:42 +0000972
lmr912c74b2009-08-17 20:43:27 +0000973 if client == "scp":
974 return kvm_utils.scp_from_remote(address, port, username, password,
975 remote_path, local_path, timeout)
lmr6f669ce2009-05-31 19:02:42 +0000976
977
978 def send_key(self, keystr):
979 """
980 Send a key event to the VM.
981
982 @param: keystr: A key event string (e.g. "ctrl-alt-delete")
983 """
984 # For compatibility with versions of QEMU that do not recognize all
985 # key names: replace keyname with the hex value from the dict, which
986 # QEMU will definitely accept
lmr9e964a02010-06-18 03:46:21 +0000987 dict = {"comma": "0x33",
988 "dot": "0x34",
989 "slash": "0x35"}
990 for key, value in dict.items():
991 keystr = keystr.replace(key, value)
992 self.monitor.sendkey(keystr)
lmr6f669ce2009-05-31 19:02:42 +0000993 time.sleep(0.2)
994
995
996 def send_string(self, str):
997 """
998 Send a string to the VM.
999
1000 @param str: String, that must consist of alphanumeric characters only.
1001 Capital letters are allowed.
1002 """
1003 for char in str:
1004 if char.isupper():
1005 self.send_key("shift-%s" % char.lower())
1006 else:
1007 self.send_key(char)
lmra2533222009-07-20 12:43:46 +00001008
mbligh1ef218d2009-08-03 16:57:56 +00001009
lmra2533222009-07-20 12:43:46 +00001010 def get_uuid(self):
1011 """
1012 Catch UUID of the VM.
1013
1014 @return: None,if not specified in config file
1015 """
1016 if self.params.get("uuid") == "random":
1017 return self.uuid
1018 else:
1019 return self.params.get("uuid", None)
lmrdd2ff922009-12-01 23:39:12 +00001020
1021
1022 def get_cpu_count(self):
1023 """
1024 Get the cpu count of the VM.
1025 """
lmr13426552010-01-17 15:38:41 +00001026 session = self.remote_login()
1027 if not session:
1028 return None
lmrdd2ff922009-12-01 23:39:12 +00001029 try:
lmr13426552010-01-17 15:38:41 +00001030 cmd = self.params.get("cpu_chk_cmd")
1031 s, count = session.get_command_status_output(cmd)
1032 if s == 0:
1033 return int(count)
lmrdd2ff922009-12-01 23:39:12 +00001034 return None
1035 finally:
1036 session.close()
1037
1038
lmr28426c82010-04-16 06:02:58 +00001039 def get_memory_size(self, cmd=None):
lmrdd2ff922009-12-01 23:39:12 +00001040 """
lmr28426c82010-04-16 06:02:58 +00001041 Get bootup memory size of the VM.
1042
1043 @param check_cmd: Command used to check memory. If not provided,
1044 self.params.get("mem_chk_cmd") will be used.
lmrdd2ff922009-12-01 23:39:12 +00001045 """
lmr13426552010-01-17 15:38:41 +00001046 session = self.remote_login()
1047 if not session:
lmrdd2ff922009-12-01 23:39:12 +00001048 return None
lmr13426552010-01-17 15:38:41 +00001049 try:
lmr28426c82010-04-16 06:02:58 +00001050 if not cmd:
1051 cmd = self.params.get("mem_chk_cmd")
lmr13426552010-01-17 15:38:41 +00001052 s, mem_str = session.get_command_status_output(cmd)
1053 if s != 0:
1054 return None
lmr6d69f4d2010-02-12 11:35:55 +00001055 mem = re.findall("([0-9]+)", mem_str)
lmr13426552010-01-17 15:38:41 +00001056 mem_size = 0
1057 for m in mem:
1058 mem_size += int(m)
1059 if "GB" in mem_str:
1060 mem_size *= 1024
1061 elif "MB" in mem_str:
1062 pass
1063 else:
1064 mem_size /= 1024
1065 return int(mem_size)
lmrdd2ff922009-12-01 23:39:12 +00001066 finally:
1067 session.close()
lmr28426c82010-04-16 06:02:58 +00001068
1069
1070 def get_current_memory_size(self):
1071 """
1072 Get current memory size of the VM, rather than bootup memory.
1073 """
1074 cmd = self.params.get("mem_chk_cur_cmd")
1075 return self.get_memory_size(cmd)