blob: 225f26a056a9cc0ab8bd3d27ff5bd898cbc87527 [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":
lmr449d2252010-06-18 03:48:23 +0000595 # Add a QMP monitor
596 monitor = kvm_monitor.QMPMonitor(
597 monitor_name,
598 self.get_monitor_filename(monitor_name))
lmr9e964a02010-06-18 03:46:21 +0000599 else:
600 # Add a "human" monitor
601 monitor = kvm_monitor.HumanMonitor(
602 monitor_name,
603 self.get_monitor_filename(monitor_name))
604 except kvm_monitor.MonitorError, e:
605 logging.warn(e)
606 else:
lmr449d2252010-06-18 03:48:23 +0000607 if monitor.is_responsive():
lmr9e964a02010-06-18 03:46:21 +0000608 break
609 time.sleep(1)
610 else:
611 logging.error("Could not connect to monitor '%s'" %
612 monitor_name)
613 self.destroy()
614 return False
615 # Add this monitor to the list
616 self.monitors += [monitor]
lmra4967622009-07-23 01:36:32 +0000617
lmrfe6515e2009-07-29 13:01:17 +0000618 # Get the output so far, to see if we have any problems with
619 # hugepage setup.
620 output = self.process.get_output()
621
622 if "alloc_mem_area" in output:
623 logging.error("Could not allocate hugepage memory; "
624 "qemu command:\n%s" % qemu_command)
625 logging.error("Output:" + kvm_utils.format_str_for_message(
626 self.process.get_output()))
lmr090cd7a2010-04-01 02:18:52 +0000627 self.destroy()
lmrfe6515e2009-07-29 13:01:17 +0000628 return False
629
lmr71fa4de2010-06-14 15:54:55 +0000630 logging.debug("VM appears to be alive with PID %s", self.get_pid())
lmrdc2ac6a2009-06-10 19:15:49 +0000631 return True
632
633 finally:
634 fcntl.lockf(lockfile, fcntl.LOCK_UN)
635 lockfile.close()
lmr6f669ce2009-05-31 19:02:42 +0000636
637
lmr6f669ce2009-05-31 19:02:42 +0000638 def destroy(self, gracefully=True):
639 """
640 Destroy the VM.
641
lmr912c74b2009-08-17 20:43:27 +0000642 If gracefully is True, first attempt to shutdown the VM with a shell
643 command. Then, attempt to destroy the VM via the monitor with a 'quit'
644 command. If that fails, send SIGKILL to the qemu process.
lmr6f669ce2009-05-31 19:02:42 +0000645
646 @param gracefully: Whether an attempt will be made to end the VM
lmr912c74b2009-08-17 20:43:27 +0000647 using a shell command before trying to end the qemu process
648 with a 'quit' or a kill signal.
lmr6f669ce2009-05-31 19:02:42 +0000649 """
lmrf320b042009-09-15 05:48:06 +0000650 try:
651 # Is it already dead?
652 if self.is_dead():
653 logging.debug("VM is already down")
654 return
lmr6f669ce2009-05-31 19:02:42 +0000655
lmr71fa4de2010-06-14 15:54:55 +0000656 logging.debug("Destroying VM with PID %s...", self.get_pid())
lmr6f669ce2009-05-31 19:02:42 +0000657
lmrf320b042009-09-15 05:48:06 +0000658 if gracefully and self.params.get("shutdown_command"):
659 # Try to destroy with shell command
660 logging.debug("Trying to shutdown VM with shell command...")
661 session = self.remote_login()
662 if session:
663 try:
664 # Send the shutdown command
665 session.sendline(self.params.get("shutdown_command"))
666 logging.debug("Shutdown command sent; waiting for VM "
667 "to go down...")
668 if kvm_utils.wait_for(self.is_dead, 60, 1, 1):
669 logging.debug("VM is down")
670 return
671 finally:
672 session.close()
lmr6f669ce2009-05-31 19:02:42 +0000673
lmr9e964a02010-06-18 03:46:21 +0000674 if self.monitor:
675 # Try to destroy with a monitor command
676 logging.debug("Trying to kill VM with monitor command...")
677 try:
678 self.monitor.quit()
679 except kvm_monitor.MonitorError, e:
680 logging.warn(e)
681 else:
682 # Wait for the VM to be really dead
683 if kvm_utils.wait_for(self.is_dead, 5, 0.5, 0.5):
684 logging.debug("VM is down")
685 return
lmrf320b042009-09-15 05:48:06 +0000686
687 # If the VM isn't dead yet...
688 logging.debug("Cannot quit normally; sending a kill to close the "
689 "deal...")
690 kvm_utils.kill_process_tree(self.process.get_pid(), 9)
lmr6f669ce2009-05-31 19:02:42 +0000691 # Wait for the VM to be really dead
692 if kvm_utils.wait_for(self.is_dead, 5, 0.5, 0.5):
693 logging.debug("VM is down")
lmr6f669ce2009-05-31 19:02:42 +0000694 return
695
lmrf320b042009-09-15 05:48:06 +0000696 logging.error("Process %s is a zombie!" % self.process.get_pid())
lmr6f669ce2009-05-31 19:02:42 +0000697
lmrf320b042009-09-15 05:48:06 +0000698 finally:
lmr9e964a02010-06-18 03:46:21 +0000699 self.monitors = []
lmr4513c432010-02-03 11:59:03 +0000700 if self.pci_assignable:
701 self.pci_assignable.release_devs()
lmrf320b042009-09-15 05:48:06 +0000702 if self.process:
703 self.process.close()
lmr9e964a02010-06-18 03:46:21 +0000704 for f in ([self.get_testlog_filename()] +
705 self.get_monitor_filenames()):
706 try:
707 os.unlink(f)
708 except OSError:
709 pass
710
711
712 @property
713 def monitor(self):
714 """
715 Return the main monitor object, selected by the parameter main_monitor.
716 If main_monitor isn't defined, return the first monitor.
717 If no monitors exist, or if main_monitor refers to a nonexistent
718 monitor, return None.
719 """
720 for m in self.monitors:
721 if m.name == self.params.get("main_monitor"):
722 return m
723 if self.monitors and not self.params.get("main_monitor"):
724 return self.monitors[0]
lmr6f669ce2009-05-31 19:02:42 +0000725
726
727 def is_alive(self):
728 """
lmr9e964a02010-06-18 03:46:21 +0000729 Return True if the VM is alive and its monitor is responsive.
lmr6f669ce2009-05-31 19:02:42 +0000730 """
lmra4967622009-07-23 01:36:32 +0000731 # Check if the process is running
732 if self.is_dead():
lmr6f669ce2009-05-31 19:02:42 +0000733 return False
734 # Try sending a monitor command
lmr9e964a02010-06-18 03:46:21 +0000735 return bool(self.monitor) and self.monitor.is_responsive()
lmr6f669ce2009-05-31 19:02:42 +0000736
737
738 def is_dead(self):
739 """
lmra4967622009-07-23 01:36:32 +0000740 Return True if the qemu process is dead.
lmr6f669ce2009-05-31 19:02:42 +0000741 """
lmra4967622009-07-23 01:36:32 +0000742 return not self.process or not self.process.is_alive()
lmr6f669ce2009-05-31 19:02:42 +0000743
744
lmra4197002009-08-13 05:00:51 +0000745 def kill_tail_thread(self):
746 """
747 Stop the tailing thread which reports the output of qemu.
748 """
749 if self.process:
750 self.process.kill_tail_thread()
751
752
lmr6f669ce2009-05-31 19:02:42 +0000753 def get_params(self):
754 """
755 Return the VM's params dict. Most modified params take effect only
756 upon VM.create().
757 """
758 return self.params
759
760
lmr9e964a02010-06-18 03:46:21 +0000761 def get_monitor_filename(self, monitor_name):
762 """
763 Return the filename corresponding to a given monitor name.
764 """
765 return "/tmp/monitor-%s-%s" % (monitor_name, self.instance)
766
767
768 def get_monitor_filenames(self):
769 """
770 Return a list of all monitor filenames (as specified in the VM's
771 params).
772 """
773 return [self.get_monitor_filename(m) for m in
774 kvm_utils.get_sub_dict_names(self.params, "monitors")]
775
776
777 def get_testlog_filename(self):
778 """
779 Return the testlog filename.
780 """
781 return "/tmp/testlog-%s" % self.instance
782
783
lmrf4696342009-08-13 04:06:33 +0000784 def get_address(self, index=0):
lmr6f669ce2009-05-31 19:02:42 +0000785 """
lmrf4696342009-08-13 04:06:33 +0000786 Return the address of a NIC of the guest, in host space.
lmr6f669ce2009-05-31 19:02:42 +0000787
lmrf4696342009-08-13 04:06:33 +0000788 If port redirection is used, return 'localhost' (the NIC has no IP
789 address of its own). Otherwise return the NIC's IP address.
790
791 @param index: Index of the NIC whose address is requested.
lmr6f669ce2009-05-31 19:02:42 +0000792 """
lmree90dd92009-08-13 04:13:39 +0000793 nics = kvm_utils.get_sub_dict_names(self.params, "nics")
794 nic_name = nics[index]
lmrf4696342009-08-13 04:06:33 +0000795 nic_params = kvm_utils.get_sub_dict(self.params, nic_name)
796 if nic_params.get("nic_mode") == "tap":
797 mac, ip = kvm_utils.get_mac_ip_pair_from_dict(nic_params)
lmree90dd92009-08-13 04:13:39 +0000798 if not mac:
799 logging.debug("MAC address unavailable")
800 return None
801 if not ip or nic_params.get("always_use_tcpdump") == "yes":
802 # Get the IP address from the cache
803 ip = self.address_cache.get(mac)
804 if not ip:
805 logging.debug("Could not find IP address for MAC address: "
806 "%s" % mac)
807 return None
808 # Make sure the IP address is assigned to this guest
809 nic_dicts = [kvm_utils.get_sub_dict(self.params, nic)
810 for nic in nics]
811 macs = [kvm_utils.get_mac_ip_pair_from_dict(dict)[0]
812 for dict in nic_dicts]
813 if not kvm_utils.verify_ip_address_ownership(ip, macs):
814 logging.debug("Could not verify MAC-IP address mapping: "
815 "%s ---> %s" % (mac, ip))
816 return None
lmrf4696342009-08-13 04:06:33 +0000817 return ip
818 else:
819 return "localhost"
lmr6f669ce2009-05-31 19:02:42 +0000820
821
lmree90dd92009-08-13 04:13:39 +0000822 def get_port(self, port, nic_index=0):
lmr6f669ce2009-05-31 19:02:42 +0000823 """
824 Return the port in host space corresponding to port in guest space.
825
826 @param port: Port number in host space.
lmree90dd92009-08-13 04:13:39 +0000827 @param nic_index: Index of the NIC.
lmr6f669ce2009-05-31 19:02:42 +0000828 @return: If port redirection is used, return the host port redirected
829 to guest port port. Otherwise return port.
830 """
lmree90dd92009-08-13 04:13:39 +0000831 nic_name = kvm_utils.get_sub_dict_names(self.params, "nics")[nic_index]
lmrf4696342009-08-13 04:06:33 +0000832 nic_params = kvm_utils.get_sub_dict(self.params, nic_name)
833 if nic_params.get("nic_mode") == "tap":
834 return port
lmr6f669ce2009-05-31 19:02:42 +0000835 else:
lmrf4696342009-08-13 04:06:33 +0000836 if not self.redirs.has_key(port):
837 logging.warn("Warning: guest port %s requested but not "
838 "redirected" % port)
839 return self.redirs.get(port)
lmr6f669ce2009-05-31 19:02:42 +0000840
841
lmra4967622009-07-23 01:36:32 +0000842 def get_pid(self):
843 """
lmr71fa4de2010-06-14 15:54:55 +0000844 Return the VM's PID. If the VM is dead return None.
845
846 @note: This works under the assumption that self.process.get_pid()
847 returns the PID of the parent shell process.
848 """
849 try:
850 children = commands.getoutput("ps --ppid=%d -o pid=" %
851 self.process.get_pid()).split()
852 return int(children[0])
853 except (TypeError, IndexError, ValueError):
854 return None
855
856
857 def get_shell_pid(self):
858 """
859 Return the PID of the parent shell process.
860
861 @note: This works under the assumption that self.process.get_pid()
862 returns the PID of the parent shell process.
lmra4967622009-07-23 01:36:32 +0000863 """
864 return self.process.get_pid()
865
866
lmr0bee2342010-02-24 00:01:37 +0000867 def get_shared_meminfo(self):
868 """
869 Returns the VM's shared memory information.
870
871 @return: Shared memory used by VM (MB)
872 """
873 if self.is_dead():
874 logging.error("Could not get shared memory info from dead VM.")
875 return None
876
lmr983ecdf2010-06-14 15:57:12 +0000877 filename = "/proc/%d/statm" % self.get_pid()
878 shm = int(open(filename).read().split()[2])
lmr0bee2342010-02-24 00:01:37 +0000879 # statm stores informations in pages, translate it to MB
lmr983ecdf2010-06-14 15:57:12 +0000880 return shm * 4.0 / 1024
lmr0bee2342010-02-24 00:01:37 +0000881
882
lmr912c74b2009-08-17 20:43:27 +0000883 def remote_login(self, nic_index=0, timeout=10):
lmr6f669ce2009-05-31 19:02:42 +0000884 """
lmr912c74b2009-08-17 20:43:27 +0000885 Log into the guest via SSH/Telnet/Netcat.
lmr6f669ce2009-05-31 19:02:42 +0000886 If timeout expires while waiting for output from the guest (e.g. a
887 password prompt or a shell prompt) -- fail.
888
lmree90dd92009-08-13 04:13:39 +0000889 @param nic_index: The index of the NIC to connect to.
lmr6f669ce2009-05-31 19:02:42 +0000890 @param timeout: Time (seconds) before giving up logging into the
891 guest.
892 @return: kvm_spawn object on success and None on failure.
893 """
894 username = self.params.get("username", "")
895 password = self.params.get("password", "")
lmr912c74b2009-08-17 20:43:27 +0000896 prompt = self.params.get("shell_prompt", "[\#\$]")
lmr59f9e2d2009-10-05 18:47:16 +0000897 linesep = eval("'%s'" % self.params.get("shell_linesep", r"\n"))
lmr912c74b2009-08-17 20:43:27 +0000898 client = self.params.get("shell_client")
lmree90dd92009-08-13 04:13:39 +0000899 address = self.get_address(nic_index)
lmr912c74b2009-08-17 20:43:27 +0000900 port = self.get_port(int(self.params.get("shell_port")))
901
lmree90dd92009-08-13 04:13:39 +0000902 if not address or not port:
903 logging.debug("IP address or port unavailable")
lmr6f669ce2009-05-31 19:02:42 +0000904 return None
905
lmr158604f2010-06-22 01:57:34 +0000906 session = kvm_utils.remote_login(client, address, port, username,
907 password, prompt, linesep, timeout)
lmr912c74b2009-08-17 20:43:27 +0000908
lmr6f669ce2009-05-31 19:02:42 +0000909 if session:
lmr912c74b2009-08-17 20:43:27 +0000910 session.set_status_test_command(self.params.get("status_test_"
lmr6f669ce2009-05-31 19:02:42 +0000911 "command", ""))
912 return session
913
914
lmrc196d492010-05-07 14:14:26 +0000915 def copy_files_to(self, local_path, remote_path, nic_index=0, timeout=600):
lmr6f669ce2009-05-31 19:02:42 +0000916 """
lmr912c74b2009-08-17 20:43:27 +0000917 Transfer files to the guest.
lmr6f669ce2009-05-31 19:02:42 +0000918
919 @param local_path: Host path
920 @param remote_path: Guest path
lmr912c74b2009-08-17 20:43:27 +0000921 @param nic_index: The index of the NIC to connect to.
lmr6f669ce2009-05-31 19:02:42 +0000922 @param timeout: Time (seconds) before giving up on doing the remote
923 copy.
924 """
925 username = self.params.get("username", "")
926 password = self.params.get("password", "")
lmr912c74b2009-08-17 20:43:27 +0000927 client = self.params.get("file_transfer_client")
lmree90dd92009-08-13 04:13:39 +0000928 address = self.get_address(nic_index)
lmr912c74b2009-08-17 20:43:27 +0000929 port = self.get_port(int(self.params.get("file_transfer_port")))
930
lmree90dd92009-08-13 04:13:39 +0000931 if not address or not port:
932 logging.debug("IP address or port unavailable")
lmr6f669ce2009-05-31 19:02:42 +0000933 return None
lmr912c74b2009-08-17 20:43:27 +0000934
935 if client == "scp":
936 return kvm_utils.scp_to_remote(address, port, username, password,
937 local_path, remote_path, timeout)
lmr6f669ce2009-05-31 19:02:42 +0000938
939
lmrc196d492010-05-07 14:14:26 +0000940 def copy_files_from(self, remote_path, local_path, nic_index=0, timeout=600):
lmr6f669ce2009-05-31 19:02:42 +0000941 """
lmr912c74b2009-08-17 20:43:27 +0000942 Transfer files from the guest.
lmr6f669ce2009-05-31 19:02:42 +0000943
944 @param local_path: Guest path
945 @param remote_path: Host path
lmr912c74b2009-08-17 20:43:27 +0000946 @param nic_index: The index of the NIC to connect to.
lmr6f669ce2009-05-31 19:02:42 +0000947 @param timeout: Time (seconds) before giving up on doing the remote
948 copy.
949 """
950 username = self.params.get("username", "")
951 password = self.params.get("password", "")
lmr912c74b2009-08-17 20:43:27 +0000952 client = self.params.get("file_transfer_client")
lmree90dd92009-08-13 04:13:39 +0000953 address = self.get_address(nic_index)
lmr912c74b2009-08-17 20:43:27 +0000954 port = self.get_port(int(self.params.get("file_transfer_port")))
955
lmree90dd92009-08-13 04:13:39 +0000956 if not address or not port:
957 logging.debug("IP address or port unavailable")
lmr6f669ce2009-05-31 19:02:42 +0000958 return None
lmr6f669ce2009-05-31 19:02:42 +0000959
lmr912c74b2009-08-17 20:43:27 +0000960 if client == "scp":
961 return kvm_utils.scp_from_remote(address, port, username, password,
962 remote_path, local_path, timeout)
lmr6f669ce2009-05-31 19:02:42 +0000963
964
965 def send_key(self, keystr):
966 """
967 Send a key event to the VM.
968
969 @param: keystr: A key event string (e.g. "ctrl-alt-delete")
970 """
971 # For compatibility with versions of QEMU that do not recognize all
972 # key names: replace keyname with the hex value from the dict, which
973 # QEMU will definitely accept
lmr9e964a02010-06-18 03:46:21 +0000974 dict = {"comma": "0x33",
975 "dot": "0x34",
976 "slash": "0x35"}
977 for key, value in dict.items():
978 keystr = keystr.replace(key, value)
979 self.monitor.sendkey(keystr)
lmr6f669ce2009-05-31 19:02:42 +0000980 time.sleep(0.2)
981
982
983 def send_string(self, str):
984 """
985 Send a string to the VM.
986
987 @param str: String, that must consist of alphanumeric characters only.
988 Capital letters are allowed.
989 """
990 for char in str:
991 if char.isupper():
992 self.send_key("shift-%s" % char.lower())
993 else:
994 self.send_key(char)
lmra2533222009-07-20 12:43:46 +0000995
mbligh1ef218d2009-08-03 16:57:56 +0000996
lmra2533222009-07-20 12:43:46 +0000997 def get_uuid(self):
998 """
999 Catch UUID of the VM.
1000
1001 @return: None,if not specified in config file
1002 """
1003 if self.params.get("uuid") == "random":
1004 return self.uuid
1005 else:
1006 return self.params.get("uuid", None)
lmrdd2ff922009-12-01 23:39:12 +00001007
1008
1009 def get_cpu_count(self):
1010 """
1011 Get the cpu count of the VM.
1012 """
lmr13426552010-01-17 15:38:41 +00001013 session = self.remote_login()
1014 if not session:
1015 return None
lmrdd2ff922009-12-01 23:39:12 +00001016 try:
lmr13426552010-01-17 15:38:41 +00001017 cmd = self.params.get("cpu_chk_cmd")
1018 s, count = session.get_command_status_output(cmd)
1019 if s == 0:
1020 return int(count)
lmrdd2ff922009-12-01 23:39:12 +00001021 return None
1022 finally:
1023 session.close()
1024
1025
lmr28426c82010-04-16 06:02:58 +00001026 def get_memory_size(self, cmd=None):
lmrdd2ff922009-12-01 23:39:12 +00001027 """
lmr28426c82010-04-16 06:02:58 +00001028 Get bootup memory size of the VM.
1029
1030 @param check_cmd: Command used to check memory. If not provided,
1031 self.params.get("mem_chk_cmd") will be used.
lmrdd2ff922009-12-01 23:39:12 +00001032 """
lmr13426552010-01-17 15:38:41 +00001033 session = self.remote_login()
1034 if not session:
lmrdd2ff922009-12-01 23:39:12 +00001035 return None
lmr13426552010-01-17 15:38:41 +00001036 try:
lmr28426c82010-04-16 06:02:58 +00001037 if not cmd:
1038 cmd = self.params.get("mem_chk_cmd")
lmr13426552010-01-17 15:38:41 +00001039 s, mem_str = session.get_command_status_output(cmd)
1040 if s != 0:
1041 return None
lmr6d69f4d2010-02-12 11:35:55 +00001042 mem = re.findall("([0-9]+)", mem_str)
lmr13426552010-01-17 15:38:41 +00001043 mem_size = 0
1044 for m in mem:
1045 mem_size += int(m)
1046 if "GB" in mem_str:
1047 mem_size *= 1024
1048 elif "MB" in mem_str:
1049 pass
1050 else:
1051 mem_size /= 1024
1052 return int(mem_size)
lmrdd2ff922009-12-01 23:39:12 +00001053 finally:
1054 session.close()
lmr28426c82010-04-16 06:02:58 +00001055
1056
1057 def get_current_memory_size(self):
1058 """
1059 Get current memory size of the VM, rather than bootup memory.
1060 """
1061 cmd = self.params.get("mem_chk_cur_cmd")
1062 return self.get_memory_size(cmd)