blob: 0643bca217e9d86ced330d613a70d514565bd616 [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():
122 self.netdev_id.append(kvm_utils.generate_random_string(4))
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
lmr48abd7d2010-05-26 13:48:04 +0000290 # End of command line option wrappers
291
292 if name is None: name = self.name
293 if params is None: params = self.params
294 if root_dir is None: root_dir = self.root_dir
295
296 qemu_binary = kvm_utils.get_path(root_dir, params.get("qemu_binary",
297 "qemu"))
298 # Get the output of 'qemu -help' (log a message in case this call never
299 # returns or causes some other kind of trouble)
300 logging.debug("Getting output of 'qemu -help'")
301 help = commands.getoutput("%s -help" % qemu_binary)
lmr6f669ce2009-05-31 19:02:42 +0000302
lmreeff0eb2009-06-10 19:19:15 +0000303 # Start constructing the qemu command
304 qemu_cmd = ""
305 # Set the X11 display parameter if requested
306 if params.get("x11_display"):
307 qemu_cmd += "DISPLAY=%s " % params.get("x11_display")
308 # Add the qemu binary
lmr48abd7d2010-05-26 13:48:04 +0000309 qemu_cmd += qemu_binary
lmreeff0eb2009-06-10 19:19:15 +0000310 # Add the VM's name
lmr48abd7d2010-05-26 13:48:04 +0000311 qemu_cmd += add_name(help, name)
lmr9e964a02010-06-18 03:46:21 +0000312 # Add monitors
313 for monitor_name in kvm_utils.get_sub_dict_names(params, "monitors"):
314 monitor_params = kvm_utils.get_sub_dict(params, monitor_name)
315 monitor_filename = self.get_monitor_filename(monitor_name)
316 if monitor_params.get("monitor_type") == "qmp":
317 qemu_cmd += add_qmp_monitor(help, monitor_filename)
318 else:
319 qemu_cmd += add_human_monitor(help, monitor_filename)
lmr6f669ce2009-05-31 19:02:42 +0000320
lmr2b06f332010-06-22 02:03:41 +0000321 # Add serial console redirection
322 qemu_cmd += add_serial(help, self.get_serial_console_filename())
323
lmr6f669ce2009-05-31 19:02:42 +0000324 for image_name in kvm_utils.get_sub_dict_names(params, "images"):
325 image_params = kvm_utils.get_sub_dict(params, image_name)
lmr9d75ee32009-09-29 13:14:13 +0000326 if image_params.get("boot_drive") == "no":
327 continue
lmr48abd7d2010-05-26 13:48:04 +0000328 qemu_cmd += add_drive(help,
329 get_image_filename(image_params, root_dir),
330 image_params.get("drive_format"),
331 image_params.get("drive_cache"),
332 image_params.get("drive_werror"),
333 image_params.get("drive_serial"),
334 image_params.get("image_snapshot") == "yes",
335 image_params.get("image_boot") == "yes")
lmr6f669ce2009-05-31 19:02:42 +0000336
337 vlan = 0
338 for nic_name in kvm_utils.get_sub_dict_names(params, "nics"):
339 nic_params = kvm_utils.get_sub_dict(params, nic_name)
lmrf4696342009-08-13 04:06:33 +0000340 # Handle the '-net nic' part
lmr48abd7d2010-05-26 13:48:04 +0000341 mac = None
342 if "address_index" in nic_params:
343 mac = kvm_utils.get_mac_ip_pair_from_dict(nic_params)[0]
lmrb1cad1e2010-06-17 17:36:09 +0000344 qemu_cmd += add_nic(help, vlan, nic_params.get("nic_model"), mac,
345 self.netdev_id[vlan])
lmrf4696342009-08-13 04:06:33 +0000346 # Handle the '-net tap' or '-net user' part
lmre4eaa862010-06-01 19:15:14 +0000347 script = nic_params.get("nic_script")
348 downscript = nic_params.get("nic_downscript")
lmr48abd7d2010-05-26 13:48:04 +0000349 if script:
350 script = kvm_utils.get_path(root_dir, script)
351 if downscript:
352 downscript = kvm_utils.get_path(root_dir, downscript)
353 qemu_cmd += add_net(help, vlan, nic_params.get("nic_mode", "user"),
354 nic_params.get("nic_ifname"),
lmrb1cad1e2010-06-17 17:36:09 +0000355 script, downscript, self.netdev_id[vlan])
lmrf4696342009-08-13 04:06:33 +0000356 # Proceed to next NIC
lmr6f669ce2009-05-31 19:02:42 +0000357 vlan += 1
358
359 mem = params.get("mem")
360 if mem:
lmr48abd7d2010-05-26 13:48:04 +0000361 qemu_cmd += add_mem(help, mem)
lmr6f669ce2009-05-31 19:02:42 +0000362
lmrc43bf372009-11-10 13:19:00 +0000363 smp = params.get("smp")
364 if smp:
lmrdb3fe612010-06-14 16:19:28 +0000365 qemu_cmd += add_smp(help, smp)
lmrc43bf372009-11-10 13:19:00 +0000366
lmr6f669ce2009-05-31 19:02:42 +0000367 iso = params.get("cdrom")
368 if iso:
lmr90b9fd52009-08-17 20:48:18 +0000369 iso = kvm_utils.get_path(root_dir, iso)
lmr48abd7d2010-05-26 13:48:04 +0000370 qemu_cmd += add_cdrom(help, iso)
lmr89fd6412010-01-18 02:42:57 +0000371
372 # Even though this is not a really scalable approach,
373 # it doesn't seem like we are going to need more than
374 # 2 CDs active on the same VM.
375 iso_extra = params.get("cdrom_extra")
376 if iso_extra:
377 iso_extra = kvm_utils.get_path(root_dir, iso_extra)
lmr48abd7d2010-05-26 13:48:04 +0000378 qemu_cmd += add_cdrom(help, iso_extra, 3)
lmr6f669ce2009-05-31 19:02:42 +0000379
lmrb0a9b762009-10-09 20:43:30 +0000380 # We may want to add {floppy_otps} parameter for -fda
lmr48abd7d2010-05-26 13:48:04 +0000381 # {fat:floppy:}/path/. However vvfat is not usually recommended.
lmrb0a9b762009-10-09 20:43:30 +0000382 floppy = params.get("floppy")
383 if floppy:
lmrf69f6b12009-11-10 16:33:44 +0000384 floppy = kvm_utils.get_path(root_dir, floppy)
lmr48abd7d2010-05-26 13:48:04 +0000385 qemu_cmd += add_floppy(help, floppy)
lmrb0a9b762009-10-09 20:43:30 +0000386
387 tftp = params.get("tftp")
388 if tftp:
lmrf69f6b12009-11-10 16:33:44 +0000389 tftp = kvm_utils.get_path(root_dir, tftp)
lmr48abd7d2010-05-26 13:48:04 +0000390 qemu_cmd += add_tftp(help, tftp)
lmr6f669ce2009-05-31 19:02:42 +0000391
lmr41cb8fc2010-06-10 15:30:45 +0000392 kernel = params.get("kernel")
393 if kernel:
394 kernel = kvm_utils.get_path(root_dir, kernel)
395 qemu_cmd += add_kernel(help, kernel)
396
397 initrd = params.get("initrd")
398 if initrd:
399 initrd = kvm_utils.get_path(root_dir, initrd)
400 qemu_cmd += add_initrd(help, initrd)
401
lmr6f669ce2009-05-31 19:02:42 +0000402 for redir_name in kvm_utils.get_sub_dict_names(params, "redirs"):
403 redir_params = kvm_utils.get_sub_dict(params, redir_name)
404 guest_port = int(redir_params.get("guest_port"))
lmrf4696342009-08-13 04:06:33 +0000405 host_port = self.redirs.get(guest_port)
lmr48abd7d2010-05-26 13:48:04 +0000406 qemu_cmd += add_tcp_redir(help, host_port, guest_port)
lmr6f669ce2009-05-31 19:02:42 +0000407
408 if params.get("display") == "vnc":
lmr48abd7d2010-05-26 13:48:04 +0000409 qemu_cmd += add_vnc(help, self.vnc_port)
lmr6f669ce2009-05-31 19:02:42 +0000410 elif params.get("display") == "sdl":
lmr48abd7d2010-05-26 13:48:04 +0000411 qemu_cmd += add_sdl(help)
lmr6f669ce2009-05-31 19:02:42 +0000412 elif params.get("display") == "nographic":
lmr48abd7d2010-05-26 13:48:04 +0000413 qemu_cmd += add_nographic(help)
lmr6f669ce2009-05-31 19:02:42 +0000414
lmra2533222009-07-20 12:43:46 +0000415 if params.get("uuid") == "random":
lmr48abd7d2010-05-26 13:48:04 +0000416 qemu_cmd += add_uuid(help, self.uuid)
lmra2533222009-07-20 12:43:46 +0000417 elif params.get("uuid"):
lmr48abd7d2010-05-26 13:48:04 +0000418 qemu_cmd += add_uuid(help, params.get("uuid"))
lmra2533222009-07-20 12:43:46 +0000419
lmr31af3a12010-01-18 16:46:52 +0000420 # If the PCI assignment step went OK, add each one of the PCI assigned
421 # devices to the qemu command line.
422 if self.pci_assignable:
423 for pci_id in self.pa_pci_ids:
lmr48abd7d2010-05-26 13:48:04 +0000424 qemu_cmd += add_pcidevice(help, pci_id)
425
426 extra_params = params.get("extra_params")
427 if extra_params:
428 qemu_cmd += " %s" % extra_params
lmr31af3a12010-01-18 16:46:52 +0000429
lmr6f669ce2009-05-31 19:02:42 +0000430 return qemu_cmd
431
432
lmr52800ba2009-08-17 20:49:58 +0000433 def create(self, name=None, params=None, root_dir=None,
lmr1424f3e2010-06-17 13:57:09 +0000434 for_migration=False, timeout=5.0, extra_params=None):
lmr6f669ce2009-05-31 19:02:42 +0000435 """
436 Start the VM by running a qemu command.
437 All parameters are optional. The following applies to all parameters
438 but for_migration: If a parameter is not supplied, the corresponding
439 value stored in the class attributes is used, and if it is supplied,
440 it is stored for later use.
441
442 @param name: The name of the object
443 @param params: A dict containing VM params
lmr90b9fd52009-08-17 20:48:18 +0000444 @param root_dir: Base directory for relative filenames
lmr6f669ce2009-05-31 19:02:42 +0000445 @param for_migration: If True, start the VM with the -incoming
446 option
lmr1424f3e2010-06-17 13:57:09 +0000447 @param extra_params: extra params for qemu command.e.g -incoming option
448 Please use this parameter instead of for_migration.
lmr6f669ce2009-05-31 19:02:42 +0000449 """
lmr135b5e62009-06-10 19:22:31 +0000450 self.destroy()
451
lmre45a1f22009-11-10 16:35:08 +0000452 if name is not None:
lmr6f669ce2009-05-31 19:02:42 +0000453 self.name = name
lmre45a1f22009-11-10 16:35:08 +0000454 if params is not None:
lmr6f669ce2009-05-31 19:02:42 +0000455 self.params = params
lmre45a1f22009-11-10 16:35:08 +0000456 if root_dir is not None:
lmr90b9fd52009-08-17 20:48:18 +0000457 self.root_dir = root_dir
lmr6f669ce2009-05-31 19:02:42 +0000458 name = self.name
459 params = self.params
lmr90b9fd52009-08-17 20:48:18 +0000460 root_dir = self.root_dir
lmr6f669ce2009-05-31 19:02:42 +0000461
462 # Verify the md5sum of the ISO image
463 iso = params.get("cdrom")
464 if iso:
lmr90b9fd52009-08-17 20:48:18 +0000465 iso = kvm_utils.get_path(root_dir, iso)
lmr6f669ce2009-05-31 19:02:42 +0000466 if not os.path.exists(iso):
467 logging.error("ISO file not found: %s" % iso)
468 return False
469 compare = False
470 if params.get("md5sum_1m"):
lmrf4696342009-08-13 04:06:33 +0000471 logging.debug("Comparing expected MD5 sum with MD5 sum of "
472 "first MB of ISO file...")
lmrd60882f2010-02-04 03:26:36 +0000473 actual_hash = utils.hash_file(iso, 1048576, method="md5")
lmr03ba22e2009-10-23 12:07:44 +0000474 expected_hash = params.get("md5sum_1m")
lmr6f669ce2009-05-31 19:02:42 +0000475 compare = True
476 elif params.get("md5sum"):
lmrf4696342009-08-13 04:06:33 +0000477 logging.debug("Comparing expected MD5 sum with MD5 sum of ISO "
478 "file...")
lmrd60882f2010-02-04 03:26:36 +0000479 actual_hash = utils.hash_file(iso, method="md5")
lmr03ba22e2009-10-23 12:07:44 +0000480 expected_hash = params.get("md5sum")
481 compare = True
482 elif params.get("sha1sum"):
483 logging.debug("Comparing expected SHA1 sum with SHA1 sum of "
484 "ISO file...")
lmrd60882f2010-02-04 03:26:36 +0000485 actual_hash = utils.hash_file(iso, method="sha1")
lmrea1266e2009-11-10 16:41:08 +0000486 expected_hash = params.get("sha1sum")
lmr6f669ce2009-05-31 19:02:42 +0000487 compare = True
488 if compare:
lmr03ba22e2009-10-23 12:07:44 +0000489 if actual_hash == expected_hash:
490 logging.debug("Hashes match")
lmr6f669ce2009-05-31 19:02:42 +0000491 else:
lmr03ba22e2009-10-23 12:07:44 +0000492 logging.error("Actual hash differs from expected one")
lmr6f669ce2009-05-31 19:02:42 +0000493 return False
494
lmrdc2ac6a2009-06-10 19:15:49 +0000495 # Make sure the following code is not executed by more than one thread
496 # at the same time
497 lockfile = open("/tmp/kvm-autotest-vm-create.lock", "w+")
498 fcntl.lockf(lockfile, fcntl.LOCK_EX)
lmr6f669ce2009-05-31 19:02:42 +0000499
lmrdc2ac6a2009-06-10 19:15:49 +0000500 try:
501 # Handle port redirections
502 redir_names = kvm_utils.get_sub_dict_names(params, "redirs")
503 host_ports = kvm_utils.find_free_ports(5000, 6000, len(redir_names))
504 self.redirs = {}
505 for i in range(len(redir_names)):
506 redir_params = kvm_utils.get_sub_dict(params, redir_names[i])
507 guest_port = int(redir_params.get("guest_port"))
508 self.redirs[guest_port] = host_ports[i]
lmr6f669ce2009-05-31 19:02:42 +0000509
lmrdc2ac6a2009-06-10 19:15:49 +0000510 # Find available VNC port, if needed
511 if params.get("display") == "vnc":
lmrc0da8902010-05-17 20:31:36 +0000512 self.vnc_port = kvm_utils.find_free_port(5900, 6100)
lmr6f669ce2009-05-31 19:02:42 +0000513
lmra2533222009-07-20 12:43:46 +0000514 # Find random UUID if specified 'uuid = random' in config file
515 if params.get("uuid") == "random":
516 f = open("/proc/sys/kernel/random/uuid")
517 self.uuid = f.read().strip()
518 f.close()
519
lmr31ed61d2010-06-07 13:21:38 +0000520 # Assign a PCI assignable device
521 self.pci_assignable = None
522 pa_type = params.get("pci_assignable")
523 if pa_type in ["vf", "pf", "mixed"]:
lmr31af3a12010-01-18 16:46:52 +0000524 pa_devices_requested = params.get("devices_requested")
525
526 # Virtual Functions (VF) assignable devices
527 if pa_type == "vf":
lmr31ed61d2010-06-07 13:21:38 +0000528 self.pci_assignable = kvm_utils.PciAssignable(
529 type=pa_type,
530 driver=params.get("driver"),
531 driver_option=params.get("driver_option"),
532 devices_requested=pa_devices_requested)
lmr31af3a12010-01-18 16:46:52 +0000533 # Physical NIC (PF) assignable devices
534 elif pa_type == "pf":
lmr31ed61d2010-06-07 13:21:38 +0000535 self.pci_assignable = kvm_utils.PciAssignable(
536 type=pa_type,
537 names=params.get("device_names"),
538 devices_requested=pa_devices_requested)
lmr31af3a12010-01-18 16:46:52 +0000539 # Working with both VF and PF
540 elif pa_type == "mixed":
lmr31ed61d2010-06-07 13:21:38 +0000541 self.pci_assignable = kvm_utils.PciAssignable(
542 type=pa_type,
543 driver=params.get("driver"),
544 driver_option=params.get("driver_option"),
545 names=params.get("device_names"),
546 devices_requested=pa_devices_requested)
lmr31af3a12010-01-18 16:46:52 +0000547
548 self.pa_pci_ids = self.pci_assignable.request_devs()
549
550 if self.pa_pci_ids:
lmr31ed61d2010-06-07 13:21:38 +0000551 logging.debug("Successfuly assigned devices: %s",
lmr31af3a12010-01-18 16:46:52 +0000552 self.pa_pci_ids)
553 else:
554 logging.error("No PCI assignable devices were assigned "
555 "and 'pci_assignable' is defined to %s "
lmr31ed61d2010-06-07 13:21:38 +0000556 "on your config file. Aborting VM creation.",
lmr31af3a12010-01-18 16:46:52 +0000557 pa_type)
558 return False
559
lmr856d58c2010-06-08 18:29:31 +0000560 elif pa_type and pa_type != "no":
lmr31ed61d2010-06-07 13:21:38 +0000561 logging.warn("Unsupported pci_assignable type: %s", pa_type)
lmr31af3a12010-01-18 16:46:52 +0000562
lmrdc2ac6a2009-06-10 19:15:49 +0000563 # Make qemu command
564 qemu_command = self.make_qemu_command()
lmr6f669ce2009-05-31 19:02:42 +0000565
lmr1424f3e2010-06-17 13:57:09 +0000566 # Enable migration support for VM by adding extra_params.
567 if extra_params is not None:
568 if " -incoming tcp:0:%d" == extra_params:
569 self.migration_port = kvm_utils.find_free_port(5200, 6000)
570 qemu_command += extra_params % self.migration_port
571 elif " -incoming unix:%s" == extra_params:
572 self.migration_file = os.path.join("/tmp/", "unix-" +
573 time.strftime("%Y%m%d-%H%M%S"))
574 qemu_command += extra_params % self.migration_file
575 else:
576 qemu_command += extra_params
lmr6f669ce2009-05-31 19:02:42 +0000577
lmrdc2ac6a2009-06-10 19:15:49 +0000578 logging.debug("Running qemu command:\n%s", qemu_command)
lmra4967622009-07-23 01:36:32 +0000579 self.process = kvm_subprocess.run_bg(qemu_command, None,
580 logging.debug, "(qemu) ")
lmr6f669ce2009-05-31 19:02:42 +0000581
lmr9e964a02010-06-18 03:46:21 +0000582 # Make sure the process was started successfully
lmra4967622009-07-23 01:36:32 +0000583 if not self.process.is_alive():
584 logging.error("VM could not be created; "
585 "qemu command failed:\n%s" % qemu_command)
586 logging.error("Status: %s" % self.process.get_status())
587 logging.error("Output:" + kvm_utils.format_str_for_message(
588 self.process.get_output()))
lmrdc2ac6a2009-06-10 19:15:49 +0000589 self.destroy()
590 return False
lmr6f669ce2009-05-31 19:02:42 +0000591
lmr9e964a02010-06-18 03:46:21 +0000592 # Establish monitor connections
593 self.monitors = []
594 for monitor_name in kvm_utils.get_sub_dict_names(params,
595 "monitors"):
596 monitor_params = kvm_utils.get_sub_dict(params, monitor_name)
597 # Wait for monitor connection to succeed
598 end_time = time.time() + timeout
599 while time.time() < end_time:
600 try:
601 if monitor_params.get("monitor_type") == "qmp":
lmr449d2252010-06-18 03:48:23 +0000602 # Add a QMP monitor
603 monitor = kvm_monitor.QMPMonitor(
604 monitor_name,
605 self.get_monitor_filename(monitor_name))
lmr9e964a02010-06-18 03:46:21 +0000606 else:
607 # Add a "human" monitor
608 monitor = kvm_monitor.HumanMonitor(
609 monitor_name,
610 self.get_monitor_filename(monitor_name))
611 except kvm_monitor.MonitorError, e:
612 logging.warn(e)
613 else:
lmr449d2252010-06-18 03:48:23 +0000614 if monitor.is_responsive():
lmr9e964a02010-06-18 03:46:21 +0000615 break
616 time.sleep(1)
617 else:
618 logging.error("Could not connect to monitor '%s'" %
619 monitor_name)
620 self.destroy()
621 return False
622 # Add this monitor to the list
623 self.monitors += [monitor]
lmra4967622009-07-23 01:36:32 +0000624
lmrfe6515e2009-07-29 13:01:17 +0000625 # Get the output so far, to see if we have any problems with
626 # hugepage setup.
627 output = self.process.get_output()
628
629 if "alloc_mem_area" in output:
630 logging.error("Could not allocate hugepage memory; "
631 "qemu command:\n%s" % qemu_command)
632 logging.error("Output:" + kvm_utils.format_str_for_message(
633 self.process.get_output()))
lmr090cd7a2010-04-01 02:18:52 +0000634 self.destroy()
lmrfe6515e2009-07-29 13:01:17 +0000635 return False
636
lmr71fa4de2010-06-14 15:54:55 +0000637 logging.debug("VM appears to be alive with PID %s", self.get_pid())
lmraa380a22010-06-22 02:05:29 +0000638
639 # Establish a session with the serial console -- requires a version
640 # of netcat that supports -U
641 self.serial_console = kvm_subprocess.kvm_shell_session(
642 "nc -U %s" % self.get_serial_console_filename(),
643 auto_close=False,
644 output_func=kvm_utils.log_line,
645 output_params=("serial-%s.log" % name,))
646
lmrdc2ac6a2009-06-10 19:15:49 +0000647 return True
648
649 finally:
650 fcntl.lockf(lockfile, fcntl.LOCK_UN)
651 lockfile.close()
lmr6f669ce2009-05-31 19:02:42 +0000652
653
lmr6f669ce2009-05-31 19:02:42 +0000654 def destroy(self, gracefully=True):
655 """
656 Destroy the VM.
657
lmr912c74b2009-08-17 20:43:27 +0000658 If gracefully is True, first attempt to shutdown the VM with a shell
659 command. Then, attempt to destroy the VM via the monitor with a 'quit'
660 command. If that fails, send SIGKILL to the qemu process.
lmr6f669ce2009-05-31 19:02:42 +0000661
662 @param gracefully: Whether an attempt will be made to end the VM
lmr912c74b2009-08-17 20:43:27 +0000663 using a shell command before trying to end the qemu process
664 with a 'quit' or a kill signal.
lmr6f669ce2009-05-31 19:02:42 +0000665 """
lmrf320b042009-09-15 05:48:06 +0000666 try:
667 # Is it already dead?
668 if self.is_dead():
669 logging.debug("VM is already down")
670 return
lmr6f669ce2009-05-31 19:02:42 +0000671
lmr71fa4de2010-06-14 15:54:55 +0000672 logging.debug("Destroying VM with PID %s...", self.get_pid())
lmr6f669ce2009-05-31 19:02:42 +0000673
lmrf320b042009-09-15 05:48:06 +0000674 if gracefully and self.params.get("shutdown_command"):
675 # Try to destroy with shell command
676 logging.debug("Trying to shutdown VM with shell command...")
677 session = self.remote_login()
678 if session:
679 try:
680 # Send the shutdown command
681 session.sendline(self.params.get("shutdown_command"))
682 logging.debug("Shutdown command sent; waiting for VM "
683 "to go down...")
684 if kvm_utils.wait_for(self.is_dead, 60, 1, 1):
685 logging.debug("VM is down")
686 return
687 finally:
688 session.close()
lmr6f669ce2009-05-31 19:02:42 +0000689
lmr9e964a02010-06-18 03:46:21 +0000690 if self.monitor:
691 # Try to destroy with a monitor command
692 logging.debug("Trying to kill VM with monitor command...")
693 try:
694 self.monitor.quit()
695 except kvm_monitor.MonitorError, e:
696 logging.warn(e)
697 else:
698 # Wait for the VM to be really dead
699 if kvm_utils.wait_for(self.is_dead, 5, 0.5, 0.5):
700 logging.debug("VM is down")
701 return
lmrf320b042009-09-15 05:48:06 +0000702
703 # If the VM isn't dead yet...
704 logging.debug("Cannot quit normally; sending a kill to close the "
705 "deal...")
706 kvm_utils.kill_process_tree(self.process.get_pid(), 9)
lmr6f669ce2009-05-31 19:02:42 +0000707 # Wait for the VM to be really dead
708 if kvm_utils.wait_for(self.is_dead, 5, 0.5, 0.5):
709 logging.debug("VM is down")
lmr6f669ce2009-05-31 19:02:42 +0000710 return
711
lmrf320b042009-09-15 05:48:06 +0000712 logging.error("Process %s is a zombie!" % self.process.get_pid())
lmr6f669ce2009-05-31 19:02:42 +0000713
lmrf320b042009-09-15 05:48:06 +0000714 finally:
lmr9e964a02010-06-18 03:46:21 +0000715 self.monitors = []
lmr4513c432010-02-03 11:59:03 +0000716 if self.pci_assignable:
717 self.pci_assignable.release_devs()
lmrf320b042009-09-15 05:48:06 +0000718 if self.process:
719 self.process.close()
lmraa380a22010-06-22 02:05:29 +0000720 if self.serial_console:
721 self.serial_console.close()
lmr9e964a02010-06-18 03:46:21 +0000722 for f in ([self.get_testlog_filename()] +
723 self.get_monitor_filenames()):
724 try:
725 os.unlink(f)
726 except OSError:
727 pass
728
729
730 @property
731 def monitor(self):
732 """
733 Return the main monitor object, selected by the parameter main_monitor.
734 If main_monitor isn't defined, return the first monitor.
735 If no monitors exist, or if main_monitor refers to a nonexistent
736 monitor, return None.
737 """
738 for m in self.monitors:
739 if m.name == self.params.get("main_monitor"):
740 return m
741 if self.monitors and not self.params.get("main_monitor"):
742 return self.monitors[0]
lmr6f669ce2009-05-31 19:02:42 +0000743
744
745 def is_alive(self):
746 """
lmr9e964a02010-06-18 03:46:21 +0000747 Return True if the VM is alive and its monitor is responsive.
lmr6f669ce2009-05-31 19:02:42 +0000748 """
lmra4967622009-07-23 01:36:32 +0000749 # Check if the process is running
750 if self.is_dead():
lmr6f669ce2009-05-31 19:02:42 +0000751 return False
752 # Try sending a monitor command
lmr9e964a02010-06-18 03:46:21 +0000753 return bool(self.monitor) and self.monitor.is_responsive()
lmr6f669ce2009-05-31 19:02:42 +0000754
755
756 def is_dead(self):
757 """
lmra4967622009-07-23 01:36:32 +0000758 Return True if the qemu process is dead.
lmr6f669ce2009-05-31 19:02:42 +0000759 """
lmra4967622009-07-23 01:36:32 +0000760 return not self.process or not self.process.is_alive()
lmr6f669ce2009-05-31 19:02:42 +0000761
762
lmra4197002009-08-13 05:00:51 +0000763 def kill_tail_thread(self):
764 """
765 Stop the tailing thread which reports the output of qemu.
766 """
767 if self.process:
768 self.process.kill_tail_thread()
769
770
lmr6f669ce2009-05-31 19:02:42 +0000771 def get_params(self):
772 """
773 Return the VM's params dict. Most modified params take effect only
774 upon VM.create().
775 """
776 return self.params
777
778
lmr9e964a02010-06-18 03:46:21 +0000779 def get_monitor_filename(self, monitor_name):
780 """
781 Return the filename corresponding to a given monitor name.
782 """
783 return "/tmp/monitor-%s-%s" % (monitor_name, self.instance)
784
785
786 def get_monitor_filenames(self):
787 """
788 Return a list of all monitor filenames (as specified in the VM's
789 params).
790 """
791 return [self.get_monitor_filename(m) for m in
792 kvm_utils.get_sub_dict_names(self.params, "monitors")]
793
794
lmr2b06f332010-06-22 02:03:41 +0000795 def get_serial_console_filename(self):
796 """
797 Return the serial console filename.
798 """
799 return "/tmp/serial-%s" % self.instance
800
801
lmr9e964a02010-06-18 03:46:21 +0000802 def get_testlog_filename(self):
803 """
804 Return the testlog filename.
805 """
806 return "/tmp/testlog-%s" % self.instance
807
808
lmrf4696342009-08-13 04:06:33 +0000809 def get_address(self, index=0):
lmr6f669ce2009-05-31 19:02:42 +0000810 """
lmrf4696342009-08-13 04:06:33 +0000811 Return the address of a NIC of the guest, in host space.
lmr6f669ce2009-05-31 19:02:42 +0000812
lmrf4696342009-08-13 04:06:33 +0000813 If port redirection is used, return 'localhost' (the NIC has no IP
814 address of its own). Otherwise return the NIC's IP address.
815
816 @param index: Index of the NIC whose address is requested.
lmr6f669ce2009-05-31 19:02:42 +0000817 """
lmree90dd92009-08-13 04:13:39 +0000818 nics = kvm_utils.get_sub_dict_names(self.params, "nics")
819 nic_name = nics[index]
lmrf4696342009-08-13 04:06:33 +0000820 nic_params = kvm_utils.get_sub_dict(self.params, nic_name)
821 if nic_params.get("nic_mode") == "tap":
822 mac, ip = kvm_utils.get_mac_ip_pair_from_dict(nic_params)
lmree90dd92009-08-13 04:13:39 +0000823 if not mac:
824 logging.debug("MAC address unavailable")
825 return None
826 if not ip or nic_params.get("always_use_tcpdump") == "yes":
827 # Get the IP address from the cache
828 ip = self.address_cache.get(mac)
829 if not ip:
830 logging.debug("Could not find IP address for MAC address: "
831 "%s" % mac)
832 return None
833 # Make sure the IP address is assigned to this guest
834 nic_dicts = [kvm_utils.get_sub_dict(self.params, nic)
835 for nic in nics]
836 macs = [kvm_utils.get_mac_ip_pair_from_dict(dict)[0]
837 for dict in nic_dicts]
838 if not kvm_utils.verify_ip_address_ownership(ip, macs):
839 logging.debug("Could not verify MAC-IP address mapping: "
840 "%s ---> %s" % (mac, ip))
841 return None
lmrf4696342009-08-13 04:06:33 +0000842 return ip
843 else:
844 return "localhost"
lmr6f669ce2009-05-31 19:02:42 +0000845
846
lmree90dd92009-08-13 04:13:39 +0000847 def get_port(self, port, nic_index=0):
lmr6f669ce2009-05-31 19:02:42 +0000848 """
849 Return the port in host space corresponding to port in guest space.
850
851 @param port: Port number in host space.
lmree90dd92009-08-13 04:13:39 +0000852 @param nic_index: Index of the NIC.
lmr6f669ce2009-05-31 19:02:42 +0000853 @return: If port redirection is used, return the host port redirected
854 to guest port port. Otherwise return port.
855 """
lmree90dd92009-08-13 04:13:39 +0000856 nic_name = kvm_utils.get_sub_dict_names(self.params, "nics")[nic_index]
lmrf4696342009-08-13 04:06:33 +0000857 nic_params = kvm_utils.get_sub_dict(self.params, nic_name)
858 if nic_params.get("nic_mode") == "tap":
859 return port
lmr6f669ce2009-05-31 19:02:42 +0000860 else:
lmrf4696342009-08-13 04:06:33 +0000861 if not self.redirs.has_key(port):
862 logging.warn("Warning: guest port %s requested but not "
863 "redirected" % port)
864 return self.redirs.get(port)
lmr6f669ce2009-05-31 19:02:42 +0000865
866
lmra4967622009-07-23 01:36:32 +0000867 def get_pid(self):
868 """
lmr71fa4de2010-06-14 15:54:55 +0000869 Return the VM's PID. If the VM is dead return None.
870
871 @note: This works under the assumption that self.process.get_pid()
872 returns the PID of the parent shell process.
873 """
874 try:
875 children = commands.getoutput("ps --ppid=%d -o pid=" %
876 self.process.get_pid()).split()
877 return int(children[0])
878 except (TypeError, IndexError, ValueError):
879 return None
880
881
882 def get_shell_pid(self):
883 """
884 Return the PID of the parent shell process.
885
886 @note: This works under the assumption that self.process.get_pid()
887 returns the PID of the parent shell process.
lmra4967622009-07-23 01:36:32 +0000888 """
889 return self.process.get_pid()
890
891
lmr0bee2342010-02-24 00:01:37 +0000892 def get_shared_meminfo(self):
893 """
894 Returns the VM's shared memory information.
895
896 @return: Shared memory used by VM (MB)
897 """
898 if self.is_dead():
899 logging.error("Could not get shared memory info from dead VM.")
900 return None
901
lmr983ecdf2010-06-14 15:57:12 +0000902 filename = "/proc/%d/statm" % self.get_pid()
903 shm = int(open(filename).read().split()[2])
lmr0bee2342010-02-24 00:01:37 +0000904 # statm stores informations in pages, translate it to MB
lmr983ecdf2010-06-14 15:57:12 +0000905 return shm * 4.0 / 1024
lmr0bee2342010-02-24 00:01:37 +0000906
907
lmr912c74b2009-08-17 20:43:27 +0000908 def remote_login(self, nic_index=0, timeout=10):
lmr6f669ce2009-05-31 19:02:42 +0000909 """
lmr912c74b2009-08-17 20:43:27 +0000910 Log into the guest via SSH/Telnet/Netcat.
lmr6f669ce2009-05-31 19:02:42 +0000911 If timeout expires while waiting for output from the guest (e.g. a
912 password prompt or a shell prompt) -- fail.
913
lmree90dd92009-08-13 04:13:39 +0000914 @param nic_index: The index of the NIC to connect to.
lmr6f669ce2009-05-31 19:02:42 +0000915 @param timeout: Time (seconds) before giving up logging into the
916 guest.
917 @return: kvm_spawn object on success and None on failure.
918 """
919 username = self.params.get("username", "")
920 password = self.params.get("password", "")
lmr912c74b2009-08-17 20:43:27 +0000921 prompt = self.params.get("shell_prompt", "[\#\$]")
lmr59f9e2d2009-10-05 18:47:16 +0000922 linesep = eval("'%s'" % self.params.get("shell_linesep", r"\n"))
lmr912c74b2009-08-17 20:43:27 +0000923 client = self.params.get("shell_client")
lmree90dd92009-08-13 04:13:39 +0000924 address = self.get_address(nic_index)
lmr912c74b2009-08-17 20:43:27 +0000925 port = self.get_port(int(self.params.get("shell_port")))
lmre56903f2010-06-22 02:09:35 +0000926 log_filename = ("session-%s-%s.log" %
927 (self.name, kvm_utils.generate_random_string(4)))
lmr912c74b2009-08-17 20:43:27 +0000928
lmree90dd92009-08-13 04:13:39 +0000929 if not address or not port:
930 logging.debug("IP address or port unavailable")
lmr6f669ce2009-05-31 19:02:42 +0000931 return None
932
lmr158604f2010-06-22 01:57:34 +0000933 session = kvm_utils.remote_login(client, address, port, username,
lmre56903f2010-06-22 02:09:35 +0000934 password, prompt, linesep,
935 log_filename, timeout)
lmr912c74b2009-08-17 20:43:27 +0000936
lmr6f669ce2009-05-31 19:02:42 +0000937 if session:
lmr912c74b2009-08-17 20:43:27 +0000938 session.set_status_test_command(self.params.get("status_test_"
lmr6f669ce2009-05-31 19:02:42 +0000939 "command", ""))
940 return session
941
942
lmrc196d492010-05-07 14:14:26 +0000943 def copy_files_to(self, local_path, remote_path, nic_index=0, timeout=600):
lmr6f669ce2009-05-31 19:02:42 +0000944 """
lmr912c74b2009-08-17 20:43:27 +0000945 Transfer files to the guest.
lmr6f669ce2009-05-31 19:02:42 +0000946
947 @param local_path: Host path
948 @param remote_path: Guest path
lmr912c74b2009-08-17 20:43:27 +0000949 @param nic_index: The index of the NIC to connect to.
lmr6f669ce2009-05-31 19:02:42 +0000950 @param timeout: Time (seconds) before giving up on doing the remote
951 copy.
952 """
953 username = self.params.get("username", "")
954 password = self.params.get("password", "")
lmr912c74b2009-08-17 20:43:27 +0000955 client = self.params.get("file_transfer_client")
lmree90dd92009-08-13 04:13:39 +0000956 address = self.get_address(nic_index)
lmr912c74b2009-08-17 20:43:27 +0000957 port = self.get_port(int(self.params.get("file_transfer_port")))
lmre56903f2010-06-22 02:09:35 +0000958 log_filename = ("scp-%s-%s.log" %
959 (self.name, kvm_utils.generate_random_string(4)))
lmr912c74b2009-08-17 20:43:27 +0000960
lmree90dd92009-08-13 04:13:39 +0000961 if not address or not port:
962 logging.debug("IP address or port unavailable")
lmr6f669ce2009-05-31 19:02:42 +0000963 return None
lmr912c74b2009-08-17 20:43:27 +0000964
965 if client == "scp":
966 return kvm_utils.scp_to_remote(address, port, username, password,
lmre56903f2010-06-22 02:09:35 +0000967 local_path, remote_path,
968 log_filename, timeout)
lmr6f669ce2009-05-31 19:02:42 +0000969
970
lmrc196d492010-05-07 14:14:26 +0000971 def copy_files_from(self, remote_path, local_path, nic_index=0, timeout=600):
lmr6f669ce2009-05-31 19:02:42 +0000972 """
lmr912c74b2009-08-17 20:43:27 +0000973 Transfer files from the guest.
lmr6f669ce2009-05-31 19:02:42 +0000974
975 @param local_path: Guest path
976 @param remote_path: Host path
lmr912c74b2009-08-17 20:43:27 +0000977 @param nic_index: The index of the NIC to connect to.
lmr6f669ce2009-05-31 19:02:42 +0000978 @param timeout: Time (seconds) before giving up on doing the remote
979 copy.
980 """
981 username = self.params.get("username", "")
982 password = self.params.get("password", "")
lmr912c74b2009-08-17 20:43:27 +0000983 client = self.params.get("file_transfer_client")
lmree90dd92009-08-13 04:13:39 +0000984 address = self.get_address(nic_index)
lmr912c74b2009-08-17 20:43:27 +0000985 port = self.get_port(int(self.params.get("file_transfer_port")))
lmre56903f2010-06-22 02:09:35 +0000986 log_filename = ("scp-%s-%s.log" %
987 (self.name, kvm_utils.generate_random_string(4)))
lmr912c74b2009-08-17 20:43:27 +0000988
lmree90dd92009-08-13 04:13:39 +0000989 if not address or not port:
990 logging.debug("IP address or port unavailable")
lmr6f669ce2009-05-31 19:02:42 +0000991 return None
lmr6f669ce2009-05-31 19:02:42 +0000992
lmr912c74b2009-08-17 20:43:27 +0000993 if client == "scp":
994 return kvm_utils.scp_from_remote(address, port, username, password,
lmre56903f2010-06-22 02:09:35 +0000995 remote_path, local_path,
996 log_filename, timeout)
lmr6f669ce2009-05-31 19:02:42 +0000997
998
lmraa380a22010-06-22 02:05:29 +0000999 def serial_login(self, timeout=10):
1000 """
1001 Log into the guest via the serial console.
1002 If timeout expires while waiting for output from the guest (e.g. a
1003 password prompt or a shell prompt) -- fail.
1004
1005 @param timeout: Time (seconds) before giving up logging into the guest.
1006 @return: kvm_spawn object on success and None on failure.
1007 """
1008 username = self.params.get("username", "")
1009 password = self.params.get("password", "")
1010 prompt = self.params.get("shell_prompt", "[\#\$]")
1011 linesep = eval("'%s'" % self.params.get("shell_linesep", r"\n"))
1012 status_test_command = self.params.get("status_test_command", "")
1013
1014 if self.serial_console:
1015 self.serial_console.set_linesep(linesep)
1016 self.serial_console.set_status_test_command(status_test_command)
1017 else:
1018 return None
1019
1020 # Make sure we get a login prompt
1021 self.serial_console.sendline()
1022
1023 if kvm_utils._remote_login(self.serial_console, username, password,
1024 prompt, timeout):
1025 return self.serial_console
1026
1027
lmr6f669ce2009-05-31 19:02:42 +00001028 def send_key(self, keystr):
1029 """
1030 Send a key event to the VM.
1031
1032 @param: keystr: A key event string (e.g. "ctrl-alt-delete")
1033 """
1034 # For compatibility with versions of QEMU that do not recognize all
1035 # key names: replace keyname with the hex value from the dict, which
1036 # QEMU will definitely accept
lmr9e964a02010-06-18 03:46:21 +00001037 dict = {"comma": "0x33",
1038 "dot": "0x34",
1039 "slash": "0x35"}
1040 for key, value in dict.items():
1041 keystr = keystr.replace(key, value)
1042 self.monitor.sendkey(keystr)
lmr6f669ce2009-05-31 19:02:42 +00001043 time.sleep(0.2)
1044
1045
1046 def send_string(self, str):
1047 """
1048 Send a string to the VM.
1049
1050 @param str: String, that must consist of alphanumeric characters only.
1051 Capital letters are allowed.
1052 """
1053 for char in str:
1054 if char.isupper():
1055 self.send_key("shift-%s" % char.lower())
1056 else:
1057 self.send_key(char)
lmra2533222009-07-20 12:43:46 +00001058
mbligh1ef218d2009-08-03 16:57:56 +00001059
lmra2533222009-07-20 12:43:46 +00001060 def get_uuid(self):
1061 """
1062 Catch UUID of the VM.
1063
1064 @return: None,if not specified in config file
1065 """
1066 if self.params.get("uuid") == "random":
1067 return self.uuid
1068 else:
1069 return self.params.get("uuid", None)
lmrdd2ff922009-12-01 23:39:12 +00001070
1071
1072 def get_cpu_count(self):
1073 """
1074 Get the cpu count of the VM.
1075 """
lmr13426552010-01-17 15:38:41 +00001076 session = self.remote_login()
1077 if not session:
1078 return None
lmrdd2ff922009-12-01 23:39:12 +00001079 try:
lmr13426552010-01-17 15:38:41 +00001080 cmd = self.params.get("cpu_chk_cmd")
1081 s, count = session.get_command_status_output(cmd)
1082 if s == 0:
1083 return int(count)
lmrdd2ff922009-12-01 23:39:12 +00001084 return None
1085 finally:
1086 session.close()
1087
1088
lmr28426c82010-04-16 06:02:58 +00001089 def get_memory_size(self, cmd=None):
lmrdd2ff922009-12-01 23:39:12 +00001090 """
lmr28426c82010-04-16 06:02:58 +00001091 Get bootup memory size of the VM.
1092
1093 @param check_cmd: Command used to check memory. If not provided,
1094 self.params.get("mem_chk_cmd") will be used.
lmrdd2ff922009-12-01 23:39:12 +00001095 """
lmr13426552010-01-17 15:38:41 +00001096 session = self.remote_login()
1097 if not session:
lmrdd2ff922009-12-01 23:39:12 +00001098 return None
lmr13426552010-01-17 15:38:41 +00001099 try:
lmr28426c82010-04-16 06:02:58 +00001100 if not cmd:
1101 cmd = self.params.get("mem_chk_cmd")
lmr13426552010-01-17 15:38:41 +00001102 s, mem_str = session.get_command_status_output(cmd)
1103 if s != 0:
1104 return None
lmr6d69f4d2010-02-12 11:35:55 +00001105 mem = re.findall("([0-9]+)", mem_str)
lmr13426552010-01-17 15:38:41 +00001106 mem_size = 0
1107 for m in mem:
1108 mem_size += int(m)
1109 if "GB" in mem_str:
1110 mem_size *= 1024
1111 elif "MB" in mem_str:
1112 pass
1113 else:
1114 mem_size /= 1024
1115 return int(mem_size)
lmrdd2ff922009-12-01 23:39:12 +00001116 finally:
1117 session.close()
lmr28426c82010-04-16 06:02:58 +00001118
1119
1120 def get_current_memory_size(self):
1121 """
1122 Get current memory size of the VM, rather than bootup memory.
1123 """
1124 cmd = self.params.get("mem_chk_cur_cmd")
1125 return self.get_memory_size(cmd)