blob: 4183f1c569a54d1dacef71862a9c6ed62090519d [file] [log] [blame]
lmr6f669ce2009-05-31 19:02:42 +00001"""
2KVM test utility functions.
3
4@copyright: 2008-2009 Red Hat Inc.
5"""
6
lmr5ab537a2010-06-14 15:38:18 +00007import time, string, random, socket, os, signal, re, logging, commands, cPickle
lmrb635b862009-09-10 14:53:21 +00008from autotest_lib.client.bin import utils
lmr84154412010-02-03 18:34:43 +00009from autotest_lib.client.common_lib import error, logging_config
lmrb635b862009-09-10 14:53:21 +000010import kvm_subprocess
11
lmr6f669ce2009-05-31 19:02:42 +000012
lmre8a66dd2009-09-15 19:51:07 +000013def dump_env(obj, filename):
14 """
15 Dump KVM test environment to a file.
16
17 @param filename: Path to a file where the environment will be dumped to.
18 """
19 file = open(filename, "w")
20 cPickle.dump(obj, file)
21 file.close()
22
23
lmr8b5400c2010-03-23 15:32:29 +000024def load_env(filename, default={}):
lmre8a66dd2009-09-15 19:51:07 +000025 """
26 Load KVM test environment from an environment file.
27
28 @param filename: Path to a file where the environment was dumped to.
29 """
30 try:
31 file = open(filename, "r")
lmr8b5400c2010-03-23 15:32:29 +000032 obj = cPickle.load(file)
33 file.close()
34 return obj
35 # Almost any exception can be raised during unpickling, so let's catch
36 # them all
lmr258f7932010-06-14 15:37:02 +000037 except Exception, e:
38 logging.warn(e)
lmre8a66dd2009-09-15 19:51:07 +000039 return default
lmre8a66dd2009-09-15 19:51:07 +000040
41
lmr6f669ce2009-05-31 19:02:42 +000042def get_sub_dict(dict, name):
43 """
44 Return a "sub-dict" corresponding to a specific object.
45
46 Operate on a copy of dict: for each key that ends with the suffix
47 "_" + name, strip the suffix from the key, and set the value of
48 the stripped key to that of the key. Return the resulting dict.
49
50 @param name: Suffix of the key we want to set the value.
51 """
52 suffix = "_" + name
53 new_dict = dict.copy()
54 for key in dict.keys():
55 if key.endswith(suffix):
56 new_key = key.split(suffix)[0]
57 new_dict[new_key] = dict[key]
58 return new_dict
59
60
61def get_sub_dict_names(dict, keyword):
62 """
63 Return a list of "sub-dict" names that may be extracted with get_sub_dict.
64
65 This function may be modified to change the behavior of all functions that
66 deal with multiple objects defined in dicts (e.g. VMs, images, NICs).
67
68 @param keyword: A key in dict (e.g. "vms", "images", "nics").
69 """
70 names = dict.get(keyword)
71 if names:
72 return names.split()
73 else:
74 return []
75
76
lmrac5089b2009-08-13 04:05:47 +000077# Functions related to MAC/IP addresses
78
79def mac_str_to_int(addr):
80 """
81 Convert MAC address string to integer.
82
83 @param addr: String representing the MAC address.
84 """
85 return sum(int(s, 16) * 256 ** i
86 for i, s in enumerate(reversed(addr.split(":"))))
87
88
89def mac_int_to_str(addr):
90 """
91 Convert MAC address integer to string.
92
93 @param addr: Integer representing the MAC address.
94 """
95 return ":".join("%02x" % (addr >> 8 * i & 0xFF)
96 for i in reversed(range(6)))
97
98
99def ip_str_to_int(addr):
100 """
101 Convert IP address string to integer.
102
103 @param addr: String representing the IP address.
104 """
105 return sum(int(s) * 256 ** i
106 for i, s in enumerate(reversed(addr.split("."))))
107
108
109def ip_int_to_str(addr):
110 """
111 Convert IP address integer to string.
112
113 @param addr: Integer representing the IP address.
114 """
115 return ".".join(str(addr >> 8 * i & 0xFF)
116 for i in reversed(range(4)))
117
118
119def offset_mac(base, offset):
120 """
121 Add offset to a given MAC address.
122
123 @param base: String representing a MAC address.
124 @param offset: Offset to add to base (integer)
125 @return: A string representing the offset MAC address.
126 """
127 return mac_int_to_str(mac_str_to_int(base) + offset)
128
129
130def offset_ip(base, offset):
131 """
132 Add offset to a given IP address.
133
134 @param base: String representing an IP address.
135 @param offset: Offset to add to base (integer)
136 @return: A string representing the offset IP address.
137 """
138 return ip_int_to_str(ip_str_to_int(base) + offset)
139
140
141def get_mac_ip_pair_from_dict(dict):
142 """
143 Fetch a MAC-IP address pair from dict and return it.
144
145 The parameters in dict are expected to conform to a certain syntax.
146 Typical usage may be:
147
148 address_ranges = r1 r2 r3
149
150 address_range_base_mac_r1 = 55:44:33:22:11:00
151 address_range_base_ip_r1 = 10.0.0.0
152 address_range_size_r1 = 16
153
154 address_range_base_mac_r2 = 55:44:33:22:11:40
155 address_range_base_ip_r2 = 10.0.0.60
156 address_range_size_r2 = 25
157
158 address_range_base_mac_r3 = 55:44:33:22:12:10
159 address_range_base_ip_r3 = 10.0.1.20
160 address_range_size_r3 = 230
161
162 address_index = 0
163
164 All parameters except address_index specify a MAC-IP address pool. The
165 pool consists of several MAC-IP address ranges.
166 address_index specified the index of the desired MAC-IP pair from the pool.
167
168 @param dict: The dictionary from which to fetch the addresses.
169 """
170 index = int(dict.get("address_index", 0))
171 for mac_range_name in get_sub_dict_names(dict, "address_ranges"):
172 mac_range_params = get_sub_dict(dict, mac_range_name)
173 mac_base = mac_range_params.get("address_range_base_mac")
174 ip_base = mac_range_params.get("address_range_base_ip")
175 size = int(mac_range_params.get("address_range_size", 1))
176 if index < size:
177 return (mac_base and offset_mac(mac_base, index),
178 ip_base and offset_ip(ip_base, index))
179 index -= size
180 return (None, None)
181
182
lmrf3d3e522010-03-23 16:38:12 +0000183def get_sub_pool(dict, piece, num_pieces):
184 """
185 Split a MAC-IP pool and return a single requested piece.
186
187 For example, get_sub_pool(dict, 0, 3) will split the pool in 3 pieces and
188 return a dict representing the first piece.
189
190 @param dict: A dict that contains pool parameters.
191 @param piece: The index of the requested piece. Should range from 0 to
192 num_pieces - 1.
193 @param num_pieces: The total number of pieces.
194 @return: A copy of dict, modified to describe the requested sub-pool.
195 """
196 range_dicts = [get_sub_dict(dict, name) for name in
197 get_sub_dict_names(dict, "address_ranges")]
198 if not range_dicts:
199 return dict
200 ranges = [[d.get("address_range_base_mac"),
201 d.get("address_range_base_ip"),
202 int(d.get("address_range_size", 1))] for d in range_dicts]
203 total_size = sum(r[2] for r in ranges)
204 base = total_size * piece / num_pieces
205 size = total_size * (piece + 1) / num_pieces - base
206
207 # Find base of current sub-pool
208 for i in range(len(ranges)):
209 r = ranges[i]
210 if base < r[2]:
211 r[0] = r[0] and offset_mac(r[0], base)
212 r[1] = r[1] and offset_ip(r[1], base)
213 r[2] -= base
214 break
215 base -= r[2]
216
217 # Collect ranges up to end of current sub-pool
218 new_ranges = []
219 for i in range(i, len(ranges)):
220 r = ranges[i]
221 new_ranges.append(r)
222 if size <= r[2]:
223 r[2] = size
224 break
225 size -= r[2]
226
227 # Write new dict
228 new_dict = dict.copy()
229 new_dict["address_ranges"] = " ".join("r%d" % i for i in
230 range(len(new_ranges)))
231 for i in range(len(new_ranges)):
232 new_dict["address_range_base_mac_r%d" % i] = new_ranges[i][0]
233 new_dict["address_range_base_ip_r%d" % i] = new_ranges[i][1]
234 new_dict["address_range_size_r%d" % i] = new_ranges[i][2]
235 return new_dict
236
237
lmr53d3e932009-09-09 21:56:18 +0000238def verify_ip_address_ownership(ip, macs, timeout=10.0):
lmree90dd92009-08-13 04:13:39 +0000239 """
lmr53d3e932009-09-09 21:56:18 +0000240 Use arping and the ARP cache to make sure a given IP address belongs to one
241 of the given MAC addresses.
lmree90dd92009-08-13 04:13:39 +0000242
243 @param ip: An IP address.
244 @param macs: A list or tuple of MAC addresses.
245 @return: True iff ip is assigned to a MAC address in macs.
246 """
lmr53d3e932009-09-09 21:56:18 +0000247 # Compile a regex that matches the given IP address and any of the given
248 # MAC addresses
lmree90dd92009-08-13 04:13:39 +0000249 mac_regex = "|".join("(%s)" % mac for mac in macs)
lmre35507b2009-10-28 16:53:08 +0000250 regex = re.compile(r"\b%s\b.*\b(%s)\b" % (ip, mac_regex), re.IGNORECASE)
lmree90dd92009-08-13 04:13:39 +0000251
lmr53d3e932009-09-09 21:56:18 +0000252 # Check the ARP cache
lmr3eb39c72010-07-08 23:34:05 +0000253 o = commands.getoutput("%s -n" % find_command("arp"))
lmre35507b2009-10-28 16:53:08 +0000254 if regex.search(o):
lmree90dd92009-08-13 04:13:39 +0000255 return True
256
lmr53d3e932009-09-09 21:56:18 +0000257 # Get the name of the bridge device for arping
lmr3eb39c72010-07-08 23:34:05 +0000258 o = commands.getoutput("%s route get %s" % (find_command("ip"), ip))
lmr53d3e932009-09-09 21:56:18 +0000259 dev = re.findall("dev\s+\S+", o, re.IGNORECASE)
260 if not dev:
261 return False
262 dev = dev[0].split()[-1]
263
264 # Send an ARP request
lmr3eb39c72010-07-08 23:34:05 +0000265 o = commands.getoutput("%s -f -c 3 -I %s %s" %
266 (find_command("arping"), dev, ip))
lmre35507b2009-10-28 16:53:08 +0000267 return bool(regex.search(o))
lmree90dd92009-08-13 04:13:39 +0000268
269
lmr6f669ce2009-05-31 19:02:42 +0000270# Functions for working with the environment (a dict-like object)
271
272def is_vm(obj):
273 """
274 Tests whether a given object is a VM object.
275
276 @param obj: Python object (pretty much everything on python).
277 """
278 return obj.__class__.__name__ == "VM"
279
280
281def env_get_all_vms(env):
282 """
283 Return a list of all VM objects on a given environment.
284
285 @param env: Dictionary with environment items.
286 """
287 vms = []
288 for obj in env.values():
289 if is_vm(obj):
290 vms.append(obj)
291 return vms
292
293
294def env_get_vm(env, name):
295 """
296 Return a VM object by its name.
297
298 @param name: VM name.
299 """
300 return env.get("vm__%s" % name)
301
302
303def env_register_vm(env, name, vm):
304 """
305 Register a given VM in a given env.
306
307 @param env: Environment where we will register the VM.
308 @param name: VM name.
309 @param vm: VM object.
310 """
311 env["vm__%s" % name] = vm
312
313
314def env_unregister_vm(env, name):
315 """
316 Remove a given VM from a given env.
317
318 @param env: Environment where we will un-register the VM.
319 @param name: VM name.
320 """
321 del env["vm__%s" % name]
322
323
324# Utility functions for dealing with external processes
325
lmr049239c2010-07-08 23:27:18 +0000326def find_command(cmd):
327 for dir in ["/usr/local/sbin", "/usr/local/bin",
328 "/usr/sbin", "/usr/bin", "/sbin", "/bin"]:
329 file = os.path.join(dir, cmd)
330 if os.path.exists(file):
331 return file
332 raise ValueError('Missing command: %s' % cmd)
333
334
lmr6f669ce2009-05-31 19:02:42 +0000335def pid_exists(pid):
336 """
337 Return True if a given PID exists.
338
339 @param pid: Process ID number.
340 """
341 try:
342 os.kill(pid, 0)
343 return True
344 except:
345 return False
346
347
348def safe_kill(pid, signal):
349 """
350 Attempt to send a signal to a given process that may or may not exist.
351
352 @param signal: Signal number.
353 """
354 try:
355 os.kill(pid, signal)
356 return True
357 except:
358 return False
359
360
lmr1aeaefb2009-09-09 22:12:49 +0000361def kill_process_tree(pid, sig=signal.SIGKILL):
362 """Signal a process and all of its children.
363
364 If the process does not exist -- return.
365
366 @param pid: The pid of the process to signal.
367 @param sig: The signal to send to the processes.
368 """
369 if not safe_kill(pid, signal.SIGSTOP):
370 return
371 children = commands.getoutput("ps --ppid=%d -o pid=" % pid).split()
372 for child in children:
373 kill_process_tree(int(child), sig)
374 safe_kill(pid, sig)
375 safe_kill(pid, signal.SIGCONT)
376
377
lmr117bbcf2009-09-15 07:12:39 +0000378def get_latest_kvm_release_tag(release_listing):
lmr3f0b0cc2009-06-10 02:25:23 +0000379 """
380 Fetches the latest release tag for KVM.
381
lmr117bbcf2009-09-15 07:12:39 +0000382 @param release_listing: URL that contains a list of the Source Forge
383 KVM project files.
lmr3f0b0cc2009-06-10 02:25:23 +0000384 """
385 try:
lmr117bbcf2009-09-15 07:12:39 +0000386 release_page = utils.urlopen(release_listing)
387 data = release_page.read()
388 release_page.close()
lmr8ea274b2009-07-06 13:42:35 +0000389 rx = re.compile("kvm-(\d+).tar.gz", re.IGNORECASE)
lmr3f0b0cc2009-06-10 02:25:23 +0000390 matches = rx.findall(data)
lmr32525382009-08-10 13:53:37 +0000391 # In all regexp matches to something that looks like a release tag,
392 # get the largest integer. That will be our latest release tag.
393 latest_tag = max(int(x) for x in matches)
394 return str(latest_tag)
lmr3f0b0cc2009-06-10 02:25:23 +0000395 except Exception, e:
396 message = "Could not fetch latest KVM release tag: %s" % str(e)
397 logging.error(message)
398 raise error.TestError(message)
399
400
401def get_git_branch(repository, branch, srcdir, commit=None, lbranch=None):
402 """
403 Retrieves a given git code repository.
404
405 @param repository: Git repository URL
406 """
lmr160e9942010-06-09 14:09:19 +0000407 logging.info("Fetching git [REP '%s' BRANCH '%s' COMMIT '%s'] -> %s",
lmr3f0b0cc2009-06-10 02:25:23 +0000408 repository, branch, commit, srcdir)
409 if not os.path.exists(srcdir):
410 os.makedirs(srcdir)
411 os.chdir(srcdir)
412
413 if os.path.exists(".git"):
414 utils.system("git reset --hard")
415 else:
416 utils.system("git init")
417
418 if not lbranch:
419 lbranch = branch
420
421 utils.system("git fetch -q -f -u -t %s %s:%s" %
422 (repository, branch, lbranch))
423 utils.system("git checkout %s" % lbranch)
424 if commit:
425 utils.system("git checkout %s" % commit)
426
427 h = utils.system_output('git log --pretty=format:"%H" -1')
lmr05cec0f2010-01-26 17:50:29 +0000428 try:
429 desc = "tag %s" % utils.system_output("git describe")
430 except error.CmdError:
431 desc = "no tag found"
432
lmr3f0b0cc2009-06-10 02:25:23 +0000433 logging.info("Commit hash for %s is %s (%s)" % (repository, h.strip(),
434 desc))
435 return srcdir
436
437
lmr3f0b0cc2009-06-10 02:25:23 +0000438def check_kvm_source_dir(source_dir):
439 """
440 Inspects the kvm source directory and verifies its disposition. In some
441 occasions build may be dependant on the source directory disposition.
442 The reason why the return codes are numbers is that we might have more
443 changes on the source directory layout, so it's not scalable to just use
444 strings like 'old_repo', 'new_repo' and such.
445
446 @param source_dir: Source code path that will be inspected.
447 """
448 os.chdir(source_dir)
449 has_qemu_dir = os.path.isdir('qemu')
450 has_kvm_dir = os.path.isdir('kvm')
451 if has_qemu_dir and not has_kvm_dir:
452 logging.debug("qemu directory detected, source dir layout 1")
453 return 1
454 if has_kvm_dir and not has_qemu_dir:
455 logging.debug("kvm directory detected, source dir layout 2")
456 return 2
457 else:
458 raise error.TestError("Unknown source dir layout, cannot proceed.")
459
460
lmrf9349c32009-07-23 01:44:24 +0000461# The following are functions used for SSH, SCP and Telnet communication with
462# guests.
lmr6f669ce2009-05-31 19:02:42 +0000463
lmra4cd1f12010-06-22 02:01:00 +0000464def _remote_login(session, username, password, prompt, timeout=10):
lmr6f669ce2009-05-31 19:02:42 +0000465 """
lmr158604f2010-06-22 01:57:34 +0000466 Log into a remote host (guest) using SSH or Telnet. Wait for questions
467 and provide answers. If timeout expires while waiting for output from the
468 child (e.g. a password prompt or a shell prompt) -- fail.
lmr6f669ce2009-05-31 19:02:42 +0000469
470 @brief: Log into a remote host (guest) using SSH or Telnet.
471
lmr158604f2010-06-22 01:57:34 +0000472 @param session: A kvm_expect or kvm_shell_session instance to operate on
lmra4cd1f12010-06-22 02:01:00 +0000473 @param username: The username to send in reply to a login prompt
lmr6f669ce2009-05-31 19:02:42 +0000474 @param password: The password to send in reply to a password prompt
475 @param prompt: The shell prompt that indicates a successful login
lmr6f669ce2009-05-31 19:02:42 +0000476 @param timeout: The maximal time duration (in seconds) to wait for each
477 step of the login procedure (i.e. the "Are you sure" prompt, the
478 password prompt, the shell prompt, etc)
479
lmr158604f2010-06-22 01:57:34 +0000480 @return: True on success and False otherwise.
lmr6f669ce2009-05-31 19:02:42 +0000481 """
lmr6f669ce2009-05-31 19:02:42 +0000482 password_prompt_count = 0
lmra4cd1f12010-06-22 02:01:00 +0000483 login_prompt_count = 0
lmr6f669ce2009-05-31 19:02:42 +0000484
lmr6f669ce2009-05-31 19:02:42 +0000485 while True:
lmr158604f2010-06-22 01:57:34 +0000486 (match, text) = session.read_until_last_line_matches(
lmr2c502672010-06-22 02:02:19 +0000487 [r"[Aa]re you sure", r"[Pp]assword:\s*$", r"[Ll]ogin:\s*$",
lmrba69bc52010-03-25 01:50:09 +0000488 r"[Cc]onnection.*closed", r"[Cc]onnection.*refused",
489 r"[Pp]lease wait", prompt],
lmr6f669ce2009-05-31 19:02:42 +0000490 timeout=timeout, internal_timeout=0.5)
491 if match == 0: # "Are you sure you want to continue connecting"
492 logging.debug("Got 'Are you sure...'; sending 'yes'")
lmr158604f2010-06-22 01:57:34 +0000493 session.sendline("yes")
lmr6f669ce2009-05-31 19:02:42 +0000494 continue
495 elif match == 1: # "password:"
496 if password_prompt_count == 0:
497 logging.debug("Got password prompt; sending '%s'" % password)
lmr158604f2010-06-22 01:57:34 +0000498 session.sendline(password)
lmr6f669ce2009-05-31 19:02:42 +0000499 password_prompt_count += 1
500 continue
501 else:
502 logging.debug("Got password prompt again")
lmr158604f2010-06-22 01:57:34 +0000503 return False
lmr6f669ce2009-05-31 19:02:42 +0000504 elif match == 2: # "login:"
lmra4cd1f12010-06-22 02:01:00 +0000505 if login_prompt_count == 0:
506 logging.debug("Got username prompt; sending '%s'" % username)
507 session.sendline(username)
508 login_prompt_count += 1
509 continue
510 else:
511 logging.debug("Got username prompt again")
512 return False
lmr6f669ce2009-05-31 19:02:42 +0000513 elif match == 3: # "Connection closed"
514 logging.debug("Got 'Connection closed'")
lmr158604f2010-06-22 01:57:34 +0000515 return False
lmr3ca79fe2009-06-10 19:24:26 +0000516 elif match == 4: # "Connection refused"
lmr0d2ed1f2009-07-01 03:23:18 +0000517 logging.debug("Got 'Connection refused'")
lmr158604f2010-06-22 01:57:34 +0000518 return False
lmrba69bc52010-03-25 01:50:09 +0000519 elif match == 5: # "Please wait"
520 logging.debug("Got 'Please wait'")
521 timeout = 30
522 continue
523 elif match == 6: # prompt
lmr6f669ce2009-05-31 19:02:42 +0000524 logging.debug("Got shell prompt -- logged in")
lmr158604f2010-06-22 01:57:34 +0000525 return session
lmr6f669ce2009-05-31 19:02:42 +0000526 else: # match == None
lmr3ca79fe2009-06-10 19:24:26 +0000527 logging.debug("Timeout elapsed or process terminated")
lmr158604f2010-06-22 01:57:34 +0000528 return False
529
530
531def _remote_scp(session, password, transfer_timeout=600, login_timeout=10):
532 """
533 Transfer file(s) to a remote host (guest) using SCP. Wait for questions
534 and provide answers. If login_timeout expires while waiting for output
535 from the child (e.g. a password prompt), fail. If transfer_timeout expires
536 while waiting for the transfer to complete, fail.
537
538 @brief: Transfer files using SCP, given a command line.
539
540 @param session: A kvm_expect or kvm_shell_session instance to operate on
541 @param password: The password to send in reply to a password prompt.
542 @param transfer_timeout: The time duration (in seconds) to wait for the
543 transfer to complete.
544 @param login_timeout: The maximal time duration (in seconds) to wait for
545 each step of the login procedure (i.e. the "Are you sure" prompt or
546 the password prompt)
547
548 @return: True if the transfer succeeds and False on failure.
549 """
550 password_prompt_count = 0
551 timeout = login_timeout
552
553 while True:
554 (match, text) = session.read_until_last_line_matches(
555 [r"[Aa]re you sure", r"[Pp]assword:\s*$", r"lost connection"],
556 timeout=timeout, internal_timeout=0.5)
557 if match == 0: # "Are you sure you want to continue connecting"
558 logging.debug("Got 'Are you sure...'; sending 'yes'")
559 session.sendline("yes")
560 continue
561 elif match == 1: # "password:"
562 if password_prompt_count == 0:
563 logging.debug("Got password prompt; sending '%s'" % password)
564 session.sendline(password)
565 password_prompt_count += 1
566 timeout = transfer_timeout
567 continue
568 else:
569 logging.debug("Got password prompt again")
570 return False
571 elif match == 2: # "lost connection"
572 logging.debug("Got 'lost connection'")
573 return False
574 else: # match == None
575 if session.is_alive():
576 logging.debug("Timeout expired")
577 return False
578 else:
579 status = session.get_status()
580 logging.debug("SCP process terminated with status %s", status)
581 return status == 0
582
583
584def remote_login(client, host, port, username, password, prompt, linesep="\n",
lmre56903f2010-06-22 02:09:35 +0000585 log_filename=None, timeout=10):
lmr158604f2010-06-22 01:57:34 +0000586 """
587 Log into a remote host (guest) using SSH/Telnet/Netcat.
588
589 @param client: The client to use ('ssh', 'telnet' or 'nc')
590 @param host: Hostname or IP address
591 @param port: Port to connect to
592 @param username: Username (if required)
593 @param password: Password (if required)
594 @param prompt: Shell prompt (regular expression)
595 @param linesep: The line separator to use when sending lines
596 (e.g. '\\n' or '\\r\\n')
lmre56903f2010-06-22 02:09:35 +0000597 @param log_filename: If specified, log all output to this file
lmr158604f2010-06-22 01:57:34 +0000598 @param timeout: The maximal time duration (in seconds) to wait for
599 each step of the login procedure (i.e. the "Are you sure" prompt
600 or the password prompt)
601
602 @return: kvm_shell_session object on success and None on failure.
603 """
604 if client == "ssh":
605 cmd = ("ssh -o UserKnownHostsFile=/dev/null "
606 "-o PreferredAuthentications=password -p %s %s@%s" %
607 (port, username, host))
608 elif client == "telnet":
609 cmd = "telnet -l %s %s %s" % (username, host, port)
610 elif client == "nc":
611 cmd = "nc %s %s" % (host, port)
612 else:
613 logging.error("Unknown remote shell client: %s" % client)
614 return
lmre56903f2010-06-22 02:09:35 +0000615
lmr158604f2010-06-22 01:57:34 +0000616 logging.debug("Trying to login with command '%s'" % cmd)
617 session = kvm_subprocess.kvm_shell_session(cmd, linesep=linesep,
618 prompt=prompt)
lmra4cd1f12010-06-22 02:01:00 +0000619 if _remote_login(session, username, password, prompt, timeout):
lmre56903f2010-06-22 02:09:35 +0000620 if log_filename:
621 session.set_output_func(log_line)
622 session.set_output_params((log_filename,))
lmr158604f2010-06-22 01:57:34 +0000623 return session
624 else:
625 session.close()
lmr6f669ce2009-05-31 19:02:42 +0000626
627
lmre56903f2010-06-22 02:09:35 +0000628def remote_scp(command, password, log_filename=None, transfer_timeout=600,
629 login_timeout=10):
lmr6f669ce2009-05-31 19:02:42 +0000630 """
lmr158604f2010-06-22 01:57:34 +0000631 Transfer file(s) to a remote host (guest) using SCP.
lmr6f669ce2009-05-31 19:02:42 +0000632
633 @brief: Transfer files using SCP, given a command line.
634
635 @param command: The command to execute
636 (e.g. "scp -r foobar root@localhost:/tmp/").
637 @param password: The password to send in reply to a password prompt.
lmre56903f2010-06-22 02:09:35 +0000638 @param log_filename: If specified, log all output to this file
lmrc5f42a32010-06-18 14:15:19 +0000639 @param transfer_timeout: The time duration (in seconds) to wait for the
lmr158604f2010-06-22 01:57:34 +0000640 transfer to complete.
lmr6f669ce2009-05-31 19:02:42 +0000641 @param login_timeout: The maximal time duration (in seconds) to wait for
lmr158604f2010-06-22 01:57:34 +0000642 each step of the login procedure (i.e. the "Are you sure" prompt
643 or the password prompt)
lmr6f669ce2009-05-31 19:02:42 +0000644
645 @return: True if the transfer succeeds and False on failure.
646 """
lmr158604f2010-06-22 01:57:34 +0000647 logging.debug("Trying to SCP with command '%s', timeout %ss",
648 command, transfer_timeout)
lmre56903f2010-06-22 02:09:35 +0000649
650 if log_filename:
651 output_func = log_line
652 output_params = (log_filename,)
653 else:
654 output_func = None
655 output_params = ()
656
657 session = kvm_subprocess.kvm_expect(command,
658 output_func=output_func,
659 output_params=output_params)
lmr158604f2010-06-22 01:57:34 +0000660 try:
661 return _remote_scp(session, password, transfer_timeout, login_timeout)
662 finally:
663 session.close()
lmr6f669ce2009-05-31 19:02:42 +0000664
665
666def scp_to_remote(host, port, username, password, local_path, remote_path,
lmre56903f2010-06-22 02:09:35 +0000667 log_filename=None, timeout=600):
lmr6f669ce2009-05-31 19:02:42 +0000668 """
669 Copy files to a remote host (guest).
670
lmr912c74b2009-08-17 20:43:27 +0000671 @param host: Hostname or IP address
672 @param username: Username (if required)
673 @param password: Password (if required)
lmr6f669ce2009-05-31 19:02:42 +0000674 @param local_path: Path on the local machine where we are copying from
675 @param remote_path: Path on the remote machine where we are copying to
lmre56903f2010-06-22 02:09:35 +0000676 @param log_filename: If specified, log all output to this file
lmr158604f2010-06-22 01:57:34 +0000677 @param timeout: The time duration (in seconds) to wait for the transfer
678 to complete.
lmr6f669ce2009-05-31 19:02:42 +0000679
680 @return: True on success and False on failure.
681 """
lmrc196d492010-05-07 14:14:26 +0000682 command = ("scp -v -o UserKnownHostsFile=/dev/null "
lmr1b7e1702009-11-10 16:30:39 +0000683 "-o PreferredAuthentications=password -r -P %s %s %s@%s:%s" %
lmrd16a67d2009-06-10 19:52:59 +0000684 (port, local_path, username, host, remote_path))
lmre56903f2010-06-22 02:09:35 +0000685 return remote_scp(command, password, log_filename, timeout)
lmr6f669ce2009-05-31 19:02:42 +0000686
687
688def scp_from_remote(host, port, username, password, remote_path, local_path,
lmre56903f2010-06-22 02:09:35 +0000689 log_filename=None, timeout=600):
lmr6f669ce2009-05-31 19:02:42 +0000690 """
691 Copy files from a remote host (guest).
692
lmr912c74b2009-08-17 20:43:27 +0000693 @param host: Hostname or IP address
694 @param username: Username (if required)
695 @param password: Password (if required)
lmr6f669ce2009-05-31 19:02:42 +0000696 @param local_path: Path on the local machine where we are copying from
697 @param remote_path: Path on the remote machine where we are copying to
lmre56903f2010-06-22 02:09:35 +0000698 @param log_filename: If specified, log all output to this file
lmr158604f2010-06-22 01:57:34 +0000699 @param timeout: The time duration (in seconds) to wait for the transfer
700 to complete.
lmr6f669ce2009-05-31 19:02:42 +0000701
702 @return: True on success and False on failure.
703 """
lmrc196d492010-05-07 14:14:26 +0000704 command = ("scp -v -o UserKnownHostsFile=/dev/null "
lmr1b7e1702009-11-10 16:30:39 +0000705 "-o PreferredAuthentications=password -r -P %s %s@%s:%s %s" %
lmrd16a67d2009-06-10 19:52:59 +0000706 (port, username, host, remote_path, local_path))
lmre56903f2010-06-22 02:09:35 +0000707 return remote_scp(command, password, log_filename, timeout)
lmr6f669ce2009-05-31 19:02:42 +0000708
709
lmr6f669ce2009-05-31 19:02:42 +0000710# The following are utility functions related to ports.
711
lmr6f669ce2009-05-31 19:02:42 +0000712def is_port_free(port):
713 """
714 Return True if the given port is available for use.
715
716 @param port: Port number
717 """
718 try:
719 s = socket.socket()
720 #s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
721 s.bind(("localhost", port))
722 free = True
723 except socket.error:
724 free = False
725 s.close()
726 return free
727
728
729def find_free_port(start_port, end_port):
730 """
lmra29a5cb2010-03-18 02:39:34 +0000731 Return a host free port in the range [start_port, end_port].
lmr6f669ce2009-05-31 19:02:42 +0000732
733 @param start_port: First port that will be checked.
734 @param end_port: Port immediately after the last one that will be checked.
735 """
736 for i in range(start_port, end_port):
737 if is_port_free(i):
738 return i
739 return None
740
741
742def find_free_ports(start_port, end_port, count):
743 """
lmra29a5cb2010-03-18 02:39:34 +0000744 Return count of host free ports in the range [start_port, end_port].
lmr6f669ce2009-05-31 19:02:42 +0000745
746 @count: Initial number of ports known to be free in the range.
747 @param start_port: First port that will be checked.
748 @param end_port: Port immediately after the last one that will be checked.
749 """
750 ports = []
751 i = start_port
752 while i < end_port and count > 0:
753 if is_port_free(i):
754 ports.append(i)
755 count -= 1
756 i += 1
757 return ports
758
759
lmr23894542010-06-22 01:54:37 +0000760# An easy way to log lines to files when the logging system can't be used
761
762_open_log_files = {}
763_log_file_dir = "/tmp"
764
765
766def log_line(filename, line):
767 """
768 Write a line to a file. '\n' is appended to the line.
769
770 @param filename: Path of file to write to, either absolute or relative to
771 the dir set by set_log_file_dir().
772 @param line: Line to write.
773 """
774 global _open_log_files, _log_file_dir
775 if filename not in _open_log_files:
776 path = get_path(_log_file_dir, filename)
777 try:
778 os.makedirs(os.path.dirname(path))
779 except OSError:
780 pass
781 _open_log_files[filename] = open(path, "w")
782 timestr = time.strftime("%Y-%m-%d %H:%M:%S")
783 _open_log_files[filename].write("%s: %s\n" % (timestr, line))
784 _open_log_files[filename].flush()
785
786
787def set_log_file_dir(dir):
788 """
789 Set the base directory for log files created by log_line().
790
791 @param dir: Directory for log files.
792 """
793 global _log_file_dir
794 _log_file_dir = dir
795
796
lmr6f669ce2009-05-31 19:02:42 +0000797# The following are miscellaneous utility functions.
798
lmrb4954e02009-08-17 20:44:42 +0000799def get_path(base_path, user_path):
800 """
801 Translate a user specified path to a real path.
802 If user_path is relative, append it to base_path.
803 If user_path is absolute, return it as is.
804
805 @param base_path: The base path of relative user specified paths.
806 @param user_path: The user specified path.
807 """
808 if os.path.isabs(user_path):
809 return user_path
810 else:
811 return os.path.join(base_path, user_path)
812
813
lmr6f669ce2009-05-31 19:02:42 +0000814def generate_random_string(length):
815 """
816 Return a random string using alphanumeric characters.
817
818 @length: length of the string that will be generated.
819 """
lmr45fc0c22009-09-15 05:16:45 +0000820 r = random.SystemRandom()
lmr6f669ce2009-05-31 19:02:42 +0000821 str = ""
822 chars = string.letters + string.digits
823 while length > 0:
lmr45fc0c22009-09-15 05:16:45 +0000824 str += r.choice(chars)
lmr6f669ce2009-05-31 19:02:42 +0000825 length -= 1
826 return str
827
lmr42b16662010-06-22 11:55:23 +0000828def generate_random_id():
829 """
830 Return a random string suitable for use as a qemu id.
831 """
832 return "id" + generate_random_string(6)
833
lmr6f669ce2009-05-31 19:02:42 +0000834
lmr0bee2342010-02-24 00:01:37 +0000835def generate_tmp_file_name(file, ext=None, dir='/tmp/'):
836 """
837 Returns a temporary file name. The file is not created.
838 """
839 while True:
840 file_name = (file + '-' + time.strftime("%Y%m%d-%H%M%S-") +
841 generate_random_string(4))
842 if ext:
843 file_name += '.' + ext
844 file_name = os.path.join(dir, file_name)
845 if not os.path.exists(file_name):
846 break
847
848 return file_name
849
850
lmr6f669ce2009-05-31 19:02:42 +0000851def format_str_for_message(str):
852 """
853 Format str so that it can be appended to a message.
854 If str consists of one line, prefix it with a space.
855 If str consists of multiple lines, prefix it with a newline.
856
857 @param str: string that will be formatted.
858 """
lmr57355592009-08-07 21:55:49 +0000859 lines = str.splitlines()
860 num_lines = len(lines)
861 str = "\n".join(lines)
lmr6f669ce2009-05-31 19:02:42 +0000862 if num_lines == 0:
863 return ""
864 elif num_lines == 1:
865 return " " + str
866 else:
867 return "\n" + str
868
869
870def wait_for(func, timeout, first=0.0, step=1.0, text=None):
871 """
872 If func() evaluates to True before timeout expires, return the
873 value of func(). Otherwise return None.
874
875 @brief: Wait until func() evaluates to True.
876
877 @param timeout: Timeout in seconds
878 @param first: Time to sleep before first attempt
879 @param steps: Time to sleep between attempts in seconds
880 @param text: Text to print while waiting, for debug purposes
881 """
882 start_time = time.time()
883 end_time = time.time() + timeout
884
885 time.sleep(first)
886
887 while time.time() < end_time:
888 if text:
889 logging.debug("%s (%f secs)" % (text, time.time() - start_time))
890
891 output = func()
892 if output:
893 return output
894
895 time.sleep(step)
896
897 logging.debug("Timeout elapsed")
898 return None
899
900
lmr03ba22e2009-10-23 12:07:44 +0000901def get_hash_from_file(hash_path, dvd_basename):
902 """
903 Get the a hash from a given DVD image from a hash file
904 (Hash files are usually named MD5SUM or SHA1SUM and are located inside the
905 download directories of the DVDs)
906
907 @param hash_path: Local path to a hash file.
908 @param cd_image: Basename of a CD image
909 """
910 hash_file = open(hash_path, 'r')
911 for line in hash_file.readlines():
912 if dvd_basename in line:
913 return line.split()[0]
914
915
lmr43beef12009-12-11 21:03:36 +0000916def run_tests(test_list, job):
917 """
918 Runs the sequence of KVM tests based on the list of dictionaries
919 generated by the configuration system, handling dependencies.
920
921 @param test_list: List with all dictionary test parameters.
922 @param job: Autotest job object.
923
924 @return: True, if all tests ran passed, False if any of them failed.
925 """
926 status_dict = {}
lmr43beef12009-12-11 21:03:36 +0000927 failed = False
lmr5df6eb42010-03-23 15:34:16 +0000928
lmr43beef12009-12-11 21:03:36 +0000929 for dict in test_list:
930 if dict.get("skip") == "yes":
931 continue
932 dependencies_satisfied = True
933 for dep in dict.get("depend"):
934 for test_name in status_dict.keys():
935 if not dep in test_name:
936 continue
937 if not status_dict[test_name]:
938 dependencies_satisfied = False
939 break
940 if dependencies_satisfied:
941 test_iterations = int(dict.get("iterations", 1))
lmr7da99b22010-01-12 22:30:28 +0000942 test_tag = dict.get("shortname")
lmrd960a722010-04-01 02:32:59 +0000943 # Setting up profilers during test execution.
944 profilers = dict.get("profilers", "").split()
945 for profiler in profilers:
946 job.profilers.add(profiler)
lmr7da99b22010-01-12 22:30:28 +0000947
lmr7da99b22010-01-12 22:30:28 +0000948 # We need only one execution, profiled, hence we're passing
949 # the profile_only parameter to job.run_test().
950 current_status = job.run_test("kvm", params=dict, tag=test_tag,
951 iterations=test_iterations,
lmrd960a722010-04-01 02:32:59 +0000952 profile_only= bool(profilers) or None)
953
954 for profiler in profilers:
955 job.profilers.delete(profiler)
lmr7da99b22010-01-12 22:30:28 +0000956
lmr43beef12009-12-11 21:03:36 +0000957 if not current_status:
958 failed = True
959 else:
960 current_status = False
961 status_dict[dict.get("name")] = current_status
962
963 return not failed
964
965
966def create_report(report_dir, results_dir):
967 """
968 Creates a neatly arranged HTML results report in the results dir.
969
970 @param report_dir: Directory where the report script is located.
971 @param results_dir: Directory where the results will be output.
972 """
973 reporter = os.path.join(report_dir, 'html_report.py')
974 html_file = os.path.join(results_dir, 'results.html')
975 os.system('%s -r %s -f %s -R' % (reporter, results_dir, html_file))
lmr31af3a12010-01-18 16:46:52 +0000976
977
978def get_full_pci_id(pci_id):
979 """
980 Get full PCI ID of pci_id.
981
982 @param pci_id: PCI ID of a device.
983 """
984 cmd = "lspci -D | awk '/%s/ {print $1}'" % pci_id
985 status, full_id = commands.getstatusoutput(cmd)
986 if status != 0:
987 return None
988 return full_id
989
990
991def get_vendor_from_pci_id(pci_id):
992 """
993 Check out the device vendor ID according to pci_id.
994
995 @param pci_id: PCI ID of a device.
996 """
997 cmd = "lspci -n | awk '/%s/ {print $3}'" % pci_id
998 return re.sub(":", " ", commands.getoutput(cmd))
999
1000
lmr84154412010-02-03 18:34:43 +00001001class KvmLoggingConfig(logging_config.LoggingConfig):
1002 """
1003 Used with the sole purpose of providing convenient logging setup
1004 for the KVM test auxiliary programs.
1005 """
1006 def configure_logging(self, results_dir=None, verbose=False):
1007 super(KvmLoggingConfig, self).configure_logging(use_console=True,
1008 verbose=verbose)
1009
1010
lmr31af3a12010-01-18 16:46:52 +00001011class PciAssignable(object):
1012 """
1013 Request PCI assignable devices on host. It will check whether to request
1014 PF (physical Functions) or VF (Virtual Functions).
1015 """
lmr83d3b1a2010-01-19 08:14:36 +00001016 def __init__(self, type="vf", driver=None, driver_option=None,
lmr31af3a12010-01-18 16:46:52 +00001017 names=None, devices_requested=None):
1018 """
1019 Initialize parameter 'type' which could be:
lmr83d3b1a2010-01-19 08:14:36 +00001020 vf: Virtual Functions
1021 pf: Physical Function (actual hardware)
lmr31af3a12010-01-18 16:46:52 +00001022 mixed: Both includes VFs and PFs
1023
1024 If pass through Physical NIC cards, we need to specify which devices
1025 to be assigned, e.g. 'eth1 eth2'.
1026
1027 If pass through Virtual Functions, we need to specify how many vfs
1028 are going to be assigned, e.g. passthrough_count = 8 and max_vfs in
1029 config file.
1030
1031 @param type: PCI device type.
1032 @param driver: Kernel module for the PCI assignable device.
1033 @param driver_option: Module option to specify the maximum number of
1034 VFs (eg 'max_vfs=7')
1035 @param names: Physical NIC cards correspondent network interfaces,
1036 e.g.'eth1 eth2 ...'
1037 @param devices_requested: Number of devices being requested.
1038 """
1039 self.type = type
1040 self.driver = driver
1041 self.driver_option = driver_option
1042 if names:
1043 self.name_list = names.split()
1044 if devices_requested:
1045 self.devices_requested = int(devices_requested)
1046 else:
1047 self.devices_requested = None
1048
1049
1050 def _get_pf_pci_id(self, name, search_str):
1051 """
1052 Get the PF PCI ID according to name.
1053
1054 @param name: Name of the PCI device.
1055 @param search_str: Search string to be used on lspci.
1056 """
1057 cmd = "ethtool -i %s | awk '/bus-info/ {print $2}'" % name
1058 s, pci_id = commands.getstatusoutput(cmd)
1059 if not (s or "Cannot get driver information" in pci_id):
1060 return pci_id[5:]
1061 cmd = "lspci | awk '/%s/ {print $1}'" % search_str
1062 pci_ids = [id for id in commands.getoutput(cmd).splitlines()]
1063 nic_id = int(re.search('[0-9]+', name).group(0))
1064 if (len(pci_ids) - 1) < nic_id:
1065 return None
1066 return pci_ids[nic_id]
1067
1068
1069 def _release_dev(self, pci_id):
1070 """
1071 Release a single PCI device.
1072
1073 @param pci_id: PCI ID of a given PCI device.
1074 """
1075 base_dir = "/sys/bus/pci"
1076 full_id = get_full_pci_id(pci_id)
1077 vendor_id = get_vendor_from_pci_id(pci_id)
1078 drv_path = os.path.join(base_dir, "devices/%s/driver" % full_id)
1079 if 'pci-stub' in os.readlink(drv_path):
1080 cmd = "echo '%s' > %s/new_id" % (vendor_id, drv_path)
1081 if os.system(cmd):
1082 return False
1083
1084 stub_path = os.path.join(base_dir, "drivers/pci-stub")
1085 cmd = "echo '%s' > %s/unbind" % (full_id, stub_path)
1086 if os.system(cmd):
1087 return False
1088
1089 driver = self.dev_drivers[pci_id]
1090 cmd = "echo '%s' > %s/bind" % (full_id, driver)
1091 if os.system(cmd):
1092 return False
1093
1094 return True
1095
1096
1097 def get_vf_devs(self):
1098 """
1099 Catch all VFs PCI IDs.
1100
1101 @return: List with all PCI IDs for the Virtual Functions avaliable
1102 """
1103 if not self.sr_iov_setup():
1104 return []
1105
1106 cmd = "lspci | awk '/Virtual Function/ {print $1}'"
1107 return commands.getoutput(cmd).split()
1108
1109
1110 def get_pf_devs(self):
1111 """
1112 Catch all PFs PCI IDs.
1113
1114 @return: List with all PCI IDs for the physical hardware requested
1115 """
1116 pf_ids = []
1117 for name in self.name_list:
1118 pf_id = self._get_pf_pci_id(name, "Ethernet")
1119 if not pf_id:
1120 continue
1121 pf_ids.append(pf_id)
1122 return pf_ids
1123
1124
1125 def get_devs(self, count):
1126 """
1127 Check out all devices' PCI IDs according to their name.
1128
1129 @param count: count number of PCI devices needed for pass through
1130 @return: a list of all devices' PCI IDs
1131 """
lmr83d3b1a2010-01-19 08:14:36 +00001132 if self.type == "vf":
lmr31af3a12010-01-18 16:46:52 +00001133 vf_ids = self.get_vf_devs()
lmr83d3b1a2010-01-19 08:14:36 +00001134 elif self.type == "pf":
lmr31af3a12010-01-18 16:46:52 +00001135 vf_ids = self.get_pf_devs()
1136 elif self.type == "mixed":
1137 vf_ids = self.get_vf_devs()
1138 vf_ids.extend(self.get_pf_devs())
1139 return vf_ids[0:count]
1140
1141
1142 def get_vfs_count(self):
1143 """
1144 Get VFs count number according to lspci.
1145 """
lmr224a5412010-03-17 12:00:36 +00001146 # FIXME: Need to think out a method of identify which
1147 # 'virtual function' belongs to which physical card considering
1148 # that if the host has more than one 82576 card. PCI_ID?
lmr31af3a12010-01-18 16:46:52 +00001149 cmd = "lspci | grep 'Virtual Function' | wc -l"
lmr224a5412010-03-17 12:00:36 +00001150 return int(commands.getoutput(cmd))
lmr31af3a12010-01-18 16:46:52 +00001151
1152
1153 def check_vfs_count(self):
1154 """
1155 Check VFs count number according to the parameter driver_options.
1156 """
lmr224a5412010-03-17 12:00:36 +00001157 # Network card 82576 has two network interfaces and each can be
1158 # virtualized up to 7 virtual functions, therefore we multiply
1159 # two for the value of driver_option 'max_vfs'.
1160 expected_count = int((re.findall("(\d)", self.driver_option)[0])) * 2
1161 return (self.get_vfs_count == expected_count)
lmr31af3a12010-01-18 16:46:52 +00001162
1163
1164 def is_binded_to_stub(self, full_id):
1165 """
1166 Verify whether the device with full_id is already binded to pci-stub.
1167
1168 @param full_id: Full ID for the given PCI device
1169 """
1170 base_dir = "/sys/bus/pci"
1171 stub_path = os.path.join(base_dir, "drivers/pci-stub")
1172 if os.path.exists(os.path.join(stub_path, full_id)):
1173 return True
1174 return False
1175
1176
1177 def sr_iov_setup(self):
1178 """
1179 Ensure the PCI device is working in sr_iov mode.
1180
1181 Check if the PCI hardware device drive is loaded with the appropriate,
1182 parameters (number of VFs), and if it's not, perform setup.
1183
1184 @return: True, if the setup was completed successfuly, False otherwise.
1185 """
1186 re_probe = False
1187 s, o = commands.getstatusoutput('lsmod | grep %s' % self.driver)
1188 if s:
1189 re_probe = True
1190 elif not self.check_vfs_count():
1191 os.system("modprobe -r %s" % self.driver)
1192 re_probe = True
lmr224a5412010-03-17 12:00:36 +00001193 else:
1194 return True
lmr31af3a12010-01-18 16:46:52 +00001195
1196 # Re-probe driver with proper number of VFs
1197 if re_probe:
1198 cmd = "modprobe %s %s" % (self.driver, self.driver_option)
lmr224a5412010-03-17 12:00:36 +00001199 logging.info("Loading the driver '%s' with option '%s'" %
1200 (self.driver, self.driver_option))
lmr31af3a12010-01-18 16:46:52 +00001201 s, o = commands.getstatusoutput(cmd)
1202 if s:
1203 return False
lmr31af3a12010-01-18 16:46:52 +00001204 return True
1205
1206
1207 def request_devs(self):
1208 """
1209 Implement setup process: unbind the PCI device and then bind it
1210 to the pci-stub driver.
1211
1212 @return: a list of successfully requested devices' PCI IDs.
1213 """
1214 base_dir = "/sys/bus/pci"
1215 stub_path = os.path.join(base_dir, "drivers/pci-stub")
1216
1217 self.pci_ids = self.get_devs(self.devices_requested)
lmrbc72f082010-02-08 10:02:40 +00001218 logging.debug("The following pci_ids were found: %s", self.pci_ids)
lmr31af3a12010-01-18 16:46:52 +00001219 requested_pci_ids = []
1220 self.dev_drivers = {}
1221
1222 # Setup all devices specified for assignment to guest
1223 for pci_id in self.pci_ids:
1224 full_id = get_full_pci_id(pci_id)
1225 if not full_id:
1226 continue
1227 drv_path = os.path.join(base_dir, "devices/%s/driver" % full_id)
1228 dev_prev_driver= os.path.realpath(os.path.join(drv_path,
1229 os.readlink(drv_path)))
1230 self.dev_drivers[pci_id] = dev_prev_driver
1231
1232 # Judge whether the device driver has been binded to stub
1233 if not self.is_binded_to_stub(full_id):
lmrbc72f082010-02-08 10:02:40 +00001234 logging.debug("Binding device %s to stub", full_id)
lmr31af3a12010-01-18 16:46:52 +00001235 vendor_id = get_vendor_from_pci_id(pci_id)
1236 stub_new_id = os.path.join(stub_path, 'new_id')
1237 unbind_dev = os.path.join(drv_path, 'unbind')
1238 stub_bind = os.path.join(stub_path, 'bind')
1239
1240 info_write_to_files = [(vendor_id, stub_new_id),
1241 (full_id, unbind_dev),
1242 (full_id, stub_bind)]
1243
1244 for content, file in info_write_to_files:
1245 try:
lmrbc72f082010-02-08 10:02:40 +00001246 utils.open_write_close(file, content)
lmr31af3a12010-01-18 16:46:52 +00001247 except IOError:
lmrbc72f082010-02-08 10:02:40 +00001248 logging.debug("Failed to write %s to file %s", content,
1249 file)
lmr31af3a12010-01-18 16:46:52 +00001250 continue
1251
1252 if not self.is_binded_to_stub(full_id):
lmrbc72f082010-02-08 10:02:40 +00001253 logging.error("Binding device %s to stub failed", pci_id)
lmr31af3a12010-01-18 16:46:52 +00001254 continue
1255 else:
lmrbc72f082010-02-08 10:02:40 +00001256 logging.debug("Device %s already binded to stub", pci_id)
lmr31af3a12010-01-18 16:46:52 +00001257 requested_pci_ids.append(pci_id)
1258 self.pci_ids = requested_pci_ids
1259 return self.pci_ids
1260
1261
1262 def release_devs(self):
1263 """
1264 Release all PCI devices currently assigned to VMs back to the
1265 virtualization host.
1266 """
1267 try:
1268 for pci_id in self.dev_drivers:
1269 if not self._release_dev(pci_id):
lmrbc72f082010-02-08 10:02:40 +00001270 logging.error("Failed to release device %s to host", pci_id)
lmr31af3a12010-01-18 16:46:52 +00001271 else:
lmrbc72f082010-02-08 10:02:40 +00001272 logging.info("Released device %s successfully", pci_id)
lmr31af3a12010-01-18 16:46:52 +00001273 except:
1274 return