blob: ed8e7a34f90e9aa48ee651bab1b1117f5607c0f8 [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
lmrb635b862009-09-10 14:53:21 +00008import time, socket, os, logging, fcntl, re, commands
9import kvm_utils, kvm_subprocess
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
lmr6f669ce2009-05-31 19:02:42 +0000112
113 self.name = name
114 self.params = params
lmr90b9fd52009-08-17 20:48:18 +0000115 self.root_dir = root_dir
lmree90dd92009-08-13 04:13:39 +0000116 self.address_cache = address_cache
lmr31af3a12010-01-18 16:46:52 +0000117 self.pci_assignable = None
lmrb1cad1e2010-06-17 17:36:09 +0000118 self.netdev_id = []
119 for nic in params.get("nics").split():
120 self.netdev_id.append(kvm_utils.generate_random_string(4))
lmr6f669ce2009-05-31 19:02:42 +0000121
lmr8b134f92009-06-08 14:47:31 +0000122 # Find available monitor filename
123 while True:
124 # The monitor filename should be unique
lmrd16a67d2009-06-10 19:52:59 +0000125 self.instance = (time.strftime("%Y%m%d-%H%M%S-") +
126 kvm_utils.generate_random_string(4))
lmr8b134f92009-06-08 14:47:31 +0000127 self.monitor_file_name = os.path.join("/tmp",
128 "monitor-" + self.instance)
129 if not os.path.exists(self.monitor_file_name):
130 break
131
132
lmr52800ba2009-08-17 20:49:58 +0000133 def clone(self, name=None, params=None, root_dir=None, address_cache=None):
lmr2c241172009-06-08 15:11:29 +0000134 """
135 Return a clone of the VM object with optionally modified parameters.
136 The clone is initially not alive and needs to be started using create().
137 Any parameters not passed to this function are copied from the source
138 VM.
139
140 @param name: Optional new VM name
141 @param params: Optional new VM creation parameters
lmr90b9fd52009-08-17 20:48:18 +0000142 @param root_dir: Optional new base directory for relative filenames
lmree90dd92009-08-13 04:13:39 +0000143 @param address_cache: A dict that maps MAC addresses to IP addresses
lmr2c241172009-06-08 15:11:29 +0000144 """
lmre45a1f22009-11-10 16:35:08 +0000145 if name is None:
lmr2c241172009-06-08 15:11:29 +0000146 name = self.name
lmre45a1f22009-11-10 16:35:08 +0000147 if params is None:
lmr2c241172009-06-08 15:11:29 +0000148 params = self.params.copy()
lmre45a1f22009-11-10 16:35:08 +0000149 if root_dir is None:
lmr90b9fd52009-08-17 20:48:18 +0000150 root_dir = self.root_dir
lmre45a1f22009-11-10 16:35:08 +0000151 if address_cache is None:
lmree90dd92009-08-13 04:13:39 +0000152 address_cache = self.address_cache
lmr52800ba2009-08-17 20:49:58 +0000153 return VM(name, params, root_dir, address_cache)
lmr2c241172009-06-08 15:11:29 +0000154
155
lmr52800ba2009-08-17 20:49:58 +0000156 def make_qemu_command(self, name=None, params=None, root_dir=None):
lmr6f669ce2009-05-31 19:02:42 +0000157 """
158 Generate a qemu command line. All parameters are optional. If a
159 parameter is not supplied, the corresponding value stored in the
160 class attributes is used.
161
lmr6f669ce2009-05-31 19:02:42 +0000162 @param name: The name of the object
163 @param params: A dict containing VM params
lmr90b9fd52009-08-17 20:48:18 +0000164 @param root_dir: Base directory for relative filenames
lmr6f669ce2009-05-31 19:02:42 +0000165
166 @note: The params dict should contain:
167 mem -- memory size in MBs
168 cdrom -- ISO filename to use with the qemu -cdrom parameter
lmr6f669ce2009-05-31 19:02:42 +0000169 extra_params -- a string to append to the qemu command
lmr912c74b2009-08-17 20:43:27 +0000170 shell_port -- port of the remote shell daemon on the guest
171 (SSH, Telnet or the home-made Remote Shell Server)
172 shell_client -- client program to use for connecting to the
173 remote shell daemon on the guest (ssh, telnet or nc)
lmreeff0eb2009-06-10 19:19:15 +0000174 x11_display -- if specified, the DISPLAY environment variable
175 will be be set to this value for the qemu process (useful for
176 SDL rendering)
lmr6f669ce2009-05-31 19:02:42 +0000177 images -- a list of image object names, separated by spaces
178 nics -- a list of NIC object names, separated by spaces
179
180 For each image in images:
181 drive_format -- string to pass as 'if' parameter for this
182 image (e.g. ide, scsi)
183 image_snapshot -- if yes, pass 'snapshot=on' to qemu for
184 this image
185 image_boot -- if yes, pass 'boot=on' to qemu for this image
186 In addition, all parameters required by get_image_filename.
187
188 For each NIC in nics:
189 nic_model -- string to pass as 'model' parameter for this
190 NIC (e.g. e1000)
191 """
lmr48abd7d2010-05-26 13:48:04 +0000192 # Helper function for command line option wrappers
193 def has_option(help, option):
194 return bool(re.search(r"^-%s(\s|$)" % option, help, re.MULTILINE))
195
196 # Wrappers for all supported qemu command line parameters.
197 # This is meant to allow support for multiple qemu versions.
198 # Each of these functions receives the output of 'qemu -help' as a
199 # parameter, and should add the requested command line option
200 # accordingly.
201
202 def add_name(help, name):
203 return " -name '%s'" % name
204
205 def add_unix_socket_monitor(help, filename):
lmr09a78162010-06-14 16:29:23 +0000206 return " -monitor unix:'%s',server,nowait" % filename
lmr48abd7d2010-05-26 13:48:04 +0000207
208 def add_mem(help, mem):
209 return " -m %s" % mem
210
211 def add_smp(help, smp):
212 return " -smp %s" % smp
213
214 def add_cdrom(help, filename, index=2):
215 if has_option(help, "drive"):
lmr09a78162010-06-14 16:29:23 +0000216 return " -drive file='%s',index=%d,media=cdrom" % (filename,
217 index)
lmr48abd7d2010-05-26 13:48:04 +0000218 else:
lmr09a78162010-06-14 16:29:23 +0000219 return " -cdrom '%s'" % filename
lmr48abd7d2010-05-26 13:48:04 +0000220
221 def add_drive(help, filename, format=None, cache=None, werror=None,
222 serial=None, snapshot=False, boot=False):
lmr09a78162010-06-14 16:29:23 +0000223 cmd = " -drive file='%s'" % filename
lmr48abd7d2010-05-26 13:48:04 +0000224 if format: cmd += ",if=%s" % format
225 if cache: cmd += ",cache=%s" % cache
226 if werror: cmd += ",werror=%s" % werror
lmr09a78162010-06-14 16:29:23 +0000227 if serial: cmd += ",serial='%s'" % serial
lmr48abd7d2010-05-26 13:48:04 +0000228 if snapshot: cmd += ",snapshot=on"
229 if boot: cmd += ",boot=on"
230 return cmd
231
lmrb1cad1e2010-06-17 17:36:09 +0000232 def add_nic(help, vlan, model=None, mac=None, netdev_id=None):
lmr48abd7d2010-05-26 13:48:04 +0000233 cmd = " -net nic,vlan=%d" % vlan
lmrb1cad1e2010-06-17 17:36:09 +0000234 if has_option(help, "netdev"):
235 cmd +=",netdev=%s" % netdev_id
lmr48abd7d2010-05-26 13:48:04 +0000236 if model: cmd += ",model=%s" % model
lmr09a78162010-06-14 16:29:23 +0000237 if mac: cmd += ",macaddr='%s'" % mac
lmr48abd7d2010-05-26 13:48:04 +0000238 return cmd
239
240 def add_net(help, vlan, mode, ifname=None, script=None,
lmrb1cad1e2010-06-17 17:36:09 +0000241 downscript=None, netdev_id=None):
242 if has_option(help, "netdev"):
243 cmd = " -netdev %s,id=%s" % (mode, netdev_id)
244 else:
245 cmd = " -net %s,vlan=%d" % (mode, vlan)
lmr48abd7d2010-05-26 13:48:04 +0000246 if mode == "tap":
lmr09a78162010-06-14 16:29:23 +0000247 if ifname: cmd += ",ifname='%s'" % ifname
248 if script: cmd += ",script='%s'" % script
249 cmd += ",downscript='%s'" % (downscript or "no")
lmr48abd7d2010-05-26 13:48:04 +0000250 return cmd
251
252 def add_floppy(help, filename):
lmr09a78162010-06-14 16:29:23 +0000253 return " -fda '%s'" % filename
lmr48abd7d2010-05-26 13:48:04 +0000254
255 def add_tftp(help, filename):
lmr09a78162010-06-14 16:29:23 +0000256 return " -tftp '%s'" % filename
lmr48abd7d2010-05-26 13:48:04 +0000257
258 def add_tcp_redir(help, host_port, guest_port):
259 return " -redir tcp:%s::%s" % (host_port, guest_port)
260
261 def add_vnc(help, vnc_port):
262 return " -vnc :%d" % (vnc_port - 5900)
263
264 def add_sdl(help):
265 if has_option(help, "sdl"):
266 return " -sdl"
267 else:
268 return ""
269
270 def add_nographic(help):
271 return " -nographic"
272
273 def add_uuid(help, uuid):
lmr09a78162010-06-14 16:29:23 +0000274 return " -uuid '%s'" % uuid
lmr48abd7d2010-05-26 13:48:04 +0000275
276 def add_pcidevice(help, host):
lmr09a78162010-06-14 16:29:23 +0000277 return " -pcidevice host='%s'" % host
lmr48abd7d2010-05-26 13:48:04 +0000278
lmr41cb8fc2010-06-10 15:30:45 +0000279 def add_kernel(help, filename):
lmr09a78162010-06-14 16:29:23 +0000280 return " -kernel '%s'" % filename
lmr41cb8fc2010-06-10 15:30:45 +0000281
282 def add_initrd(help, filename):
lmr09a78162010-06-14 16:29:23 +0000283 return " -initrd '%s'" % filename
lmr41cb8fc2010-06-10 15:30:45 +0000284
lmr48abd7d2010-05-26 13:48:04 +0000285 # End of command line option wrappers
286
287 if name is None: name = self.name
288 if params is None: params = self.params
289 if root_dir is None: root_dir = self.root_dir
290
291 qemu_binary = kvm_utils.get_path(root_dir, params.get("qemu_binary",
292 "qemu"))
293 # Get the output of 'qemu -help' (log a message in case this call never
294 # returns or causes some other kind of trouble)
295 logging.debug("Getting output of 'qemu -help'")
296 help = commands.getoutput("%s -help" % qemu_binary)
lmr6f669ce2009-05-31 19:02:42 +0000297
lmreeff0eb2009-06-10 19:19:15 +0000298 # Start constructing the qemu command
299 qemu_cmd = ""
300 # Set the X11 display parameter if requested
301 if params.get("x11_display"):
302 qemu_cmd += "DISPLAY=%s " % params.get("x11_display")
303 # Add the qemu binary
lmr48abd7d2010-05-26 13:48:04 +0000304 qemu_cmd += qemu_binary
lmreeff0eb2009-06-10 19:19:15 +0000305 # Add the VM's name
lmr48abd7d2010-05-26 13:48:04 +0000306 qemu_cmd += add_name(help, name)
lmreeff0eb2009-06-10 19:19:15 +0000307 # Add the monitor socket parameter
lmr48abd7d2010-05-26 13:48:04 +0000308 qemu_cmd += add_unix_socket_monitor(help, self.monitor_file_name)
lmr6f669ce2009-05-31 19:02:42 +0000309
310 for image_name in kvm_utils.get_sub_dict_names(params, "images"):
311 image_params = kvm_utils.get_sub_dict(params, image_name)
lmr9d75ee32009-09-29 13:14:13 +0000312 if image_params.get("boot_drive") == "no":
313 continue
lmr48abd7d2010-05-26 13:48:04 +0000314 qemu_cmd += add_drive(help,
315 get_image_filename(image_params, root_dir),
316 image_params.get("drive_format"),
317 image_params.get("drive_cache"),
318 image_params.get("drive_werror"),
319 image_params.get("drive_serial"),
320 image_params.get("image_snapshot") == "yes",
321 image_params.get("image_boot") == "yes")
lmr6f669ce2009-05-31 19:02:42 +0000322
323 vlan = 0
324 for nic_name in kvm_utils.get_sub_dict_names(params, "nics"):
325 nic_params = kvm_utils.get_sub_dict(params, nic_name)
lmrf4696342009-08-13 04:06:33 +0000326 # Handle the '-net nic' part
lmr48abd7d2010-05-26 13:48:04 +0000327 mac = None
328 if "address_index" in nic_params:
329 mac = kvm_utils.get_mac_ip_pair_from_dict(nic_params)[0]
lmrb1cad1e2010-06-17 17:36:09 +0000330 qemu_cmd += add_nic(help, vlan, nic_params.get("nic_model"), mac,
331 self.netdev_id[vlan])
lmrf4696342009-08-13 04:06:33 +0000332 # Handle the '-net tap' or '-net user' part
lmre4eaa862010-06-01 19:15:14 +0000333 script = nic_params.get("nic_script")
334 downscript = nic_params.get("nic_downscript")
lmr48abd7d2010-05-26 13:48:04 +0000335 if script:
336 script = kvm_utils.get_path(root_dir, script)
337 if downscript:
338 downscript = kvm_utils.get_path(root_dir, downscript)
339 qemu_cmd += add_net(help, vlan, nic_params.get("nic_mode", "user"),
340 nic_params.get("nic_ifname"),
lmrb1cad1e2010-06-17 17:36:09 +0000341 script, downscript, self.netdev_id[vlan])
lmrf4696342009-08-13 04:06:33 +0000342 # Proceed to next NIC
lmr6f669ce2009-05-31 19:02:42 +0000343 vlan += 1
344
345 mem = params.get("mem")
346 if mem:
lmr48abd7d2010-05-26 13:48:04 +0000347 qemu_cmd += add_mem(help, mem)
lmr6f669ce2009-05-31 19:02:42 +0000348
lmrc43bf372009-11-10 13:19:00 +0000349 smp = params.get("smp")
350 if smp:
lmrdb3fe612010-06-14 16:19:28 +0000351 qemu_cmd += add_smp(help, smp)
lmrc43bf372009-11-10 13:19:00 +0000352
lmr6f669ce2009-05-31 19:02:42 +0000353 iso = params.get("cdrom")
354 if iso:
lmr90b9fd52009-08-17 20:48:18 +0000355 iso = kvm_utils.get_path(root_dir, iso)
lmr48abd7d2010-05-26 13:48:04 +0000356 qemu_cmd += add_cdrom(help, iso)
lmr89fd6412010-01-18 02:42:57 +0000357
358 # Even though this is not a really scalable approach,
359 # it doesn't seem like we are going to need more than
360 # 2 CDs active on the same VM.
361 iso_extra = params.get("cdrom_extra")
362 if iso_extra:
363 iso_extra = kvm_utils.get_path(root_dir, iso_extra)
lmr48abd7d2010-05-26 13:48:04 +0000364 qemu_cmd += add_cdrom(help, iso_extra, 3)
lmr6f669ce2009-05-31 19:02:42 +0000365
lmrb0a9b762009-10-09 20:43:30 +0000366 # We may want to add {floppy_otps} parameter for -fda
lmr48abd7d2010-05-26 13:48:04 +0000367 # {fat:floppy:}/path/. However vvfat is not usually recommended.
lmrb0a9b762009-10-09 20:43:30 +0000368 floppy = params.get("floppy")
369 if floppy:
lmrf69f6b12009-11-10 16:33:44 +0000370 floppy = kvm_utils.get_path(root_dir, floppy)
lmr48abd7d2010-05-26 13:48:04 +0000371 qemu_cmd += add_floppy(help, floppy)
lmrb0a9b762009-10-09 20:43:30 +0000372
373 tftp = params.get("tftp")
374 if tftp:
lmrf69f6b12009-11-10 16:33:44 +0000375 tftp = kvm_utils.get_path(root_dir, tftp)
lmr48abd7d2010-05-26 13:48:04 +0000376 qemu_cmd += add_tftp(help, tftp)
lmr6f669ce2009-05-31 19:02:42 +0000377
lmr41cb8fc2010-06-10 15:30:45 +0000378 kernel = params.get("kernel")
379 if kernel:
380 kernel = kvm_utils.get_path(root_dir, kernel)
381 qemu_cmd += add_kernel(help, kernel)
382
383 initrd = params.get("initrd")
384 if initrd:
385 initrd = kvm_utils.get_path(root_dir, initrd)
386 qemu_cmd += add_initrd(help, initrd)
387
lmr6f669ce2009-05-31 19:02:42 +0000388 for redir_name in kvm_utils.get_sub_dict_names(params, "redirs"):
389 redir_params = kvm_utils.get_sub_dict(params, redir_name)
390 guest_port = int(redir_params.get("guest_port"))
lmrf4696342009-08-13 04:06:33 +0000391 host_port = self.redirs.get(guest_port)
lmr48abd7d2010-05-26 13:48:04 +0000392 qemu_cmd += add_tcp_redir(help, host_port, guest_port)
lmr6f669ce2009-05-31 19:02:42 +0000393
394 if params.get("display") == "vnc":
lmr48abd7d2010-05-26 13:48:04 +0000395 qemu_cmd += add_vnc(help, self.vnc_port)
lmr6f669ce2009-05-31 19:02:42 +0000396 elif params.get("display") == "sdl":
lmr48abd7d2010-05-26 13:48:04 +0000397 qemu_cmd += add_sdl(help)
lmr6f669ce2009-05-31 19:02:42 +0000398 elif params.get("display") == "nographic":
lmr48abd7d2010-05-26 13:48:04 +0000399 qemu_cmd += add_nographic(help)
lmr6f669ce2009-05-31 19:02:42 +0000400
lmra2533222009-07-20 12:43:46 +0000401 if params.get("uuid") == "random":
lmr48abd7d2010-05-26 13:48:04 +0000402 qemu_cmd += add_uuid(help, self.uuid)
lmra2533222009-07-20 12:43:46 +0000403 elif params.get("uuid"):
lmr48abd7d2010-05-26 13:48:04 +0000404 qemu_cmd += add_uuid(help, params.get("uuid"))
lmra2533222009-07-20 12:43:46 +0000405
lmr31af3a12010-01-18 16:46:52 +0000406 # If the PCI assignment step went OK, add each one of the PCI assigned
407 # devices to the qemu command line.
408 if self.pci_assignable:
409 for pci_id in self.pa_pci_ids:
lmr48abd7d2010-05-26 13:48:04 +0000410 qemu_cmd += add_pcidevice(help, pci_id)
411
412 extra_params = params.get("extra_params")
413 if extra_params:
414 qemu_cmd += " %s" % extra_params
lmr31af3a12010-01-18 16:46:52 +0000415
lmr6f669ce2009-05-31 19:02:42 +0000416 return qemu_cmd
417
418
lmr52800ba2009-08-17 20:49:58 +0000419 def create(self, name=None, params=None, root_dir=None,
lmr1424f3e2010-06-17 13:57:09 +0000420 for_migration=False, timeout=5.0, extra_params=None):
lmr6f669ce2009-05-31 19:02:42 +0000421 """
422 Start the VM by running a qemu command.
423 All parameters are optional. The following applies to all parameters
424 but for_migration: If a parameter is not supplied, the corresponding
425 value stored in the class attributes is used, and if it is supplied,
426 it is stored for later use.
427
428 @param name: The name of the object
429 @param params: A dict containing VM params
lmr90b9fd52009-08-17 20:48:18 +0000430 @param root_dir: Base directory for relative filenames
lmr6f669ce2009-05-31 19:02:42 +0000431 @param for_migration: If True, start the VM with the -incoming
432 option
lmr1424f3e2010-06-17 13:57:09 +0000433 @param extra_params: extra params for qemu command.e.g -incoming option
434 Please use this parameter instead of for_migration.
lmr6f669ce2009-05-31 19:02:42 +0000435 """
lmr135b5e62009-06-10 19:22:31 +0000436 self.destroy()
437
lmre45a1f22009-11-10 16:35:08 +0000438 if name is not None:
lmr6f669ce2009-05-31 19:02:42 +0000439 self.name = name
lmre45a1f22009-11-10 16:35:08 +0000440 if params is not None:
lmr6f669ce2009-05-31 19:02:42 +0000441 self.params = params
lmre45a1f22009-11-10 16:35:08 +0000442 if root_dir is not None:
lmr90b9fd52009-08-17 20:48:18 +0000443 self.root_dir = root_dir
lmr6f669ce2009-05-31 19:02:42 +0000444 name = self.name
445 params = self.params
lmr90b9fd52009-08-17 20:48:18 +0000446 root_dir = self.root_dir
lmr6f669ce2009-05-31 19:02:42 +0000447
448 # Verify the md5sum of the ISO image
449 iso = params.get("cdrom")
450 if iso:
lmr90b9fd52009-08-17 20:48:18 +0000451 iso = kvm_utils.get_path(root_dir, iso)
lmr6f669ce2009-05-31 19:02:42 +0000452 if not os.path.exists(iso):
453 logging.error("ISO file not found: %s" % iso)
454 return False
455 compare = False
456 if params.get("md5sum_1m"):
lmrf4696342009-08-13 04:06:33 +0000457 logging.debug("Comparing expected MD5 sum with MD5 sum of "
458 "first MB of ISO file...")
lmrd60882f2010-02-04 03:26:36 +0000459 actual_hash = utils.hash_file(iso, 1048576, method="md5")
lmr03ba22e2009-10-23 12:07:44 +0000460 expected_hash = params.get("md5sum_1m")
lmr6f669ce2009-05-31 19:02:42 +0000461 compare = True
462 elif params.get("md5sum"):
lmrf4696342009-08-13 04:06:33 +0000463 logging.debug("Comparing expected MD5 sum with MD5 sum of ISO "
464 "file...")
lmrd60882f2010-02-04 03:26:36 +0000465 actual_hash = utils.hash_file(iso, method="md5")
lmr03ba22e2009-10-23 12:07:44 +0000466 expected_hash = params.get("md5sum")
467 compare = True
468 elif params.get("sha1sum"):
469 logging.debug("Comparing expected SHA1 sum with SHA1 sum of "
470 "ISO file...")
lmrd60882f2010-02-04 03:26:36 +0000471 actual_hash = utils.hash_file(iso, method="sha1")
lmrea1266e2009-11-10 16:41:08 +0000472 expected_hash = params.get("sha1sum")
lmr6f669ce2009-05-31 19:02:42 +0000473 compare = True
474 if compare:
lmr03ba22e2009-10-23 12:07:44 +0000475 if actual_hash == expected_hash:
476 logging.debug("Hashes match")
lmr6f669ce2009-05-31 19:02:42 +0000477 else:
lmr03ba22e2009-10-23 12:07:44 +0000478 logging.error("Actual hash differs from expected one")
lmr6f669ce2009-05-31 19:02:42 +0000479 return False
480
lmrdc2ac6a2009-06-10 19:15:49 +0000481 # Make sure the following code is not executed by more than one thread
482 # at the same time
483 lockfile = open("/tmp/kvm-autotest-vm-create.lock", "w+")
484 fcntl.lockf(lockfile, fcntl.LOCK_EX)
lmr6f669ce2009-05-31 19:02:42 +0000485
lmrdc2ac6a2009-06-10 19:15:49 +0000486 try:
487 # Handle port redirections
488 redir_names = kvm_utils.get_sub_dict_names(params, "redirs")
489 host_ports = kvm_utils.find_free_ports(5000, 6000, len(redir_names))
490 self.redirs = {}
491 for i in range(len(redir_names)):
492 redir_params = kvm_utils.get_sub_dict(params, redir_names[i])
493 guest_port = int(redir_params.get("guest_port"))
494 self.redirs[guest_port] = host_ports[i]
lmr6f669ce2009-05-31 19:02:42 +0000495
lmrdc2ac6a2009-06-10 19:15:49 +0000496 # Find available VNC port, if needed
497 if params.get("display") == "vnc":
lmrc0da8902010-05-17 20:31:36 +0000498 self.vnc_port = kvm_utils.find_free_port(5900, 6100)
lmr6f669ce2009-05-31 19:02:42 +0000499
lmra2533222009-07-20 12:43:46 +0000500 # Find random UUID if specified 'uuid = random' in config file
501 if params.get("uuid") == "random":
502 f = open("/proc/sys/kernel/random/uuid")
503 self.uuid = f.read().strip()
504 f.close()
505
lmr31ed61d2010-06-07 13:21:38 +0000506 # Assign a PCI assignable device
507 self.pci_assignable = None
508 pa_type = params.get("pci_assignable")
509 if pa_type in ["vf", "pf", "mixed"]:
lmr31af3a12010-01-18 16:46:52 +0000510 pa_devices_requested = params.get("devices_requested")
511
512 # Virtual Functions (VF) assignable devices
513 if pa_type == "vf":
lmr31ed61d2010-06-07 13:21:38 +0000514 self.pci_assignable = kvm_utils.PciAssignable(
515 type=pa_type,
516 driver=params.get("driver"),
517 driver_option=params.get("driver_option"),
518 devices_requested=pa_devices_requested)
lmr31af3a12010-01-18 16:46:52 +0000519 # Physical NIC (PF) assignable devices
520 elif pa_type == "pf":
lmr31ed61d2010-06-07 13:21:38 +0000521 self.pci_assignable = kvm_utils.PciAssignable(
522 type=pa_type,
523 names=params.get("device_names"),
524 devices_requested=pa_devices_requested)
lmr31af3a12010-01-18 16:46:52 +0000525 # Working with both VF and PF
526 elif pa_type == "mixed":
lmr31ed61d2010-06-07 13:21:38 +0000527 self.pci_assignable = kvm_utils.PciAssignable(
528 type=pa_type,
529 driver=params.get("driver"),
530 driver_option=params.get("driver_option"),
531 names=params.get("device_names"),
532 devices_requested=pa_devices_requested)
lmr31af3a12010-01-18 16:46:52 +0000533
534 self.pa_pci_ids = self.pci_assignable.request_devs()
535
536 if self.pa_pci_ids:
lmr31ed61d2010-06-07 13:21:38 +0000537 logging.debug("Successfuly assigned devices: %s",
lmr31af3a12010-01-18 16:46:52 +0000538 self.pa_pci_ids)
539 else:
540 logging.error("No PCI assignable devices were assigned "
541 "and 'pci_assignable' is defined to %s "
lmr31ed61d2010-06-07 13:21:38 +0000542 "on your config file. Aborting VM creation.",
lmr31af3a12010-01-18 16:46:52 +0000543 pa_type)
544 return False
545
lmr856d58c2010-06-08 18:29:31 +0000546 elif pa_type and pa_type != "no":
lmr31ed61d2010-06-07 13:21:38 +0000547 logging.warn("Unsupported pci_assignable type: %s", pa_type)
lmr31af3a12010-01-18 16:46:52 +0000548
lmrdc2ac6a2009-06-10 19:15:49 +0000549 # Make qemu command
550 qemu_command = self.make_qemu_command()
lmr6f669ce2009-05-31 19:02:42 +0000551
lmr1424f3e2010-06-17 13:57:09 +0000552 # Enable migration support for VM by adding extra_params.
553 if extra_params is not None:
554 if " -incoming tcp:0:%d" == extra_params:
555 self.migration_port = kvm_utils.find_free_port(5200, 6000)
556 qemu_command += extra_params % self.migration_port
557 elif " -incoming unix:%s" == extra_params:
558 self.migration_file = os.path.join("/tmp/", "unix-" +
559 time.strftime("%Y%m%d-%H%M%S"))
560 qemu_command += extra_params % self.migration_file
561 else:
562 qemu_command += extra_params
lmr6f669ce2009-05-31 19:02:42 +0000563
lmrdc2ac6a2009-06-10 19:15:49 +0000564 logging.debug("Running qemu command:\n%s", qemu_command)
lmra4967622009-07-23 01:36:32 +0000565 self.process = kvm_subprocess.run_bg(qemu_command, None,
566 logging.debug, "(qemu) ")
lmr6f669ce2009-05-31 19:02:42 +0000567
lmra4967622009-07-23 01:36:32 +0000568 if not self.process.is_alive():
569 logging.error("VM could not be created; "
570 "qemu command failed:\n%s" % qemu_command)
571 logging.error("Status: %s" % self.process.get_status())
572 logging.error("Output:" + kvm_utils.format_str_for_message(
573 self.process.get_output()))
lmrdc2ac6a2009-06-10 19:15:49 +0000574 self.destroy()
575 return False
lmr6f669ce2009-05-31 19:02:42 +0000576
lmra4967622009-07-23 01:36:32 +0000577 if not kvm_utils.wait_for(self.is_alive, timeout, 0, 1):
578 logging.error("VM is not alive for some reason; "
579 "qemu command:\n%s" % qemu_command)
580 self.destroy()
581 return False
582
lmrfe6515e2009-07-29 13:01:17 +0000583 # Get the output so far, to see if we have any problems with
584 # hugepage setup.
585 output = self.process.get_output()
586
587 if "alloc_mem_area" in output:
588 logging.error("Could not allocate hugepage memory; "
589 "qemu command:\n%s" % qemu_command)
590 logging.error("Output:" + kvm_utils.format_str_for_message(
591 self.process.get_output()))
lmr090cd7a2010-04-01 02:18:52 +0000592 self.destroy()
lmrfe6515e2009-07-29 13:01:17 +0000593 return False
594
lmr71fa4de2010-06-14 15:54:55 +0000595 logging.debug("VM appears to be alive with PID %s", self.get_pid())
lmrdc2ac6a2009-06-10 19:15:49 +0000596 return True
597
598 finally:
599 fcntl.lockf(lockfile, fcntl.LOCK_UN)
600 lockfile.close()
lmr6f669ce2009-05-31 19:02:42 +0000601
602
lmr70c1c5b2010-04-17 18:05:29 +0000603 def send_monitor_cmd(self, command, block=True, timeout=20.0, verbose=True):
lmr6f669ce2009-05-31 19:02:42 +0000604 """
605 Send command to the QEMU monitor.
606
607 Connect to the VM's monitor socket and wait for the (qemu) prompt.
608 If block is True, read output from the socket until the (qemu) prompt
609 is found again, or until timeout expires.
610
611 Return a tuple containing an integer indicating success or failure,
612 and the data read so far. The integer is 0 on success and 1 on failure.
613 A failure is any of the following cases: connection to the socket
614 failed, or the first (qemu) prompt could not be found, or block is
615 True and the second prompt could not be found.
616
617 @param command: Command that will be sent to the monitor
618 @param block: Whether the output from the socket will be read until
619 the timeout expires
620 @param timeout: Timeout (seconds) before giving up on reading from
621 socket
622 """
623 def read_up_to_qemu_prompt(s, timeout):
624 """
625 Read data from socket s until the (qemu) prompt is found.
626
627 If the prompt is found before timeout expires, return a tuple
628 containing True and the data read. Otherwise return a tuple
629 containing False and the data read so far.
630
631 @param s: Socket object
632 @param timeout: Time (seconds) before giving up trying to get the
633 qemu prompt.
634 """
635 o = ""
636 end_time = time.time() + timeout
637 while time.time() < end_time:
638 try:
lmrbcd20832009-10-15 11:56:56 +0000639 o += s.recv(1024)
lmr6f669ce2009-05-31 19:02:42 +0000640 if o.splitlines()[-1].split()[-1] == "(qemu)":
641 return (True, o)
642 except:
643 time.sleep(0.01)
644 return (False, o)
645
lmr70c1c5b2010-04-17 18:05:29 +0000646 # In certain conditions printing this debug output might be too much
647 # Just print it if verbose is enabled (True by default)
648 if verbose:
649 logging.debug("Sending monitor command: %s" % command)
lmr6f669ce2009-05-31 19:02:42 +0000650 # Connect to monitor
lmr6f669ce2009-05-31 19:02:42 +0000651 try:
652 s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
653 s.setblocking(False)
654 s.connect(self.monitor_file_name)
655 except:
656 logging.debug("Could not connect to monitor socket")
657 return (1, "")
lmrbcd20832009-10-15 11:56:56 +0000658
659 # Send the command and get the resulting output
660 try:
lmr6f669ce2009-05-31 19:02:42 +0000661 status, data = read_up_to_qemu_prompt(s, timeout)
lmr6f669ce2009-05-31 19:02:42 +0000662 if not status:
lmrbcd20832009-10-15 11:56:56 +0000663 logging.debug("Could not find (qemu) prompt; output so far:" +
664 kvm_utils.format_str_for_message(data))
665 return (1, "")
666 # Send command
667 s.sendall(command + "\n")
668 # Receive command output
669 data = ""
670 if block:
671 status, data = read_up_to_qemu_prompt(s, timeout)
672 data = "\n".join(data.splitlines()[1:])
673 if not status:
674 logging.debug("Could not find (qemu) prompt after command; "
675 "output so far:" +
676 kvm_utils.format_str_for_message(data))
677 return (1, data)
lmr612323d2010-06-17 16:48:45 +0000678 data = "".join(data.rstrip().splitlines(True)[:-1])
lmrbcd20832009-10-15 11:56:56 +0000679 return (0, data)
680
681 # Clean up before exiting
682 finally:
683 s.shutdown(socket.SHUT_RDWR)
684 s.close()
lmr6f669ce2009-05-31 19:02:42 +0000685
686
687 def destroy(self, gracefully=True):
688 """
689 Destroy the VM.
690
lmr912c74b2009-08-17 20:43:27 +0000691 If gracefully is True, first attempt to shutdown the VM with a shell
692 command. Then, attempt to destroy the VM via the monitor with a 'quit'
693 command. If that fails, send SIGKILL to the qemu process.
lmr6f669ce2009-05-31 19:02:42 +0000694
695 @param gracefully: Whether an attempt will be made to end the VM
lmr912c74b2009-08-17 20:43:27 +0000696 using a shell command before trying to end the qemu process
697 with a 'quit' or a kill signal.
lmr6f669ce2009-05-31 19:02:42 +0000698 """
lmrf320b042009-09-15 05:48:06 +0000699 try:
700 # Is it already dead?
701 if self.is_dead():
702 logging.debug("VM is already down")
703 return
lmr6f669ce2009-05-31 19:02:42 +0000704
lmr71fa4de2010-06-14 15:54:55 +0000705 logging.debug("Destroying VM with PID %s...", self.get_pid())
lmr6f669ce2009-05-31 19:02:42 +0000706
lmrf320b042009-09-15 05:48:06 +0000707 if gracefully and self.params.get("shutdown_command"):
708 # Try to destroy with shell command
709 logging.debug("Trying to shutdown VM with shell command...")
710 session = self.remote_login()
711 if session:
712 try:
713 # Send the shutdown command
714 session.sendline(self.params.get("shutdown_command"))
715 logging.debug("Shutdown command sent; waiting for VM "
716 "to go down...")
717 if kvm_utils.wait_for(self.is_dead, 60, 1, 1):
718 logging.debug("VM is down")
719 return
720 finally:
721 session.close()
lmr6f669ce2009-05-31 19:02:42 +0000722
lmrf320b042009-09-15 05:48:06 +0000723 # Try to destroy with a monitor command
724 logging.debug("Trying to kill VM with monitor command...")
725 status, output = self.send_monitor_cmd("quit", block=False)
726 # Was the command sent successfully?
727 if status == 0:
728 # Wait for the VM to be really dead
729 if kvm_utils.wait_for(self.is_dead, 5, 0.5, 0.5):
730 logging.debug("VM is down")
731 return
732
733 # If the VM isn't dead yet...
734 logging.debug("Cannot quit normally; sending a kill to close the "
735 "deal...")
736 kvm_utils.kill_process_tree(self.process.get_pid(), 9)
lmr6f669ce2009-05-31 19:02:42 +0000737 # Wait for the VM to be really dead
738 if kvm_utils.wait_for(self.is_dead, 5, 0.5, 0.5):
739 logging.debug("VM is down")
lmr6f669ce2009-05-31 19:02:42 +0000740 return
741
lmrf320b042009-09-15 05:48:06 +0000742 logging.error("Process %s is a zombie!" % self.process.get_pid())
lmr6f669ce2009-05-31 19:02:42 +0000743
lmrf320b042009-09-15 05:48:06 +0000744 finally:
lmr4513c432010-02-03 11:59:03 +0000745 if self.pci_assignable:
746 self.pci_assignable.release_devs()
lmrf320b042009-09-15 05:48:06 +0000747 if self.process:
748 self.process.close()
lmr4dcc0072009-11-10 16:52:27 +0000749 try:
750 os.unlink(self.monitor_file_name)
751 except OSError:
752 pass
lmr6f669ce2009-05-31 19:02:42 +0000753
754
755 def is_alive(self):
756 """
757 Return True if the VM's monitor is responsive.
758 """
lmra4967622009-07-23 01:36:32 +0000759 # Check if the process is running
760 if self.is_dead():
lmr6f669ce2009-05-31 19:02:42 +0000761 return False
762 # Try sending a monitor command
763 (status, output) = self.send_monitor_cmd("help")
764 if status:
765 return False
766 return True
767
768
769 def is_dead(self):
770 """
lmra4967622009-07-23 01:36:32 +0000771 Return True if the qemu process is dead.
lmr6f669ce2009-05-31 19:02:42 +0000772 """
lmra4967622009-07-23 01:36:32 +0000773 return not self.process or not self.process.is_alive()
lmr6f669ce2009-05-31 19:02:42 +0000774
775
lmra4197002009-08-13 05:00:51 +0000776 def kill_tail_thread(self):
777 """
778 Stop the tailing thread which reports the output of qemu.
779 """
780 if self.process:
781 self.process.kill_tail_thread()
782
783
lmr6f669ce2009-05-31 19:02:42 +0000784 def get_params(self):
785 """
786 Return the VM's params dict. Most modified params take effect only
787 upon VM.create().
788 """
789 return self.params
790
791
lmrf4696342009-08-13 04:06:33 +0000792 def get_address(self, index=0):
lmr6f669ce2009-05-31 19:02:42 +0000793 """
lmrf4696342009-08-13 04:06:33 +0000794 Return the address of a NIC of the guest, in host space.
lmr6f669ce2009-05-31 19:02:42 +0000795
lmrf4696342009-08-13 04:06:33 +0000796 If port redirection is used, return 'localhost' (the NIC has no IP
797 address of its own). Otherwise return the NIC's IP address.
798
799 @param index: Index of the NIC whose address is requested.
lmr6f669ce2009-05-31 19:02:42 +0000800 """
lmree90dd92009-08-13 04:13:39 +0000801 nics = kvm_utils.get_sub_dict_names(self.params, "nics")
802 nic_name = nics[index]
lmrf4696342009-08-13 04:06:33 +0000803 nic_params = kvm_utils.get_sub_dict(self.params, nic_name)
804 if nic_params.get("nic_mode") == "tap":
805 mac, ip = kvm_utils.get_mac_ip_pair_from_dict(nic_params)
lmree90dd92009-08-13 04:13:39 +0000806 if not mac:
807 logging.debug("MAC address unavailable")
808 return None
809 if not ip or nic_params.get("always_use_tcpdump") == "yes":
810 # Get the IP address from the cache
811 ip = self.address_cache.get(mac)
812 if not ip:
813 logging.debug("Could not find IP address for MAC address: "
814 "%s" % mac)
815 return None
816 # Make sure the IP address is assigned to this guest
817 nic_dicts = [kvm_utils.get_sub_dict(self.params, nic)
818 for nic in nics]
819 macs = [kvm_utils.get_mac_ip_pair_from_dict(dict)[0]
820 for dict in nic_dicts]
821 if not kvm_utils.verify_ip_address_ownership(ip, macs):
822 logging.debug("Could not verify MAC-IP address mapping: "
823 "%s ---> %s" % (mac, ip))
824 return None
lmrf4696342009-08-13 04:06:33 +0000825 return ip
826 else:
827 return "localhost"
lmr6f669ce2009-05-31 19:02:42 +0000828
829
lmree90dd92009-08-13 04:13:39 +0000830 def get_port(self, port, nic_index=0):
lmr6f669ce2009-05-31 19:02:42 +0000831 """
832 Return the port in host space corresponding to port in guest space.
833
834 @param port: Port number in host space.
lmree90dd92009-08-13 04:13:39 +0000835 @param nic_index: Index of the NIC.
lmr6f669ce2009-05-31 19:02:42 +0000836 @return: If port redirection is used, return the host port redirected
837 to guest port port. Otherwise return port.
838 """
lmree90dd92009-08-13 04:13:39 +0000839 nic_name = kvm_utils.get_sub_dict_names(self.params, "nics")[nic_index]
lmrf4696342009-08-13 04:06:33 +0000840 nic_params = kvm_utils.get_sub_dict(self.params, nic_name)
841 if nic_params.get("nic_mode") == "tap":
842 return port
lmr6f669ce2009-05-31 19:02:42 +0000843 else:
lmrf4696342009-08-13 04:06:33 +0000844 if not self.redirs.has_key(port):
845 logging.warn("Warning: guest port %s requested but not "
846 "redirected" % port)
847 return self.redirs.get(port)
lmr6f669ce2009-05-31 19:02:42 +0000848
849
lmra4967622009-07-23 01:36:32 +0000850 def get_pid(self):
851 """
lmr71fa4de2010-06-14 15:54:55 +0000852 Return the VM's PID. If the VM is dead return None.
853
854 @note: This works under the assumption that self.process.get_pid()
855 returns the PID of the parent shell process.
856 """
857 try:
858 children = commands.getoutput("ps --ppid=%d -o pid=" %
859 self.process.get_pid()).split()
860 return int(children[0])
861 except (TypeError, IndexError, ValueError):
862 return None
863
864
865 def get_shell_pid(self):
866 """
867 Return the PID of the parent shell process.
868
869 @note: This works under the assumption that self.process.get_pid()
870 returns the PID of the parent shell process.
lmra4967622009-07-23 01:36:32 +0000871 """
872 return self.process.get_pid()
873
874
lmr0bee2342010-02-24 00:01:37 +0000875 def get_shared_meminfo(self):
876 """
877 Returns the VM's shared memory information.
878
879 @return: Shared memory used by VM (MB)
880 """
881 if self.is_dead():
882 logging.error("Could not get shared memory info from dead VM.")
883 return None
884
lmr983ecdf2010-06-14 15:57:12 +0000885 filename = "/proc/%d/statm" % self.get_pid()
886 shm = int(open(filename).read().split()[2])
lmr0bee2342010-02-24 00:01:37 +0000887 # statm stores informations in pages, translate it to MB
lmr983ecdf2010-06-14 15:57:12 +0000888 return shm * 4.0 / 1024
lmr0bee2342010-02-24 00:01:37 +0000889
890
lmr912c74b2009-08-17 20:43:27 +0000891 def remote_login(self, nic_index=0, timeout=10):
lmr6f669ce2009-05-31 19:02:42 +0000892 """
lmr912c74b2009-08-17 20:43:27 +0000893 Log into the guest via SSH/Telnet/Netcat.
lmr6f669ce2009-05-31 19:02:42 +0000894 If timeout expires while waiting for output from the guest (e.g. a
895 password prompt or a shell prompt) -- fail.
896
lmree90dd92009-08-13 04:13:39 +0000897 @param nic_index: The index of the NIC to connect to.
lmr6f669ce2009-05-31 19:02:42 +0000898 @param timeout: Time (seconds) before giving up logging into the
899 guest.
900 @return: kvm_spawn object on success and None on failure.
901 """
902 username = self.params.get("username", "")
903 password = self.params.get("password", "")
lmr912c74b2009-08-17 20:43:27 +0000904 prompt = self.params.get("shell_prompt", "[\#\$]")
lmr59f9e2d2009-10-05 18:47:16 +0000905 linesep = eval("'%s'" % self.params.get("shell_linesep", r"\n"))
lmr912c74b2009-08-17 20:43:27 +0000906 client = self.params.get("shell_client")
lmree90dd92009-08-13 04:13:39 +0000907 address = self.get_address(nic_index)
lmr912c74b2009-08-17 20:43:27 +0000908 port = self.get_port(int(self.params.get("shell_port")))
909
lmree90dd92009-08-13 04:13:39 +0000910 if not address or not port:
911 logging.debug("IP address or port unavailable")
lmr6f669ce2009-05-31 19:02:42 +0000912 return None
913
lmr912c74b2009-08-17 20:43:27 +0000914 if client == "ssh":
lmr6f669ce2009-05-31 19:02:42 +0000915 session = kvm_utils.ssh(address, port, username, password,
lmr59f9e2d2009-10-05 18:47:16 +0000916 prompt, linesep, timeout)
lmr912c74b2009-08-17 20:43:27 +0000917 elif client == "telnet":
918 session = kvm_utils.telnet(address, port, username, password,
lmr59f9e2d2009-10-05 18:47:16 +0000919 prompt, linesep, timeout)
lmr9f6ebf12009-08-17 20:44:10 +0000920 elif client == "nc":
921 session = kvm_utils.netcat(address, port, username, password,
lmr59f9e2d2009-10-05 18:47:16 +0000922 prompt, linesep, timeout)
lmr912c74b2009-08-17 20:43:27 +0000923
lmr6f669ce2009-05-31 19:02:42 +0000924 if session:
lmr912c74b2009-08-17 20:43:27 +0000925 session.set_status_test_command(self.params.get("status_test_"
lmr6f669ce2009-05-31 19:02:42 +0000926 "command", ""))
927 return session
928
929
lmrc196d492010-05-07 14:14:26 +0000930 def copy_files_to(self, local_path, remote_path, nic_index=0, timeout=600):
lmr6f669ce2009-05-31 19:02:42 +0000931 """
lmr912c74b2009-08-17 20:43:27 +0000932 Transfer files to the guest.
lmr6f669ce2009-05-31 19:02:42 +0000933
934 @param local_path: Host path
935 @param remote_path: Guest path
lmr912c74b2009-08-17 20:43:27 +0000936 @param nic_index: The index of the NIC to connect to.
lmr6f669ce2009-05-31 19:02:42 +0000937 @param timeout: Time (seconds) before giving up on doing the remote
938 copy.
939 """
940 username = self.params.get("username", "")
941 password = self.params.get("password", "")
lmr912c74b2009-08-17 20:43:27 +0000942 client = self.params.get("file_transfer_client")
lmree90dd92009-08-13 04:13:39 +0000943 address = self.get_address(nic_index)
lmr912c74b2009-08-17 20:43:27 +0000944 port = self.get_port(int(self.params.get("file_transfer_port")))
945
lmree90dd92009-08-13 04:13:39 +0000946 if not address or not port:
947 logging.debug("IP address or port unavailable")
lmr6f669ce2009-05-31 19:02:42 +0000948 return None
lmr912c74b2009-08-17 20:43:27 +0000949
950 if client == "scp":
951 return kvm_utils.scp_to_remote(address, port, username, password,
952 local_path, remote_path, timeout)
lmr6f669ce2009-05-31 19:02:42 +0000953
954
lmrc196d492010-05-07 14:14:26 +0000955 def copy_files_from(self, remote_path, local_path, nic_index=0, timeout=600):
lmr6f669ce2009-05-31 19:02:42 +0000956 """
lmr912c74b2009-08-17 20:43:27 +0000957 Transfer files from the guest.
lmr6f669ce2009-05-31 19:02:42 +0000958
959 @param local_path: Guest path
960 @param remote_path: Host path
lmr912c74b2009-08-17 20:43:27 +0000961 @param nic_index: The index of the NIC to connect to.
lmr6f669ce2009-05-31 19:02:42 +0000962 @param timeout: Time (seconds) before giving up on doing the remote
963 copy.
964 """
965 username = self.params.get("username", "")
966 password = self.params.get("password", "")
lmr912c74b2009-08-17 20:43:27 +0000967 client = self.params.get("file_transfer_client")
lmree90dd92009-08-13 04:13:39 +0000968 address = self.get_address(nic_index)
lmr912c74b2009-08-17 20:43:27 +0000969 port = self.get_port(int(self.params.get("file_transfer_port")))
970
lmree90dd92009-08-13 04:13:39 +0000971 if not address or not port:
972 logging.debug("IP address or port unavailable")
lmr6f669ce2009-05-31 19:02:42 +0000973 return None
lmr6f669ce2009-05-31 19:02:42 +0000974
lmr912c74b2009-08-17 20:43:27 +0000975 if client == "scp":
976 return kvm_utils.scp_from_remote(address, port, username, password,
977 remote_path, local_path, timeout)
lmr6f669ce2009-05-31 19:02:42 +0000978
979
980 def send_key(self, keystr):
981 """
982 Send a key event to the VM.
983
984 @param: keystr: A key event string (e.g. "ctrl-alt-delete")
985 """
986 # For compatibility with versions of QEMU that do not recognize all
987 # key names: replace keyname with the hex value from the dict, which
988 # QEMU will definitely accept
989 dict = { "comma": "0x33",
990 "dot": "0x34",
991 "slash": "0x35" }
992 for key in dict.keys():
993 keystr = keystr.replace(key, dict[key])
994 self.send_monitor_cmd("sendkey %s 1" % keystr)
995 time.sleep(0.2)
996
997
998 def send_string(self, str):
999 """
1000 Send a string to the VM.
1001
1002 @param str: String, that must consist of alphanumeric characters only.
1003 Capital letters are allowed.
1004 """
1005 for char in str:
1006 if char.isupper():
1007 self.send_key("shift-%s" % char.lower())
1008 else:
1009 self.send_key(char)
lmra2533222009-07-20 12:43:46 +00001010
mbligh1ef218d2009-08-03 16:57:56 +00001011
lmra2533222009-07-20 12:43:46 +00001012 def get_uuid(self):
1013 """
1014 Catch UUID of the VM.
1015
1016 @return: None,if not specified in config file
1017 """
1018 if self.params.get("uuid") == "random":
1019 return self.uuid
1020 else:
1021 return self.params.get("uuid", None)
lmrdd2ff922009-12-01 23:39:12 +00001022
1023
1024 def get_cpu_count(self):
1025 """
1026 Get the cpu count of the VM.
1027 """
lmr13426552010-01-17 15:38:41 +00001028 session = self.remote_login()
1029 if not session:
1030 return None
lmrdd2ff922009-12-01 23:39:12 +00001031 try:
lmr13426552010-01-17 15:38:41 +00001032 cmd = self.params.get("cpu_chk_cmd")
1033 s, count = session.get_command_status_output(cmd)
1034 if s == 0:
1035 return int(count)
lmrdd2ff922009-12-01 23:39:12 +00001036 return None
1037 finally:
1038 session.close()
1039
1040
lmr28426c82010-04-16 06:02:58 +00001041 def get_memory_size(self, cmd=None):
lmrdd2ff922009-12-01 23:39:12 +00001042 """
lmr28426c82010-04-16 06:02:58 +00001043 Get bootup memory size of the VM.
1044
1045 @param check_cmd: Command used to check memory. If not provided,
1046 self.params.get("mem_chk_cmd") will be used.
lmrdd2ff922009-12-01 23:39:12 +00001047 """
lmr13426552010-01-17 15:38:41 +00001048 session = self.remote_login()
1049 if not session:
lmrdd2ff922009-12-01 23:39:12 +00001050 return None
lmr13426552010-01-17 15:38:41 +00001051 try:
lmr28426c82010-04-16 06:02:58 +00001052 if not cmd:
1053 cmd = self.params.get("mem_chk_cmd")
lmr13426552010-01-17 15:38:41 +00001054 s, mem_str = session.get_command_status_output(cmd)
1055 if s != 0:
1056 return None
lmr6d69f4d2010-02-12 11:35:55 +00001057 mem = re.findall("([0-9]+)", mem_str)
lmr13426552010-01-17 15:38:41 +00001058 mem_size = 0
1059 for m in mem:
1060 mem_size += int(m)
1061 if "GB" in mem_str:
1062 mem_size *= 1024
1063 elif "MB" in mem_str:
1064 pass
1065 else:
1066 mem_size /= 1024
1067 return int(mem_size)
lmrdd2ff922009-12-01 23:39:12 +00001068 finally:
1069 session.close()
lmr28426c82010-04-16 06:02:58 +00001070
1071
1072 def get_current_memory_size(self):
1073 """
1074 Get current memory size of the VM, rather than bootup memory.
1075 """
1076 cmd = self.params.get("mem_chk_cur_cmd")
1077 return self.get_memory_size(cmd)