blob: cb4666b7bc4e50ed6343983c50c4c2bab66a3a98 [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
lmr48abd7d2010-05-26 13:48:04 +0000209 def add_mem(help, mem):
210 return " -m %s" % mem
211
212 def add_smp(help, smp):
213 return " -smp %s" % smp
214
215 def add_cdrom(help, filename, index=2):
216 if has_option(help, "drive"):
lmr09a78162010-06-14 16:29:23 +0000217 return " -drive file='%s',index=%d,media=cdrom" % (filename,
218 index)
lmr48abd7d2010-05-26 13:48:04 +0000219 else:
lmr09a78162010-06-14 16:29:23 +0000220 return " -cdrom '%s'" % filename
lmr48abd7d2010-05-26 13:48:04 +0000221
222 def add_drive(help, filename, format=None, cache=None, werror=None,
223 serial=None, snapshot=False, boot=False):
lmr09a78162010-06-14 16:29:23 +0000224 cmd = " -drive file='%s'" % filename
lmr48abd7d2010-05-26 13:48:04 +0000225 if format: cmd += ",if=%s" % format
226 if cache: cmd += ",cache=%s" % cache
227 if werror: cmd += ",werror=%s" % werror
lmr09a78162010-06-14 16:29:23 +0000228 if serial: cmd += ",serial='%s'" % serial
lmr48abd7d2010-05-26 13:48:04 +0000229 if snapshot: cmd += ",snapshot=on"
230 if boot: cmd += ",boot=on"
231 return cmd
232
lmrb1cad1e2010-06-17 17:36:09 +0000233 def add_nic(help, vlan, model=None, mac=None, netdev_id=None):
lmr48abd7d2010-05-26 13:48:04 +0000234 cmd = " -net nic,vlan=%d" % vlan
lmrb1cad1e2010-06-17 17:36:09 +0000235 if has_option(help, "netdev"):
236 cmd +=",netdev=%s" % netdev_id
lmr48abd7d2010-05-26 13:48:04 +0000237 if model: cmd += ",model=%s" % model
lmr09a78162010-06-14 16:29:23 +0000238 if mac: cmd += ",macaddr='%s'" % mac
lmr48abd7d2010-05-26 13:48:04 +0000239 return cmd
240
241 def add_net(help, vlan, mode, ifname=None, script=None,
lmrb1cad1e2010-06-17 17:36:09 +0000242 downscript=None, netdev_id=None):
243 if has_option(help, "netdev"):
244 cmd = " -netdev %s,id=%s" % (mode, netdev_id)
245 else:
246 cmd = " -net %s,vlan=%d" % (mode, vlan)
lmr48abd7d2010-05-26 13:48:04 +0000247 if mode == "tap":
lmr09a78162010-06-14 16:29:23 +0000248 if ifname: cmd += ",ifname='%s'" % ifname
249 if script: cmd += ",script='%s'" % script
250 cmd += ",downscript='%s'" % (downscript or "no")
lmr48abd7d2010-05-26 13:48:04 +0000251 return cmd
252
253 def add_floppy(help, filename):
lmr09a78162010-06-14 16:29:23 +0000254 return " -fda '%s'" % filename
lmr48abd7d2010-05-26 13:48:04 +0000255
256 def add_tftp(help, filename):
lmr09a78162010-06-14 16:29:23 +0000257 return " -tftp '%s'" % filename
lmr48abd7d2010-05-26 13:48:04 +0000258
259 def add_tcp_redir(help, host_port, guest_port):
260 return " -redir tcp:%s::%s" % (host_port, guest_port)
261
262 def add_vnc(help, vnc_port):
263 return " -vnc :%d" % (vnc_port - 5900)
264
265 def add_sdl(help):
266 if has_option(help, "sdl"):
267 return " -sdl"
268 else:
269 return ""
270
271 def add_nographic(help):
272 return " -nographic"
273
274 def add_uuid(help, uuid):
lmr09a78162010-06-14 16:29:23 +0000275 return " -uuid '%s'" % uuid
lmr48abd7d2010-05-26 13:48:04 +0000276
277 def add_pcidevice(help, host):
lmr09a78162010-06-14 16:29:23 +0000278 return " -pcidevice host='%s'" % host
lmr48abd7d2010-05-26 13:48:04 +0000279
lmr41cb8fc2010-06-10 15:30:45 +0000280 def add_kernel(help, filename):
lmr09a78162010-06-14 16:29:23 +0000281 return " -kernel '%s'" % filename
lmr41cb8fc2010-06-10 15:30:45 +0000282
283 def add_initrd(help, filename):
lmr09a78162010-06-14 16:29:23 +0000284 return " -initrd '%s'" % filename
lmr41cb8fc2010-06-10 15:30:45 +0000285
lmr48abd7d2010-05-26 13:48:04 +0000286 # End of command line option wrappers
287
288 if name is None: name = self.name
289 if params is None: params = self.params
290 if root_dir is None: root_dir = self.root_dir
291
292 qemu_binary = kvm_utils.get_path(root_dir, params.get("qemu_binary",
293 "qemu"))
294 # Get the output of 'qemu -help' (log a message in case this call never
295 # returns or causes some other kind of trouble)
296 logging.debug("Getting output of 'qemu -help'")
297 help = commands.getoutput("%s -help" % qemu_binary)
lmr6f669ce2009-05-31 19:02:42 +0000298
lmreeff0eb2009-06-10 19:19:15 +0000299 # Start constructing the qemu command
300 qemu_cmd = ""
301 # Set the X11 display parameter if requested
302 if params.get("x11_display"):
303 qemu_cmd += "DISPLAY=%s " % params.get("x11_display")
304 # Add the qemu binary
lmr48abd7d2010-05-26 13:48:04 +0000305 qemu_cmd += qemu_binary
lmreeff0eb2009-06-10 19:19:15 +0000306 # Add the VM's name
lmr48abd7d2010-05-26 13:48:04 +0000307 qemu_cmd += add_name(help, name)
lmr9e964a02010-06-18 03:46:21 +0000308 # Add monitors
309 for monitor_name in kvm_utils.get_sub_dict_names(params, "monitors"):
310 monitor_params = kvm_utils.get_sub_dict(params, monitor_name)
311 monitor_filename = self.get_monitor_filename(monitor_name)
312 if monitor_params.get("monitor_type") == "qmp":
313 qemu_cmd += add_qmp_monitor(help, monitor_filename)
314 else:
315 qemu_cmd += add_human_monitor(help, monitor_filename)
lmr6f669ce2009-05-31 19:02:42 +0000316
317 for image_name in kvm_utils.get_sub_dict_names(params, "images"):
318 image_params = kvm_utils.get_sub_dict(params, image_name)
lmr9d75ee32009-09-29 13:14:13 +0000319 if image_params.get("boot_drive") == "no":
320 continue
lmr48abd7d2010-05-26 13:48:04 +0000321 qemu_cmd += add_drive(help,
322 get_image_filename(image_params, root_dir),
323 image_params.get("drive_format"),
324 image_params.get("drive_cache"),
325 image_params.get("drive_werror"),
326 image_params.get("drive_serial"),
327 image_params.get("image_snapshot") == "yes",
328 image_params.get("image_boot") == "yes")
lmr6f669ce2009-05-31 19:02:42 +0000329
330 vlan = 0
331 for nic_name in kvm_utils.get_sub_dict_names(params, "nics"):
332 nic_params = kvm_utils.get_sub_dict(params, nic_name)
lmrf4696342009-08-13 04:06:33 +0000333 # Handle the '-net nic' part
lmr48abd7d2010-05-26 13:48:04 +0000334 mac = None
335 if "address_index" in nic_params:
336 mac = kvm_utils.get_mac_ip_pair_from_dict(nic_params)[0]
lmrb1cad1e2010-06-17 17:36:09 +0000337 qemu_cmd += add_nic(help, vlan, nic_params.get("nic_model"), mac,
338 self.netdev_id[vlan])
lmrf4696342009-08-13 04:06:33 +0000339 # Handle the '-net tap' or '-net user' part
lmre4eaa862010-06-01 19:15:14 +0000340 script = nic_params.get("nic_script")
341 downscript = nic_params.get("nic_downscript")
lmr48abd7d2010-05-26 13:48:04 +0000342 if script:
343 script = kvm_utils.get_path(root_dir, script)
344 if downscript:
345 downscript = kvm_utils.get_path(root_dir, downscript)
346 qemu_cmd += add_net(help, vlan, nic_params.get("nic_mode", "user"),
347 nic_params.get("nic_ifname"),
lmrb1cad1e2010-06-17 17:36:09 +0000348 script, downscript, self.netdev_id[vlan])
lmrf4696342009-08-13 04:06:33 +0000349 # Proceed to next NIC
lmr6f669ce2009-05-31 19:02:42 +0000350 vlan += 1
351
352 mem = params.get("mem")
353 if mem:
lmr48abd7d2010-05-26 13:48:04 +0000354 qemu_cmd += add_mem(help, mem)
lmr6f669ce2009-05-31 19:02:42 +0000355
lmrc43bf372009-11-10 13:19:00 +0000356 smp = params.get("smp")
357 if smp:
lmrdb3fe612010-06-14 16:19:28 +0000358 qemu_cmd += add_smp(help, smp)
lmrc43bf372009-11-10 13:19:00 +0000359
lmr6f669ce2009-05-31 19:02:42 +0000360 iso = params.get("cdrom")
361 if iso:
lmr90b9fd52009-08-17 20:48:18 +0000362 iso = kvm_utils.get_path(root_dir, iso)
lmr48abd7d2010-05-26 13:48:04 +0000363 qemu_cmd += add_cdrom(help, iso)
lmr89fd6412010-01-18 02:42:57 +0000364
365 # Even though this is not a really scalable approach,
366 # it doesn't seem like we are going to need more than
367 # 2 CDs active on the same VM.
368 iso_extra = params.get("cdrom_extra")
369 if iso_extra:
370 iso_extra = kvm_utils.get_path(root_dir, iso_extra)
lmr48abd7d2010-05-26 13:48:04 +0000371 qemu_cmd += add_cdrom(help, iso_extra, 3)
lmr6f669ce2009-05-31 19:02:42 +0000372
lmrb0a9b762009-10-09 20:43:30 +0000373 # We may want to add {floppy_otps} parameter for -fda
lmr48abd7d2010-05-26 13:48:04 +0000374 # {fat:floppy:}/path/. However vvfat is not usually recommended.
lmrb0a9b762009-10-09 20:43:30 +0000375 floppy = params.get("floppy")
376 if floppy:
lmrf69f6b12009-11-10 16:33:44 +0000377 floppy = kvm_utils.get_path(root_dir, floppy)
lmr48abd7d2010-05-26 13:48:04 +0000378 qemu_cmd += add_floppy(help, floppy)
lmrb0a9b762009-10-09 20:43:30 +0000379
380 tftp = params.get("tftp")
381 if tftp:
lmrf69f6b12009-11-10 16:33:44 +0000382 tftp = kvm_utils.get_path(root_dir, tftp)
lmr48abd7d2010-05-26 13:48:04 +0000383 qemu_cmd += add_tftp(help, tftp)
lmr6f669ce2009-05-31 19:02:42 +0000384
lmr41cb8fc2010-06-10 15:30:45 +0000385 kernel = params.get("kernel")
386 if kernel:
387 kernel = kvm_utils.get_path(root_dir, kernel)
388 qemu_cmd += add_kernel(help, kernel)
389
390 initrd = params.get("initrd")
391 if initrd:
392 initrd = kvm_utils.get_path(root_dir, initrd)
393 qemu_cmd += add_initrd(help, initrd)
394
lmr6f669ce2009-05-31 19:02:42 +0000395 for redir_name in kvm_utils.get_sub_dict_names(params, "redirs"):
396 redir_params = kvm_utils.get_sub_dict(params, redir_name)
397 guest_port = int(redir_params.get("guest_port"))
lmrf4696342009-08-13 04:06:33 +0000398 host_port = self.redirs.get(guest_port)
lmr48abd7d2010-05-26 13:48:04 +0000399 qemu_cmd += add_tcp_redir(help, host_port, guest_port)
lmr6f669ce2009-05-31 19:02:42 +0000400
401 if params.get("display") == "vnc":
lmr48abd7d2010-05-26 13:48:04 +0000402 qemu_cmd += add_vnc(help, self.vnc_port)
lmr6f669ce2009-05-31 19:02:42 +0000403 elif params.get("display") == "sdl":
lmr48abd7d2010-05-26 13:48:04 +0000404 qemu_cmd += add_sdl(help)
lmr6f669ce2009-05-31 19:02:42 +0000405 elif params.get("display") == "nographic":
lmr48abd7d2010-05-26 13:48:04 +0000406 qemu_cmd += add_nographic(help)
lmr6f669ce2009-05-31 19:02:42 +0000407
lmra2533222009-07-20 12:43:46 +0000408 if params.get("uuid") == "random":
lmr48abd7d2010-05-26 13:48:04 +0000409 qemu_cmd += add_uuid(help, self.uuid)
lmra2533222009-07-20 12:43:46 +0000410 elif params.get("uuid"):
lmr48abd7d2010-05-26 13:48:04 +0000411 qemu_cmd += add_uuid(help, params.get("uuid"))
lmra2533222009-07-20 12:43:46 +0000412
lmr31af3a12010-01-18 16:46:52 +0000413 # If the PCI assignment step went OK, add each one of the PCI assigned
414 # devices to the qemu command line.
415 if self.pci_assignable:
416 for pci_id in self.pa_pci_ids:
lmr48abd7d2010-05-26 13:48:04 +0000417 qemu_cmd += add_pcidevice(help, pci_id)
418
419 extra_params = params.get("extra_params")
420 if extra_params:
421 qemu_cmd += " %s" % extra_params
lmr31af3a12010-01-18 16:46:52 +0000422
lmr6f669ce2009-05-31 19:02:42 +0000423 return qemu_cmd
424
425
lmr52800ba2009-08-17 20:49:58 +0000426 def create(self, name=None, params=None, root_dir=None,
lmr1424f3e2010-06-17 13:57:09 +0000427 for_migration=False, timeout=5.0, extra_params=None):
lmr6f669ce2009-05-31 19:02:42 +0000428 """
429 Start the VM by running a qemu command.
430 All parameters are optional. The following applies to all parameters
431 but for_migration: If a parameter is not supplied, the corresponding
432 value stored in the class attributes is used, and if it is supplied,
433 it is stored for later use.
434
435 @param name: The name of the object
436 @param params: A dict containing VM params
lmr90b9fd52009-08-17 20:48:18 +0000437 @param root_dir: Base directory for relative filenames
lmr6f669ce2009-05-31 19:02:42 +0000438 @param for_migration: If True, start the VM with the -incoming
439 option
lmr1424f3e2010-06-17 13:57:09 +0000440 @param extra_params: extra params for qemu command.e.g -incoming option
441 Please use this parameter instead of for_migration.
lmr6f669ce2009-05-31 19:02:42 +0000442 """
lmr135b5e62009-06-10 19:22:31 +0000443 self.destroy()
444
lmre45a1f22009-11-10 16:35:08 +0000445 if name is not None:
lmr6f669ce2009-05-31 19:02:42 +0000446 self.name = name
lmre45a1f22009-11-10 16:35:08 +0000447 if params is not None:
lmr6f669ce2009-05-31 19:02:42 +0000448 self.params = params
lmre45a1f22009-11-10 16:35:08 +0000449 if root_dir is not None:
lmr90b9fd52009-08-17 20:48:18 +0000450 self.root_dir = root_dir
lmr6f669ce2009-05-31 19:02:42 +0000451 name = self.name
452 params = self.params
lmr90b9fd52009-08-17 20:48:18 +0000453 root_dir = self.root_dir
lmr6f669ce2009-05-31 19:02:42 +0000454
455 # Verify the md5sum of the ISO image
456 iso = params.get("cdrom")
457 if iso:
lmr90b9fd52009-08-17 20:48:18 +0000458 iso = kvm_utils.get_path(root_dir, iso)
lmr6f669ce2009-05-31 19:02:42 +0000459 if not os.path.exists(iso):
460 logging.error("ISO file not found: %s" % iso)
461 return False
462 compare = False
463 if params.get("md5sum_1m"):
lmrf4696342009-08-13 04:06:33 +0000464 logging.debug("Comparing expected MD5 sum with MD5 sum of "
465 "first MB of ISO file...")
lmrd60882f2010-02-04 03:26:36 +0000466 actual_hash = utils.hash_file(iso, 1048576, method="md5")
lmr03ba22e2009-10-23 12:07:44 +0000467 expected_hash = params.get("md5sum_1m")
lmr6f669ce2009-05-31 19:02:42 +0000468 compare = True
469 elif params.get("md5sum"):
lmrf4696342009-08-13 04:06:33 +0000470 logging.debug("Comparing expected MD5 sum with MD5 sum of ISO "
471 "file...")
lmrd60882f2010-02-04 03:26:36 +0000472 actual_hash = utils.hash_file(iso, method="md5")
lmr03ba22e2009-10-23 12:07:44 +0000473 expected_hash = params.get("md5sum")
474 compare = True
475 elif params.get("sha1sum"):
476 logging.debug("Comparing expected SHA1 sum with SHA1 sum of "
477 "ISO file...")
lmrd60882f2010-02-04 03:26:36 +0000478 actual_hash = utils.hash_file(iso, method="sha1")
lmrea1266e2009-11-10 16:41:08 +0000479 expected_hash = params.get("sha1sum")
lmr6f669ce2009-05-31 19:02:42 +0000480 compare = True
481 if compare:
lmr03ba22e2009-10-23 12:07:44 +0000482 if actual_hash == expected_hash:
483 logging.debug("Hashes match")
lmr6f669ce2009-05-31 19:02:42 +0000484 else:
lmr03ba22e2009-10-23 12:07:44 +0000485 logging.error("Actual hash differs from expected one")
lmr6f669ce2009-05-31 19:02:42 +0000486 return False
487
lmrdc2ac6a2009-06-10 19:15:49 +0000488 # Make sure the following code is not executed by more than one thread
489 # at the same time
490 lockfile = open("/tmp/kvm-autotest-vm-create.lock", "w+")
491 fcntl.lockf(lockfile, fcntl.LOCK_EX)
lmr6f669ce2009-05-31 19:02:42 +0000492
lmrdc2ac6a2009-06-10 19:15:49 +0000493 try:
494 # Handle port redirections
495 redir_names = kvm_utils.get_sub_dict_names(params, "redirs")
496 host_ports = kvm_utils.find_free_ports(5000, 6000, len(redir_names))
497 self.redirs = {}
498 for i in range(len(redir_names)):
499 redir_params = kvm_utils.get_sub_dict(params, redir_names[i])
500 guest_port = int(redir_params.get("guest_port"))
501 self.redirs[guest_port] = host_ports[i]
lmr6f669ce2009-05-31 19:02:42 +0000502
lmrdc2ac6a2009-06-10 19:15:49 +0000503 # Find available VNC port, if needed
504 if params.get("display") == "vnc":
lmrc0da8902010-05-17 20:31:36 +0000505 self.vnc_port = kvm_utils.find_free_port(5900, 6100)
lmr6f669ce2009-05-31 19:02:42 +0000506
lmra2533222009-07-20 12:43:46 +0000507 # Find random UUID if specified 'uuid = random' in config file
508 if params.get("uuid") == "random":
509 f = open("/proc/sys/kernel/random/uuid")
510 self.uuid = f.read().strip()
511 f.close()
512
lmr31ed61d2010-06-07 13:21:38 +0000513 # Assign a PCI assignable device
514 self.pci_assignable = None
515 pa_type = params.get("pci_assignable")
516 if pa_type in ["vf", "pf", "mixed"]:
lmr31af3a12010-01-18 16:46:52 +0000517 pa_devices_requested = params.get("devices_requested")
518
519 # Virtual Functions (VF) assignable devices
520 if pa_type == "vf":
lmr31ed61d2010-06-07 13:21:38 +0000521 self.pci_assignable = kvm_utils.PciAssignable(
522 type=pa_type,
523 driver=params.get("driver"),
524 driver_option=params.get("driver_option"),
525 devices_requested=pa_devices_requested)
lmr31af3a12010-01-18 16:46:52 +0000526 # Physical NIC (PF) assignable devices
527 elif pa_type == "pf":
lmr31ed61d2010-06-07 13:21:38 +0000528 self.pci_assignable = kvm_utils.PciAssignable(
529 type=pa_type,
530 names=params.get("device_names"),
531 devices_requested=pa_devices_requested)
lmr31af3a12010-01-18 16:46:52 +0000532 # Working with both VF and PF
533 elif pa_type == "mixed":
lmr31ed61d2010-06-07 13:21:38 +0000534 self.pci_assignable = kvm_utils.PciAssignable(
535 type=pa_type,
536 driver=params.get("driver"),
537 driver_option=params.get("driver_option"),
538 names=params.get("device_names"),
539 devices_requested=pa_devices_requested)
lmr31af3a12010-01-18 16:46:52 +0000540
541 self.pa_pci_ids = self.pci_assignable.request_devs()
542
543 if self.pa_pci_ids:
lmr31ed61d2010-06-07 13:21:38 +0000544 logging.debug("Successfuly assigned devices: %s",
lmr31af3a12010-01-18 16:46:52 +0000545 self.pa_pci_ids)
546 else:
547 logging.error("No PCI assignable devices were assigned "
548 "and 'pci_assignable' is defined to %s "
lmr31ed61d2010-06-07 13:21:38 +0000549 "on your config file. Aborting VM creation.",
lmr31af3a12010-01-18 16:46:52 +0000550 pa_type)
551 return False
552
lmr856d58c2010-06-08 18:29:31 +0000553 elif pa_type and pa_type != "no":
lmr31ed61d2010-06-07 13:21:38 +0000554 logging.warn("Unsupported pci_assignable type: %s", pa_type)
lmr31af3a12010-01-18 16:46:52 +0000555
lmrdc2ac6a2009-06-10 19:15:49 +0000556 # Make qemu command
557 qemu_command = self.make_qemu_command()
lmr6f669ce2009-05-31 19:02:42 +0000558
lmr1424f3e2010-06-17 13:57:09 +0000559 # Enable migration support for VM by adding extra_params.
560 if extra_params is not None:
561 if " -incoming tcp:0:%d" == extra_params:
562 self.migration_port = kvm_utils.find_free_port(5200, 6000)
563 qemu_command += extra_params % self.migration_port
564 elif " -incoming unix:%s" == extra_params:
565 self.migration_file = os.path.join("/tmp/", "unix-" +
566 time.strftime("%Y%m%d-%H%M%S"))
567 qemu_command += extra_params % self.migration_file
568 else:
569 qemu_command += extra_params
lmr6f669ce2009-05-31 19:02:42 +0000570
lmrdc2ac6a2009-06-10 19:15:49 +0000571 logging.debug("Running qemu command:\n%s", qemu_command)
lmra4967622009-07-23 01:36:32 +0000572 self.process = kvm_subprocess.run_bg(qemu_command, None,
573 logging.debug, "(qemu) ")
lmr6f669ce2009-05-31 19:02:42 +0000574
lmr9e964a02010-06-18 03:46:21 +0000575 # Make sure the process was started successfully
lmra4967622009-07-23 01:36:32 +0000576 if not self.process.is_alive():
577 logging.error("VM could not be created; "
578 "qemu command failed:\n%s" % qemu_command)
579 logging.error("Status: %s" % self.process.get_status())
580 logging.error("Output:" + kvm_utils.format_str_for_message(
581 self.process.get_output()))
lmrdc2ac6a2009-06-10 19:15:49 +0000582 self.destroy()
583 return False
lmr6f669ce2009-05-31 19:02:42 +0000584
lmr9e964a02010-06-18 03:46:21 +0000585 # Establish monitor connections
586 self.monitors = []
587 for monitor_name in kvm_utils.get_sub_dict_names(params,
588 "monitors"):
589 monitor_params = kvm_utils.get_sub_dict(params, monitor_name)
590 # Wait for monitor connection to succeed
591 end_time = time.time() + timeout
592 while time.time() < end_time:
593 try:
594 if monitor_params.get("monitor_type") == "qmp":
595 # Add a QMP monitor: not implemented yet
596 monitor = None
597 else:
598 # Add a "human" monitor
599 monitor = kvm_monitor.HumanMonitor(
600 monitor_name,
601 self.get_monitor_filename(monitor_name))
602 except kvm_monitor.MonitorError, e:
603 logging.warn(e)
604 else:
605 if monitor and monitor.is_responsive():
606 break
607 time.sleep(1)
608 else:
609 logging.error("Could not connect to monitor '%s'" %
610 monitor_name)
611 self.destroy()
612 return False
613 # Add this monitor to the list
614 self.monitors += [monitor]
lmra4967622009-07-23 01:36:32 +0000615
lmrfe6515e2009-07-29 13:01:17 +0000616 # Get the output so far, to see if we have any problems with
617 # hugepage setup.
618 output = self.process.get_output()
619
620 if "alloc_mem_area" in output:
621 logging.error("Could not allocate hugepage memory; "
622 "qemu command:\n%s" % qemu_command)
623 logging.error("Output:" + kvm_utils.format_str_for_message(
624 self.process.get_output()))
lmr090cd7a2010-04-01 02:18:52 +0000625 self.destroy()
lmrfe6515e2009-07-29 13:01:17 +0000626 return False
627
lmr71fa4de2010-06-14 15:54:55 +0000628 logging.debug("VM appears to be alive with PID %s", self.get_pid())
lmrdc2ac6a2009-06-10 19:15:49 +0000629 return True
630
631 finally:
632 fcntl.lockf(lockfile, fcntl.LOCK_UN)
633 lockfile.close()
lmr6f669ce2009-05-31 19:02:42 +0000634
635
lmr6f669ce2009-05-31 19:02:42 +0000636 def destroy(self, gracefully=True):
637 """
638 Destroy the VM.
639
lmr912c74b2009-08-17 20:43:27 +0000640 If gracefully is True, first attempt to shutdown the VM with a shell
641 command. Then, attempt to destroy the VM via the monitor with a 'quit'
642 command. If that fails, send SIGKILL to the qemu process.
lmr6f669ce2009-05-31 19:02:42 +0000643
644 @param gracefully: Whether an attempt will be made to end the VM
lmr912c74b2009-08-17 20:43:27 +0000645 using a shell command before trying to end the qemu process
646 with a 'quit' or a kill signal.
lmr6f669ce2009-05-31 19:02:42 +0000647 """
lmrf320b042009-09-15 05:48:06 +0000648 try:
649 # Is it already dead?
650 if self.is_dead():
651 logging.debug("VM is already down")
652 return
lmr6f669ce2009-05-31 19:02:42 +0000653
lmr71fa4de2010-06-14 15:54:55 +0000654 logging.debug("Destroying VM with PID %s...", self.get_pid())
lmr6f669ce2009-05-31 19:02:42 +0000655
lmrf320b042009-09-15 05:48:06 +0000656 if gracefully and self.params.get("shutdown_command"):
657 # Try to destroy with shell command
658 logging.debug("Trying to shutdown VM with shell command...")
659 session = self.remote_login()
660 if session:
661 try:
662 # Send the shutdown command
663 session.sendline(self.params.get("shutdown_command"))
664 logging.debug("Shutdown command sent; waiting for VM "
665 "to go down...")
666 if kvm_utils.wait_for(self.is_dead, 60, 1, 1):
667 logging.debug("VM is down")
668 return
669 finally:
670 session.close()
lmr6f669ce2009-05-31 19:02:42 +0000671
lmr9e964a02010-06-18 03:46:21 +0000672 if self.monitor:
673 # Try to destroy with a monitor command
674 logging.debug("Trying to kill VM with monitor command...")
675 try:
676 self.monitor.quit()
677 except kvm_monitor.MonitorError, e:
678 logging.warn(e)
679 else:
680 # Wait for the VM to be really dead
681 if kvm_utils.wait_for(self.is_dead, 5, 0.5, 0.5):
682 logging.debug("VM is down")
683 return
lmrf320b042009-09-15 05:48:06 +0000684
685 # If the VM isn't dead yet...
686 logging.debug("Cannot quit normally; sending a kill to close the "
687 "deal...")
688 kvm_utils.kill_process_tree(self.process.get_pid(), 9)
lmr6f669ce2009-05-31 19:02:42 +0000689 # Wait for the VM to be really dead
690 if kvm_utils.wait_for(self.is_dead, 5, 0.5, 0.5):
691 logging.debug("VM is down")
lmr6f669ce2009-05-31 19:02:42 +0000692 return
693
lmrf320b042009-09-15 05:48:06 +0000694 logging.error("Process %s is a zombie!" % self.process.get_pid())
lmr6f669ce2009-05-31 19:02:42 +0000695
lmrf320b042009-09-15 05:48:06 +0000696 finally:
lmr9e964a02010-06-18 03:46:21 +0000697 self.monitors = []
lmr4513c432010-02-03 11:59:03 +0000698 if self.pci_assignable:
699 self.pci_assignable.release_devs()
lmrf320b042009-09-15 05:48:06 +0000700 if self.process:
701 self.process.close()
lmr9e964a02010-06-18 03:46:21 +0000702 for f in ([self.get_testlog_filename()] +
703 self.get_monitor_filenames()):
704 try:
705 os.unlink(f)
706 except OSError:
707 pass
708
709
710 @property
711 def monitor(self):
712 """
713 Return the main monitor object, selected by the parameter main_monitor.
714 If main_monitor isn't defined, return the first monitor.
715 If no monitors exist, or if main_monitor refers to a nonexistent
716 monitor, return None.
717 """
718 for m in self.monitors:
719 if m.name == self.params.get("main_monitor"):
720 return m
721 if self.monitors and not self.params.get("main_monitor"):
722 return self.monitors[0]
lmr6f669ce2009-05-31 19:02:42 +0000723
724
725 def is_alive(self):
726 """
lmr9e964a02010-06-18 03:46:21 +0000727 Return True if the VM is alive and its monitor is responsive.
lmr6f669ce2009-05-31 19:02:42 +0000728 """
lmra4967622009-07-23 01:36:32 +0000729 # Check if the process is running
730 if self.is_dead():
lmr6f669ce2009-05-31 19:02:42 +0000731 return False
732 # Try sending a monitor command
lmr9e964a02010-06-18 03:46:21 +0000733 return bool(self.monitor) and self.monitor.is_responsive()
lmr6f669ce2009-05-31 19:02:42 +0000734
735
736 def is_dead(self):
737 """
lmra4967622009-07-23 01:36:32 +0000738 Return True if the qemu process is dead.
lmr6f669ce2009-05-31 19:02:42 +0000739 """
lmra4967622009-07-23 01:36:32 +0000740 return not self.process or not self.process.is_alive()
lmr6f669ce2009-05-31 19:02:42 +0000741
742
lmra4197002009-08-13 05:00:51 +0000743 def kill_tail_thread(self):
744 """
745 Stop the tailing thread which reports the output of qemu.
746 """
747 if self.process:
748 self.process.kill_tail_thread()
749
750
lmr6f669ce2009-05-31 19:02:42 +0000751 def get_params(self):
752 """
753 Return the VM's params dict. Most modified params take effect only
754 upon VM.create().
755 """
756 return self.params
757
758
lmr9e964a02010-06-18 03:46:21 +0000759 def get_monitor_filename(self, monitor_name):
760 """
761 Return the filename corresponding to a given monitor name.
762 """
763 return "/tmp/monitor-%s-%s" % (monitor_name, self.instance)
764
765
766 def get_monitor_filenames(self):
767 """
768 Return a list of all monitor filenames (as specified in the VM's
769 params).
770 """
771 return [self.get_monitor_filename(m) for m in
772 kvm_utils.get_sub_dict_names(self.params, "monitors")]
773
774
775 def get_testlog_filename(self):
776 """
777 Return the testlog filename.
778 """
779 return "/tmp/testlog-%s" % self.instance
780
781
lmrf4696342009-08-13 04:06:33 +0000782 def get_address(self, index=0):
lmr6f669ce2009-05-31 19:02:42 +0000783 """
lmrf4696342009-08-13 04:06:33 +0000784 Return the address of a NIC of the guest, in host space.
lmr6f669ce2009-05-31 19:02:42 +0000785
lmrf4696342009-08-13 04:06:33 +0000786 If port redirection is used, return 'localhost' (the NIC has no IP
787 address of its own). Otherwise return the NIC's IP address.
788
789 @param index: Index of the NIC whose address is requested.
lmr6f669ce2009-05-31 19:02:42 +0000790 """
lmree90dd92009-08-13 04:13:39 +0000791 nics = kvm_utils.get_sub_dict_names(self.params, "nics")
792 nic_name = nics[index]
lmrf4696342009-08-13 04:06:33 +0000793 nic_params = kvm_utils.get_sub_dict(self.params, nic_name)
794 if nic_params.get("nic_mode") == "tap":
795 mac, ip = kvm_utils.get_mac_ip_pair_from_dict(nic_params)
lmree90dd92009-08-13 04:13:39 +0000796 if not mac:
797 logging.debug("MAC address unavailable")
798 return None
799 if not ip or nic_params.get("always_use_tcpdump") == "yes":
800 # Get the IP address from the cache
801 ip = self.address_cache.get(mac)
802 if not ip:
803 logging.debug("Could not find IP address for MAC address: "
804 "%s" % mac)
805 return None
806 # Make sure the IP address is assigned to this guest
807 nic_dicts = [kvm_utils.get_sub_dict(self.params, nic)
808 for nic in nics]
809 macs = [kvm_utils.get_mac_ip_pair_from_dict(dict)[0]
810 for dict in nic_dicts]
811 if not kvm_utils.verify_ip_address_ownership(ip, macs):
812 logging.debug("Could not verify MAC-IP address mapping: "
813 "%s ---> %s" % (mac, ip))
814 return None
lmrf4696342009-08-13 04:06:33 +0000815 return ip
816 else:
817 return "localhost"
lmr6f669ce2009-05-31 19:02:42 +0000818
819
lmree90dd92009-08-13 04:13:39 +0000820 def get_port(self, port, nic_index=0):
lmr6f669ce2009-05-31 19:02:42 +0000821 """
822 Return the port in host space corresponding to port in guest space.
823
824 @param port: Port number in host space.
lmree90dd92009-08-13 04:13:39 +0000825 @param nic_index: Index of the NIC.
lmr6f669ce2009-05-31 19:02:42 +0000826 @return: If port redirection is used, return the host port redirected
827 to guest port port. Otherwise return port.
828 """
lmree90dd92009-08-13 04:13:39 +0000829 nic_name = kvm_utils.get_sub_dict_names(self.params, "nics")[nic_index]
lmrf4696342009-08-13 04:06:33 +0000830 nic_params = kvm_utils.get_sub_dict(self.params, nic_name)
831 if nic_params.get("nic_mode") == "tap":
832 return port
lmr6f669ce2009-05-31 19:02:42 +0000833 else:
lmrf4696342009-08-13 04:06:33 +0000834 if not self.redirs.has_key(port):
835 logging.warn("Warning: guest port %s requested but not "
836 "redirected" % port)
837 return self.redirs.get(port)
lmr6f669ce2009-05-31 19:02:42 +0000838
839
lmra4967622009-07-23 01:36:32 +0000840 def get_pid(self):
841 """
lmr71fa4de2010-06-14 15:54:55 +0000842 Return the VM's PID. If the VM is dead return None.
843
844 @note: This works under the assumption that self.process.get_pid()
845 returns the PID of the parent shell process.
846 """
847 try:
848 children = commands.getoutput("ps --ppid=%d -o pid=" %
849 self.process.get_pid()).split()
850 return int(children[0])
851 except (TypeError, IndexError, ValueError):
852 return None
853
854
855 def get_shell_pid(self):
856 """
857 Return the PID of the parent shell process.
858
859 @note: This works under the assumption that self.process.get_pid()
860 returns the PID of the parent shell process.
lmra4967622009-07-23 01:36:32 +0000861 """
862 return self.process.get_pid()
863
864
lmr0bee2342010-02-24 00:01:37 +0000865 def get_shared_meminfo(self):
866 """
867 Returns the VM's shared memory information.
868
869 @return: Shared memory used by VM (MB)
870 """
871 if self.is_dead():
872 logging.error("Could not get shared memory info from dead VM.")
873 return None
874
lmr983ecdf2010-06-14 15:57:12 +0000875 filename = "/proc/%d/statm" % self.get_pid()
876 shm = int(open(filename).read().split()[2])
lmr0bee2342010-02-24 00:01:37 +0000877 # statm stores informations in pages, translate it to MB
lmr983ecdf2010-06-14 15:57:12 +0000878 return shm * 4.0 / 1024
lmr0bee2342010-02-24 00:01:37 +0000879
880
lmr912c74b2009-08-17 20:43:27 +0000881 def remote_login(self, nic_index=0, timeout=10):
lmr6f669ce2009-05-31 19:02:42 +0000882 """
lmr912c74b2009-08-17 20:43:27 +0000883 Log into the guest via SSH/Telnet/Netcat.
lmr6f669ce2009-05-31 19:02:42 +0000884 If timeout expires while waiting for output from the guest (e.g. a
885 password prompt or a shell prompt) -- fail.
886
lmree90dd92009-08-13 04:13:39 +0000887 @param nic_index: The index of the NIC to connect to.
lmr6f669ce2009-05-31 19:02:42 +0000888 @param timeout: Time (seconds) before giving up logging into the
889 guest.
890 @return: kvm_spawn object on success and None on failure.
891 """
892 username = self.params.get("username", "")
893 password = self.params.get("password", "")
lmr912c74b2009-08-17 20:43:27 +0000894 prompt = self.params.get("shell_prompt", "[\#\$]")
lmr59f9e2d2009-10-05 18:47:16 +0000895 linesep = eval("'%s'" % self.params.get("shell_linesep", r"\n"))
lmr912c74b2009-08-17 20:43:27 +0000896 client = self.params.get("shell_client")
lmree90dd92009-08-13 04:13:39 +0000897 address = self.get_address(nic_index)
lmr912c74b2009-08-17 20:43:27 +0000898 port = self.get_port(int(self.params.get("shell_port")))
899
lmree90dd92009-08-13 04:13:39 +0000900 if not address or not port:
901 logging.debug("IP address or port unavailable")
lmr6f669ce2009-05-31 19:02:42 +0000902 return None
903
lmr912c74b2009-08-17 20:43:27 +0000904 if client == "ssh":
lmr6f669ce2009-05-31 19:02:42 +0000905 session = kvm_utils.ssh(address, port, username, password,
lmr59f9e2d2009-10-05 18:47:16 +0000906 prompt, linesep, timeout)
lmr912c74b2009-08-17 20:43:27 +0000907 elif client == "telnet":
908 session = kvm_utils.telnet(address, port, username, password,
lmr59f9e2d2009-10-05 18:47:16 +0000909 prompt, linesep, timeout)
lmr9f6ebf12009-08-17 20:44:10 +0000910 elif client == "nc":
911 session = kvm_utils.netcat(address, port, username, password,
lmr59f9e2d2009-10-05 18:47:16 +0000912 prompt, linesep, timeout)
lmr912c74b2009-08-17 20:43:27 +0000913
lmr6f669ce2009-05-31 19:02:42 +0000914 if session:
lmr912c74b2009-08-17 20:43:27 +0000915 session.set_status_test_command(self.params.get("status_test_"
lmr6f669ce2009-05-31 19:02:42 +0000916 "command", ""))
917 return session
918
919
lmrc196d492010-05-07 14:14:26 +0000920 def copy_files_to(self, local_path, remote_path, nic_index=0, timeout=600):
lmr6f669ce2009-05-31 19:02:42 +0000921 """
lmr912c74b2009-08-17 20:43:27 +0000922 Transfer files to the guest.
lmr6f669ce2009-05-31 19:02:42 +0000923
924 @param local_path: Host path
925 @param remote_path: Guest path
lmr912c74b2009-08-17 20:43:27 +0000926 @param nic_index: The index of the NIC to connect to.
lmr6f669ce2009-05-31 19:02:42 +0000927 @param timeout: Time (seconds) before giving up on doing the remote
928 copy.
929 """
930 username = self.params.get("username", "")
931 password = self.params.get("password", "")
lmr912c74b2009-08-17 20:43:27 +0000932 client = self.params.get("file_transfer_client")
lmree90dd92009-08-13 04:13:39 +0000933 address = self.get_address(nic_index)
lmr912c74b2009-08-17 20:43:27 +0000934 port = self.get_port(int(self.params.get("file_transfer_port")))
935
lmree90dd92009-08-13 04:13:39 +0000936 if not address or not port:
937 logging.debug("IP address or port unavailable")
lmr6f669ce2009-05-31 19:02:42 +0000938 return None
lmr912c74b2009-08-17 20:43:27 +0000939
940 if client == "scp":
941 return kvm_utils.scp_to_remote(address, port, username, password,
942 local_path, remote_path, timeout)
lmr6f669ce2009-05-31 19:02:42 +0000943
944
lmrc196d492010-05-07 14:14:26 +0000945 def copy_files_from(self, remote_path, local_path, nic_index=0, timeout=600):
lmr6f669ce2009-05-31 19:02:42 +0000946 """
lmr912c74b2009-08-17 20:43:27 +0000947 Transfer files from the guest.
lmr6f669ce2009-05-31 19:02:42 +0000948
949 @param local_path: Guest path
950 @param remote_path: Host path
lmr912c74b2009-08-17 20:43:27 +0000951 @param nic_index: The index of the NIC to connect to.
lmr6f669ce2009-05-31 19:02:42 +0000952 @param timeout: Time (seconds) before giving up on doing the remote
953 copy.
954 """
955 username = self.params.get("username", "")
956 password = self.params.get("password", "")
lmr912c74b2009-08-17 20:43:27 +0000957 client = self.params.get("file_transfer_client")
lmree90dd92009-08-13 04:13:39 +0000958 address = self.get_address(nic_index)
lmr912c74b2009-08-17 20:43:27 +0000959 port = self.get_port(int(self.params.get("file_transfer_port")))
960
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
lmr6f669ce2009-05-31 19:02:42 +0000964
lmr912c74b2009-08-17 20:43:27 +0000965 if client == "scp":
966 return kvm_utils.scp_from_remote(address, port, username, password,
967 remote_path, local_path, timeout)
lmr6f669ce2009-05-31 19:02:42 +0000968
969
970 def send_key(self, keystr):
971 """
972 Send a key event to the VM.
973
974 @param: keystr: A key event string (e.g. "ctrl-alt-delete")
975 """
976 # For compatibility with versions of QEMU that do not recognize all
977 # key names: replace keyname with the hex value from the dict, which
978 # QEMU will definitely accept
lmr9e964a02010-06-18 03:46:21 +0000979 dict = {"comma": "0x33",
980 "dot": "0x34",
981 "slash": "0x35"}
982 for key, value in dict.items():
983 keystr = keystr.replace(key, value)
984 self.monitor.sendkey(keystr)
lmr6f669ce2009-05-31 19:02:42 +0000985 time.sleep(0.2)
986
987
988 def send_string(self, str):
989 """
990 Send a string to the VM.
991
992 @param str: String, that must consist of alphanumeric characters only.
993 Capital letters are allowed.
994 """
995 for char in str:
996 if char.isupper():
997 self.send_key("shift-%s" % char.lower())
998 else:
999 self.send_key(char)
lmra2533222009-07-20 12:43:46 +00001000
mbligh1ef218d2009-08-03 16:57:56 +00001001
lmra2533222009-07-20 12:43:46 +00001002 def get_uuid(self):
1003 """
1004 Catch UUID of the VM.
1005
1006 @return: None,if not specified in config file
1007 """
1008 if self.params.get("uuid") == "random":
1009 return self.uuid
1010 else:
1011 return self.params.get("uuid", None)
lmrdd2ff922009-12-01 23:39:12 +00001012
1013
1014 def get_cpu_count(self):
1015 """
1016 Get the cpu count of the VM.
1017 """
lmr13426552010-01-17 15:38:41 +00001018 session = self.remote_login()
1019 if not session:
1020 return None
lmrdd2ff922009-12-01 23:39:12 +00001021 try:
lmr13426552010-01-17 15:38:41 +00001022 cmd = self.params.get("cpu_chk_cmd")
1023 s, count = session.get_command_status_output(cmd)
1024 if s == 0:
1025 return int(count)
lmrdd2ff922009-12-01 23:39:12 +00001026 return None
1027 finally:
1028 session.close()
1029
1030
lmr28426c82010-04-16 06:02:58 +00001031 def get_memory_size(self, cmd=None):
lmrdd2ff922009-12-01 23:39:12 +00001032 """
lmr28426c82010-04-16 06:02:58 +00001033 Get bootup memory size of the VM.
1034
1035 @param check_cmd: Command used to check memory. If not provided,
1036 self.params.get("mem_chk_cmd") will be used.
lmrdd2ff922009-12-01 23:39:12 +00001037 """
lmr13426552010-01-17 15:38:41 +00001038 session = self.remote_login()
1039 if not session:
lmrdd2ff922009-12-01 23:39:12 +00001040 return None
lmr13426552010-01-17 15:38:41 +00001041 try:
lmr28426c82010-04-16 06:02:58 +00001042 if not cmd:
1043 cmd = self.params.get("mem_chk_cmd")
lmr13426552010-01-17 15:38:41 +00001044 s, mem_str = session.get_command_status_output(cmd)
1045 if s != 0:
1046 return None
lmr6d69f4d2010-02-12 11:35:55 +00001047 mem = re.findall("([0-9]+)", mem_str)
lmr13426552010-01-17 15:38:41 +00001048 mem_size = 0
1049 for m in mem:
1050 mem_size += int(m)
1051 if "GB" in mem_str:
1052 mem_size *= 1024
1053 elif "MB" in mem_str:
1054 pass
1055 else:
1056 mem_size /= 1024
1057 return int(mem_size)
lmrdd2ff922009-12-01 23:39:12 +00001058 finally:
1059 session.close()
lmr28426c82010-04-16 06:02:58 +00001060
1061
1062 def get_current_memory_size(self):
1063 """
1064 Get current memory size of the VM, rather than bootup memory.
1065 """
1066 cmd = self.params.get("mem_chk_cur_cmd")
1067 return self.get_memory_size(cmd)