Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(620)

Side by Side Diff: client/tests/kvm/kvm_utils.py

Issue 6246035: Merge remote branch 'cros/upstream' into master (Closed) Base URL: ssh://git@gitrw.chromium.org:9222/autotest.git@master
Patch Set: patch Created 9 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 """ 1 """
2 KVM test utility functions. 2 KVM test utility functions.
3 3
4 @copyright: 2008-2009 Red Hat Inc. 4 @copyright: 2008-2009 Red Hat Inc.
5 """ 5 """
6 6
7 import time, string, random, socket, os, signal, re, logging, commands, cPickle 7 import time, string, random, socket, os, signal, re, logging, commands, cPickle
8 import fcntl, shelve, ConfigParser 8 import fcntl, shelve, ConfigParser, rss_file_transfer, threading, sys, UserDict
9 from autotest_lib.client.bin import utils, os_dep 9 from autotest_lib.client.bin import utils, os_dep
10 from autotest_lib.client.common_lib import error, logging_config 10 from autotest_lib.client.common_lib import error, logging_config
11 import kvm_subprocess 11 import kvm_subprocess
12 try: 12 try:
13 import koji 13 import koji
14 KOJI_INSTALLED = True 14 KOJI_INSTALLED = True
15 except ImportError: 15 except ImportError:
16 KOJI_INSTALLED = False 16 KOJI_INSTALLED = False
17 17
18 18
19 def _lock_file(filename): 19 def _lock_file(filename):
20 f = open(filename, "w") 20 f = open(filename, "w")
21 fcntl.lockf(f, fcntl.LOCK_EX) 21 fcntl.lockf(f, fcntl.LOCK_EX)
22 return f 22 return f
23 23
24 24
25 def _unlock_file(f): 25 def _unlock_file(f):
26 fcntl.lockf(f, fcntl.LOCK_UN) 26 fcntl.lockf(f, fcntl.LOCK_UN)
27 f.close() 27 f.close()
28 28
29 29
30 def dump_env(obj, filename): 30 def is_vm(obj):
31 """ 31 """
32 Dump KVM test environment to a file. 32 Tests whether a given object is a VM object.
33 33
34 @param filename: Path to a file where the environment will be dumped to. 34 @param obj: Python object.
35 """ 35 """
36 file = open(filename, "w") 36 return obj.__class__.__name__ == "VM"
37 cPickle.dump(obj, file)
38 file.close()
39 37
40 38
41 def load_env(filename, version): 39 class Env(UserDict.IterableUserDict):
42 """ 40 """
43 Load KVM test environment from an env file. 41 A dict-like object containing global objects used by tests.
44 If the version recorded in the file is lower than version, return an empty 42 """
45 env. If some other error occurs during unpickling, return an empty env. 43 def __init__(self, filename=None, version=0):
44 """
45 Create an empty Env object or load an existing one from a file.
46 46
47 @param filename: Path to an env file. 47 If the version recorded in the file is lower than version, or if some
48 """ 48 error occurs during unpickling, or if filename is not supplied,
49 default = {"version": version} 49 create an empty Env object.
50 try: 50
51 file = open(filename, "r") 51 @param filename: Path to an env file.
52 env = cPickle.load(file) 52 @param version: Required env version (int).
53 file.close() 53 """
54 if env.get("version", 0) < version: 54 UserDict.IterableUserDict.__init__(self)
55 logging.warn("Incompatible env file found. Not using it.") 55 empty = {"version": version}
56 return default 56 if filename:
57 return env 57 self._filename = filename
58 # Almost any exception can be raised during unpickling, so let's catch 58 try:
59 # them all 59 f = open(filename, "r")
60 except Exception, e: 60 env = cPickle.load(f)
61 logging.warn(e) 61 f.close()
62 return default 62 if env.get("version", 0) >= version:
63 self.data = env
64 else:
65 logging.warn("Incompatible env file found. Not using it.")
66 self.data = empty
67 # Almost any exception can be raised during unpickling, so let's
68 # catch them all
69 except Exception, e:
70 logging.warn(e)
71 self.data = empty
72 else:
73 self.data = empty
63 74
64 75
65 def get_sub_dict(dict, name): 76 def save(self, filename=None):
66 """ 77 """
67 Return a "sub-dict" corresponding to a specific object. 78 Pickle the contents of the Env object into a file.
68 79
69 Operate on a copy of dict: for each key that ends with the suffix 80 @param filename: Filename to pickle the dict into. If not supplied,
70 "_" + name, strip the suffix from the key, and set the value of 81 use the filename from which the dict was loaded.
71 the stripped key to that of the key. Return the resulting dict. 82 """
72 83 filename = filename or self._filename
73 @param name: Suffix of the key we want to set the value. 84 f = open(filename, "w")
74 """ 85 cPickle.dump(self.data, f)
75 suffix = "_" + name 86 f.close()
76 new_dict = dict.copy()
77 for key in dict.keys():
78 if key.endswith(suffix):
79 new_key = key.split(suffix)[0]
80 new_dict[new_key] = dict[key]
81 return new_dict
82 87
83 88
84 def get_sub_dict_names(dict, keyword): 89 def get_all_vms(self):
90 """
91 Return a list of all VM objects in this Env object.
92 """
93 return [o for o in self.values() if is_vm(o)]
94
95
96 def get_vm(self, name):
97 """
98 Return a VM object by its name.
99
100 @param name: VM name.
101 """
102 return self.get("vm__%s" % name)
103
104
105 def register_vm(self, name, vm):
106 """
107 Register a VM in this Env object.
108
109 @param name: VM name.
110 @param vm: VM object.
111 """
112 self["vm__%s" % name] = vm
113
114
115 def unregister_vm(self, name):
116 """
117 Remove a given VM.
118
119 @param name: VM name.
120 """
121 del self["vm__%s" % name]
122
123
124 def register_installer(self, installer):
125 """
126 Register a installer that was just run
127
128 The installer will be available for other tests, so that
129 information about the installed KVM modules and qemu-kvm can be used by
130 them.
131 """
132 self['last_installer'] = installer
133
134
135 def previous_installer(self):
136 """
137 Return the last installer that was registered
138 """
139 return self.get('last_installer')
140
141
142 class Params(UserDict.IterableUserDict):
85 """ 143 """
86 Return a list of "sub-dict" names that may be extracted with get_sub_dict. 144 A dict-like object passed to every test.
145 """
146 def objects(self, key):
147 """
148 Return the names of objects defined using a given key.
87 149
88 This function may be modified to change the behavior of all functions that 150 @param key: The name of the key whose value lists the objects
89 deal with multiple objects defined in dicts (e.g. VMs, images, NICs). 151 (e.g. 'nics').
152 """
153 return self.get(key, "").split()
90 154
91 @param keyword: A key in dict (e.g. "vms", "images", "nics"). 155
92 """ 156 def object_params(self, obj_name):
93 names = dict.get(keyword) 157 """
94 if names: 158 Return a dict-like object containing the parameters of an individual
95 return names.split() 159 object.
96 else: 160
97 return [] 161 This method behaves as follows: the suffix '_' + obj_name is removed
162 from all key names that have it. Other key names are left unchanged.
163 The values of keys with the suffix overwrite the values of their
164 suffixless versions.
165
166 @param obj_name: The name of the object (objects are listed by the
167 objects() method).
168 """
169 suffix = "_" + obj_name
170 new_dict = self.copy()
171 for key in self:
172 if key.endswith(suffix):
173 new_key = key.split(suffix)[0]
174 new_dict[new_key] = self[key]
175 return new_dict
98 176
99 177
100 # Functions related to MAC/IP addresses 178 # Functions related to MAC/IP addresses
101 179
102 def _open_mac_pool(lock_mode): 180 def _open_mac_pool(lock_mode):
103 lock_file = open("/tmp/mac_lock", "w+") 181 lock_file = open("/tmp/mac_lock", "w+")
104 fcntl.lockf(lock_file, lock_mode) 182 fcntl.lockf(lock_file, lock_mode)
105 pool = shelve.open("/tmp/address_pool") 183 pool = shelve.open("/tmp/address_pool")
106 return pool, lock_file 184 return pool, lock_file
107 185
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
233 if not dev: 311 if not dev:
234 return False 312 return False
235 dev = dev[0].split()[-1] 313 dev = dev[0].split()[-1]
236 314
237 # Send an ARP request 315 # Send an ARP request
238 o = commands.getoutput("%s -f -c 3 -I %s %s" % 316 o = commands.getoutput("%s -f -c 3 -I %s %s" %
239 (find_command("arping"), dev, ip)) 317 (find_command("arping"), dev, ip))
240 return bool(regex.search(o)) 318 return bool(regex.search(o))
241 319
242 320
243 # Functions for working with the environment (a dict-like object)
244
245 def is_vm(obj):
246 """
247 Tests whether a given object is a VM object.
248
249 @param obj: Python object (pretty much everything on python).
250 """
251 return obj.__class__.__name__ == "VM"
252
253
254 def env_get_all_vms(env):
255 """
256 Return a list of all VM objects on a given environment.
257
258 @param env: Dictionary with environment items.
259 """
260 vms = []
261 for obj in env.values():
262 if is_vm(obj):
263 vms.append(obj)
264 return vms
265
266
267 def env_get_vm(env, name):
268 """
269 Return a VM object by its name.
270
271 @param name: VM name.
272 """
273 return env.get("vm__%s" % name)
274
275
276 def env_register_vm(env, name, vm):
277 """
278 Register a given VM in a given env.
279
280 @param env: Environment where we will register the VM.
281 @param name: VM name.
282 @param vm: VM object.
283 """
284 env["vm__%s" % name] = vm
285
286
287 def env_unregister_vm(env, name):
288 """
289 Remove a given VM from a given env.
290
291 @param env: Environment where we will un-register the VM.
292 @param name: VM name.
293 """
294 del env["vm__%s" % name]
295
296
297 # Utility functions for dealing with external processes 321 # Utility functions for dealing with external processes
298 322
299 def find_command(cmd): 323 def find_command(cmd):
300 for dir in ["/usr/local/sbin", "/usr/local/bin", 324 for dir in ["/usr/local/sbin", "/usr/local/bin",
301 "/usr/sbin", "/usr/bin", "/sbin", "/bin"]: 325 "/usr/sbin", "/usr/bin", "/sbin", "/bin"]:
302 file = os.path.join(dir, cmd) 326 file = os.path.join(dir, cmd)
303 if os.path.exists(file): 327 if os.path.exists(file):
304 return file 328 return file
305 raise ValueError('Missing command: %s' % cmd) 329 raise ValueError('Missing command: %s' % cmd)
306 330
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
396 utils.system("git checkout %s" % lbranch) 420 utils.system("git checkout %s" % lbranch)
397 if commit: 421 if commit:
398 utils.system("git checkout %s" % commit) 422 utils.system("git checkout %s" % commit)
399 423
400 h = utils.system_output('git log --pretty=format:"%H" -1') 424 h = utils.system_output('git log --pretty=format:"%H" -1')
401 try: 425 try:
402 desc = "tag %s" % utils.system_output("git describe") 426 desc = "tag %s" % utils.system_output("git describe")
403 except error.CmdError: 427 except error.CmdError:
404 desc = "no tag found" 428 desc = "no tag found"
405 429
406 logging.info("Commit hash for %s is %s (%s)" % (repository, h.strip(), 430 logging.info("Commit hash for %s is %s (%s)", repository, h.strip(), desc)
407 desc))
408 return srcdir 431 return srcdir
409 432
410 433
411 def check_kvm_source_dir(source_dir): 434 def check_kvm_source_dir(source_dir):
412 """ 435 """
413 Inspects the kvm source directory and verifies its disposition. In some 436 Inspects the kvm source directory and verifies its disposition. In some
414 occasions build may be dependant on the source directory disposition. 437 occasions build may be dependant on the source directory disposition.
415 The reason why the return codes are numbers is that we might have more 438 The reason why the return codes are numbers is that we might have more
416 changes on the source directory layout, so it's not scalable to just use 439 changes on the source directory layout, so it's not scalable to just use
417 strings like 'old_repo', 'new_repo' and such. 440 strings like 'old_repo', 'new_repo' and such.
418 441
419 @param source_dir: Source code path that will be inspected. 442 @param source_dir: Source code path that will be inspected.
420 """ 443 """
421 os.chdir(source_dir) 444 os.chdir(source_dir)
422 has_qemu_dir = os.path.isdir('qemu') 445 has_qemu_dir = os.path.isdir('qemu')
423 has_kvm_dir = os.path.isdir('kvm') 446 has_kvm_dir = os.path.isdir('kvm')
424 if has_qemu_dir and not has_kvm_dir: 447 if has_qemu_dir:
425 logging.debug("qemu directory detected, source dir layout 1") 448 logging.debug("qemu directory detected, source dir layout 1")
426 return 1 449 return 1
427 if has_kvm_dir and not has_qemu_dir: 450 if has_kvm_dir and not has_qemu_dir:
428 logging.debug("kvm directory detected, source dir layout 2") 451 logging.debug("kvm directory detected, source dir layout 2")
429 return 2 452 return 2
430 else: 453 else:
431 raise error.TestError("Unknown source dir layout, cannot proceed.") 454 raise error.TestError("Unknown source dir layout, cannot proceed.")
432 455
433 456
434 # The following are functions used for SSH, SCP and Telnet communication with 457 # Functions and classes used for logging into guests and transferring files
435 # guests. 458
459 class LoginError(Exception):
460 def __init__(self, msg, output):
461 Exception.__init__(self, msg, output)
462 self.msg = msg
463 self.output = output
464
465 def __str__(self):
466 return "%s (output: %r)" % (self.msg, self.output)
467
468
469 class LoginAuthenticationError(LoginError):
470 pass
471
472
473 class LoginTimeoutError(LoginError):
474 def __init__(self, output):
475 LoginError.__init__(self, "Login timeout expired", output)
476
477
478 class LoginProcessTerminatedError(LoginError):
479 def __init__(self, status, output):
480 LoginError.__init__(self, None, output)
481 self.status = status
482
483 def __str__(self):
484 return ("Client process terminated (status: %s, output: %r)" %
485 (self.status, self.output))
486
487
488 class LoginBadClientError(LoginError):
489 def __init__(self, client):
490 LoginError.__init__(self, None, None)
491 self.client = client
492
493 def __str__(self):
494 return "Unknown remote shell client: %r" % self.client
495
496
497 class SCPError(Exception):
498 def __init__(self, msg, output):
499 Exception.__init__(self, msg, output)
500 self.msg = msg
501 self.output = output
502
503 def __str__(self):
504 return "%s (output: %r)" % (self.msg, self.output)
505
506
507 class SCPAuthenticationError(SCPError):
508 pass
509
510
511 class SCPAuthenticationTimeoutError(SCPAuthenticationError):
512 def __init__(self, output):
513 SCPAuthenticationError.__init__(self, "Authentication timeout expired",
514 output)
515
516
517 class SCPTransferTimeoutError(SCPError):
518 def __init__(self, output):
519 SCPError.__init__(self, "Transfer timeout expired", output)
520
521
522 class SCPTransferFailedError(SCPError):
523 def __init__(self, status, output):
524 SCPError.__init__(self, None, output)
525 self.status = status
526
527 def __str__(self):
528 return ("SCP transfer failed (status: %s, output: %r)" %
529 (self.status, self.output))
530
436 531
437 def _remote_login(session, username, password, prompt, timeout=10): 532 def _remote_login(session, username, password, prompt, timeout=10):
438 """ 533 """
439 Log into a remote host (guest) using SSH or Telnet. Wait for questions 534 Log into a remote host (guest) using SSH or Telnet. Wait for questions
440 and provide answers. If timeout expires while waiting for output from the 535 and provide answers. If timeout expires while waiting for output from the
441 child (e.g. a password prompt or a shell prompt) -- fail. 536 child (e.g. a password prompt or a shell prompt) -- fail.
442 537
443 @brief: Log into a remote host (guest) using SSH or Telnet. 538 @brief: Log into a remote host (guest) using SSH or Telnet.
444 539
445 @param session: A kvm_expect or kvm_shell_session instance to operate on 540 @param session: An Expect or ShellSession instance to operate on
446 @param username: The username to send in reply to a login prompt 541 @param username: The username to send in reply to a login prompt
447 @param password: The password to send in reply to a password prompt 542 @param password: The password to send in reply to a password prompt
448 @param prompt: The shell prompt that indicates a successful login 543 @param prompt: The shell prompt that indicates a successful login
449 @param timeout: The maximal time duration (in seconds) to wait for each 544 @param timeout: The maximal time duration (in seconds) to wait for each
450 step of the login procedure (i.e. the "Are you sure" prompt, the 545 step of the login procedure (i.e. the "Are you sure" prompt, the
451 password prompt, the shell prompt, etc) 546 password prompt, the shell prompt, etc)
452 547 @raise LoginTimeoutError: If timeout expires
453 @return: True on success and False otherwise. 548 @raise LoginAuthenticationError: If authentication fails
549 @raise LoginProcessTerminatedError: If the client terminates during login
550 @raise LoginError: If some other error occurs
454 """ 551 """
455 password_prompt_count = 0 552 password_prompt_count = 0
456 login_prompt_count = 0 553 login_prompt_count = 0
457 554
458 while True: 555 while True:
459 (match, text) = session.read_until_last_line_matches( 556 try:
557 match, text = session.read_until_last_line_matches(
460 [r"[Aa]re you sure", r"[Pp]assword:\s*$", r"[Ll]ogin:\s*$", 558 [r"[Aa]re you sure", r"[Pp]assword:\s*$", r"[Ll]ogin:\s*$",
461 r"[Cc]onnection.*closed", r"[Cc]onnection.*refused", 559 r"[Cc]onnection.*closed", r"[Cc]onnection.*refused",
462 r"[Pp]lease wait", prompt], 560 r"[Pp]lease wait", prompt],
463 timeout=timeout, internal_timeout=0.5) 561 timeout=timeout, internal_timeout=0.5)
464 if match == 0: # "Are you sure you want to continue connecting" 562 if match == 0: # "Are you sure you want to continue connecting"
465 logging.debug("Got 'Are you sure...'; sending 'yes'") 563 logging.debug("Got 'Are you sure...'; sending 'yes'")
466 session.sendline("yes") 564 session.sendline("yes")
467 continue
468 elif match == 1: # "password:"
469 if password_prompt_count == 0:
470 logging.debug("Got password prompt; sending '%s'" % password)
471 session.sendline(password)
472 password_prompt_count += 1
473 continue 565 continue
474 else: 566 elif match == 1: # "password:"
475 logging.debug("Got password prompt again") 567 if password_prompt_count == 0:
476 return False 568 logging.debug("Got password prompt; sending '%s'", password)
477 elif match == 2: # "login:" 569 session.sendline(password)
478 if login_prompt_count == 0: 570 password_prompt_count += 1
479 logging.debug("Got username prompt; sending '%s'" % username) 571 continue
480 session.sendline(username) 572 else:
481 login_prompt_count += 1 573 raise LoginAuthenticationError("Got password prompt twice",
574 text)
575 elif match == 2: # "login:"
576 if login_prompt_count == 0 and password_prompt_count == 0:
577 logging.debug("Got username prompt; sending '%s'", username)
578 session.sendline(username)
579 login_prompt_count += 1
580 continue
581 else:
582 if login_prompt_count > 0:
583 msg = "Got username prompt twice"
584 else:
585 msg = "Got username prompt after password prompt"
586 raise LoginAuthenticationError(msg, text)
587 elif match == 3: # "Connection closed"
588 raise LoginError("Client said 'connection closed'", text)
589 elif match == 4: # "Connection refused"
590 raise LoginError("Client said 'connection refused'", text)
591 elif match == 5: # "Please wait"
592 logging.debug("Got 'Please wait'")
593 timeout = 30
482 continue 594 continue
483 else: 595 elif match == 6: # prompt
484 logging.debug("Got username prompt again") 596 logging.debug("Got shell prompt -- logged in")
485 return False 597 break
486 elif match == 3: # "Connection closed" 598 except kvm_subprocess.ExpectTimeoutError, e:
487 logging.debug("Got 'Connection closed'") 599 raise LoginTimeoutError(e.output)
488 return False 600 except kvm_subprocess.ExpectProcessTerminatedError, e:
489 elif match == 4: # "Connection refused" 601 raise LoginProcessTerminatedError(e.status, e.output)
490 logging.debug("Got 'Connection refused'")
491 return False
492 elif match == 5: # "Please wait"
493 logging.debug("Got 'Please wait'")
494 timeout = 30
495 continue
496 elif match == 6: # prompt
497 logging.debug("Got shell prompt -- logged in")
498 return session
499 else: # match == None
500 logging.debug("Timeout elapsed or process terminated")
501 return False
502
503
504 def _remote_scp(session, password, transfer_timeout=600, login_timeout=10):
505 """
506 Transfer file(s) to a remote host (guest) using SCP. Wait for questions
507 and provide answers. If login_timeout expires while waiting for output
508 from the child (e.g. a password prompt), fail. If transfer_timeout expires
509 while waiting for the transfer to complete, fail.
510
511 @brief: Transfer files using SCP, given a command line.
512
513 @param session: A kvm_expect or kvm_shell_session instance to operate on
514 @param password: The password to send in reply to a password prompt.
515 @param transfer_timeout: The time duration (in seconds) to wait for the
516 transfer to complete.
517 @param login_timeout: The maximal time duration (in seconds) to wait for
518 each step of the login procedure (i.e. the "Are you sure" prompt or
519 the password prompt)
520
521 @return: True if the transfer succeeds and False on failure.
522 """
523 password_prompt_count = 0
524 timeout = login_timeout
525
526 while True:
527 (match, text) = session.read_until_last_line_matches(
528 [r"[Aa]re you sure", r"[Pp]assword:\s*$", r"lost connection"],
529 timeout=timeout, internal_timeout=0.5)
530 if match == 0: # "Are you sure you want to continue connecting"
531 logging.debug("Got 'Are you sure...'; sending 'yes'")
532 session.sendline("yes")
533 continue
534 elif match == 1: # "password:"
535 if password_prompt_count == 0:
536 logging.debug("Got password prompt; sending '%s'" % password)
537 session.sendline(password)
538 password_prompt_count += 1
539 timeout = transfer_timeout
540 continue
541 else:
542 logging.debug("Got password prompt again")
543 return False
544 elif match == 2: # "lost connection"
545 logging.debug("Got 'lost connection'")
546 return False
547 else: # match == None
548 if session.is_alive():
549 logging.debug("Timeout expired")
550 return False
551 else:
552 status = session.get_status()
553 logging.debug("SCP process terminated with status %s", status)
554 return status == 0
555 602
556 603
557 def remote_login(client, host, port, username, password, prompt, linesep="\n", 604 def remote_login(client, host, port, username, password, prompt, linesep="\n",
558 log_filename=None, timeout=10): 605 log_filename=None, timeout=10):
559 """ 606 """
560 Log into a remote host (guest) using SSH/Telnet/Netcat. 607 Log into a remote host (guest) using SSH/Telnet/Netcat.
561 608
562 @param client: The client to use ('ssh', 'telnet' or 'nc') 609 @param client: The client to use ('ssh', 'telnet' or 'nc')
563 @param host: Hostname or IP address 610 @param host: Hostname or IP address
564 @param port: Port to connect to 611 @param port: Port to connect to
565 @param username: Username (if required) 612 @param username: Username (if required)
566 @param password: Password (if required) 613 @param password: Password (if required)
567 @param prompt: Shell prompt (regular expression) 614 @param prompt: Shell prompt (regular expression)
568 @param linesep: The line separator to use when sending lines 615 @param linesep: The line separator to use when sending lines
569 (e.g. '\\n' or '\\r\\n') 616 (e.g. '\\n' or '\\r\\n')
570 @param log_filename: If specified, log all output to this file 617 @param log_filename: If specified, log all output to this file
571 @param timeout: The maximal time duration (in seconds) to wait for 618 @param timeout: The maximal time duration (in seconds) to wait for
572 each step of the login procedure (i.e. the "Are you sure" prompt 619 each step of the login procedure (i.e. the "Are you sure" prompt
573 or the password prompt) 620 or the password prompt)
574 621 @raise LoginBadClientError: If an unknown client is requested
575 @return: kvm_shell_session object on success and None on failure. 622 @raise: Whatever _remote_login() raises
623 @return: A ShellSession object.
576 """ 624 """
577 if client == "ssh": 625 if client == "ssh":
578 cmd = ("ssh -o UserKnownHostsFile=/dev/null " 626 cmd = ("ssh -o UserKnownHostsFile=/dev/null "
579 "-o PreferredAuthentications=password -p %s %s@%s" % 627 "-o PreferredAuthentications=password -p %s %s@%s" %
580 (port, username, host)) 628 (port, username, host))
581 elif client == "telnet": 629 elif client == "telnet":
582 cmd = "telnet -l %s %s %s" % (username, host, port) 630 cmd = "telnet -l %s %s %s" % (username, host, port)
583 elif client == "nc": 631 elif client == "nc":
584 cmd = "nc %s %s" % (host, port) 632 cmd = "nc %s %s" % (host, port)
585 else: 633 else:
586 logging.error("Unknown remote shell client: %s" % client) 634 raise LoginBadClientError(client)
587 return
588 635
589 logging.debug("Trying to login with command '%s'" % cmd) 636 logging.debug("Trying to login with command '%s'", cmd)
590 session = kvm_subprocess.kvm_shell_session(cmd, linesep=linesep, 637 session = kvm_subprocess.ShellSession(cmd, linesep=linesep, prompt=prompt)
591 prompt=prompt) 638 try:
592 if _remote_login(session, username, password, prompt, timeout): 639 _remote_login(session, username, password, prompt, timeout)
593 if log_filename: 640 except:
594 session.set_output_func(log_line)
595 session.set_output_params((log_filename,))
596 return session
597 else:
598 session.close() 641 session.close()
642 raise
643 if log_filename:
644 session.set_output_func(log_line)
645 session.set_output_params((log_filename,))
646 return session
647
648
649 def wait_for_login(client, host, port, username, password, prompt, linesep="\n",
650 log_filename=None, timeout=240, internal_timeout=10):
651 """
652 Make multiple attempts to log into a remote host (guest) until one succeeds
653 or timeout expires.
654
655 @param timeout: Total time duration to wait for a successful login
656 @param internal_timeout: The maximal time duration (in seconds) to wait for
657 each step of the login procedure (e.g. the "Are you sure" prompt
658 or the password prompt)
659 @see: remote_login()
660 @raise: Whatever remote_login() raises
661 @return: A ShellSession object.
662 """
663 logging.debug("Attempting to log into %s:%s using %s (timeout %ds)",
664 host, port, client, timeout)
665 end_time = time.time() + timeout
666 while time.time() < end_time:
667 try:
668 return remote_login(client, host, port, username, password, prompt,
669 linesep, log_filename, internal_timeout)
670 except LoginError, e:
671 logging.debug(e)
672 time.sleep(2)
673 # Timeout expired; try one more time but don't catch exceptions
674 return remote_login(client, host, port, username, password, prompt,
675 linesep, log_filename, internal_timeout)
676
677
678 def _remote_scp(session, password, transfer_timeout=600, login_timeout=10):
679 """
680 Transfer file(s) to a remote host (guest) using SCP. Wait for questions
681 and provide answers. If login_timeout expires while waiting for output
682 from the child (e.g. a password prompt), fail. If transfer_timeout expires
683 while waiting for the transfer to complete, fail.
684
685 @brief: Transfer files using SCP, given a command line.
686
687 @param session: An Expect or ShellSession instance to operate on
688 @param password: The password to send in reply to a password prompt.
689 @param transfer_timeout: The time duration (in seconds) to wait for the
690 transfer to complete.
691 @param login_timeout: The maximal time duration (in seconds) to wait for
692 each step of the login procedure (i.e. the "Are you sure" prompt or
693 the password prompt)
694 @raise SCPAuthenticationError: If authentication fails
695 @raise SCPTransferTimeoutError: If the transfer fails to complete in time
696 @raise SCPTransferFailedError: If the process terminates with a nonzero
697 exit code
698 @raise SCPError: If some other error occurs
699 """
700 password_prompt_count = 0
701 timeout = login_timeout
702 authentication_done = False
703
704 while True:
705 try:
706 match, text = session.read_until_last_line_matches(
707 [r"[Aa]re you sure", r"[Pp]assword:\s*$", r"lost connection"],
708 timeout=timeout, internal_timeout=0.5)
709 if match == 0: # "Are you sure you want to continue connecting"
710 logging.debug("Got 'Are you sure...'; sending 'yes'")
711 session.sendline("yes")
712 continue
713 elif match == 1: # "password:"
714 if password_prompt_count == 0:
715 logging.debug("Got password prompt; sending '%s'", password)
716 session.sendline(password)
717 password_prompt_count += 1
718 timeout = transfer_timeout
719 authentication_done = True
720 continue
721 else:
722 raise SCPAuthenticationError("Got password prompt twice",
723 text)
724 elif match == 2: # "lost connection"
725 raise SCPError("SCP client said 'lost connection'", text)
726 except kvm_subprocess.ExpectTimeoutError, e:
727 if authentication_done:
728 raise SCPTransferTimeoutError(e.output)
729 else:
730 raise SCPAuthenticationTimeoutError(e.output)
731 except kvm_subprocess.ExpectProcessTerminatedError, e:
732 if e.status == 0:
733 logging.debug("SCP process terminated with status 0")
734 break
735 else:
736 raise SCPTransferFailedError(e.status, e.output)
599 737
600 738
601 def remote_scp(command, password, log_filename=None, transfer_timeout=600, 739 def remote_scp(command, password, log_filename=None, transfer_timeout=600,
602 login_timeout=10): 740 login_timeout=10):
603 """ 741 """
604 Transfer file(s) to a remote host (guest) using SCP. 742 Transfer file(s) to a remote host (guest) using SCP.
605 743
606 @brief: Transfer files using SCP, given a command line. 744 @brief: Transfer files using SCP, given a command line.
607 745
608 @param command: The command to execute 746 @param command: The command to execute
609 (e.g. "scp -r foobar root@localhost:/tmp/"). 747 (e.g. "scp -r foobar root@localhost:/tmp/").
610 @param password: The password to send in reply to a password prompt. 748 @param password: The password to send in reply to a password prompt.
611 @param log_filename: If specified, log all output to this file 749 @param log_filename: If specified, log all output to this file
612 @param transfer_timeout: The time duration (in seconds) to wait for the 750 @param transfer_timeout: The time duration (in seconds) to wait for the
613 transfer to complete. 751 transfer to complete.
614 @param login_timeout: The maximal time duration (in seconds) to wait for 752 @param login_timeout: The maximal time duration (in seconds) to wait for
615 each step of the login procedure (i.e. the "Are you sure" prompt 753 each step of the login procedure (i.e. the "Are you sure" prompt
616 or the password prompt) 754 or the password prompt)
617 755 @raise: Whatever _remote_scp() raises
618 @return: True if the transfer succeeds and False on failure.
619 """ 756 """
620 logging.debug("Trying to SCP with command '%s', timeout %ss", 757 logging.debug("Trying to SCP with command '%s', timeout %ss",
621 command, transfer_timeout) 758 command, transfer_timeout)
622
623 if log_filename: 759 if log_filename:
624 output_func = log_line 760 output_func = log_line
625 output_params = (log_filename,) 761 output_params = (log_filename,)
626 else: 762 else:
627 output_func = None 763 output_func = None
628 output_params = () 764 output_params = ()
629 765 session = kvm_subprocess.Expect(command,
630 session = kvm_subprocess.kvm_expect(command, 766 output_func=output_func,
631 output_func=output_func, 767 output_params=output_params)
632 output_params=output_params)
633 try: 768 try:
634 return _remote_scp(session, password, transfer_timeout, login_timeout) 769 _remote_scp(session, password, transfer_timeout, login_timeout)
635 finally: 770 finally:
636 session.close() 771 session.close()
637 772
638 773
639 def scp_to_remote(host, port, username, password, local_path, remote_path, 774 def scp_to_remote(host, port, username, password, local_path, remote_path,
640 log_filename=None, timeout=600): 775 log_filename=None, timeout=600):
641 """ 776 """
642 Copy files to a remote host (guest). 777 Copy files to a remote host (guest) through scp.
643 778
644 @param host: Hostname or IP address 779 @param host: Hostname or IP address
645 @param username: Username (if required) 780 @param username: Username (if required)
646 @param password: Password (if required) 781 @param password: Password (if required)
647 @param local_path: Path on the local machine where we are copying from 782 @param local_path: Path on the local machine where we are copying from
648 @param remote_path: Path on the remote machine where we are copying to 783 @param remote_path: Path on the remote machine where we are copying to
649 @param log_filename: If specified, log all output to this file 784 @param log_filename: If specified, log all output to this file
650 @param timeout: The time duration (in seconds) to wait for the transfer 785 @param timeout: The time duration (in seconds) to wait for the transfer
651 to complete. 786 to complete.
652 787 @raise: Whatever remote_scp() raises
653 @return: True on success and False on failure.
654 """ 788 """
655 command = ("scp -v -o UserKnownHostsFile=/dev/null " 789 command = ("scp -v -o UserKnownHostsFile=/dev/null "
656 "-o PreferredAuthentications=password -r -P %s %s %s@%s:%s" % 790 "-o PreferredAuthentications=password -r -P %s %s %s@%s:%s" %
657 (port, local_path, username, host, remote_path)) 791 (port, local_path, username, host, remote_path))
658 return remote_scp(command, password, log_filename, timeout) 792 remote_scp(command, password, log_filename, timeout)
659 793
660 794
661 def scp_from_remote(host, port, username, password, remote_path, local_path, 795 def scp_from_remote(host, port, username, password, remote_path, local_path,
662 log_filename=None, timeout=600): 796 log_filename=None, timeout=600):
663 """ 797 """
664 Copy files from a remote host (guest). 798 Copy files from a remote host (guest).
665 799
666 @param host: Hostname or IP address 800 @param host: Hostname or IP address
667 @param username: Username (if required) 801 @param username: Username (if required)
668 @param password: Password (if required) 802 @param password: Password (if required)
669 @param local_path: Path on the local machine where we are copying from 803 @param local_path: Path on the local machine where we are copying from
670 @param remote_path: Path on the remote machine where we are copying to 804 @param remote_path: Path on the remote machine where we are copying to
671 @param log_filename: If specified, log all output to this file 805 @param log_filename: If specified, log all output to this file
672 @param timeout: The time duration (in seconds) to wait for the transfer 806 @param timeout: The time duration (in seconds) to wait for the transfer
673 to complete. 807 to complete.
674 808 @raise: Whatever remote_scp() raises
675 @return: True on success and False on failure.
676 """ 809 """
677 command = ("scp -v -o UserKnownHostsFile=/dev/null " 810 command = ("scp -v -o UserKnownHostsFile=/dev/null "
678 "-o PreferredAuthentications=password -r -P %s %s@%s:%s %s" % 811 "-o PreferredAuthentications=password -r -P %s %s@%s:%s %s" %
679 (port, username, host, remote_path, local_path)) 812 (port, username, host, remote_path, local_path))
680 return remote_scp(command, password, log_filename, timeout) 813 remote_scp(command, password, log_filename, timeout)
814
815
816 def copy_files_to(address, client, username, password, port, local_path,
817 remote_path, log_filename=None, verbose=False, timeout=600):
818 """
819 Copy files to a remote host (guest) using the selected client.
820
821 @param client: Type of transfer client
822 @param username: Username (if required)
823 @param password: Password (if requried)
824 @param local_path: Path on the local machine where we are copying from
825 @param remote_path: Path on the remote machine where we are copying to
826 @param address: Address of remote host(guest)
827 @param log_filename: If specified, log all output to this file (SCP only)
828 @param verbose: If True, log some stats using logging.debug (RSS only)
829 @param timeout: The time duration (in seconds) to wait for the transfer to
830 complete.
831 @raise: Whatever remote_scp() raises
832 """
833 if client == "scp":
834 scp_to_remote(address, port, username, password, local_path,
835 remote_path, log_filename, timeout)
836 elif client == "rss":
837 log_func = None
838 if verbose:
839 log_func = logging.debug
840 c = rss_file_transfer.FileUploadClient(address, port, log_func)
841 c.upload(local_path, remote_path, timeout)
842 c.close()
843
844
845 def copy_files_from(address, client, username, password, port, remote_path,
846 local_path, log_filename=None, verbose=False, timeout=600):
847 """
848 Copy files from a remote host (guest) using the selected client.
849
850 @param client: Type of transfer client
851 @param username: Username (if required)
852 @param password: Password (if requried)
853 @param remote_path: Path on the remote machine where we are copying from
854 @param local_path: Path on the local machine where we are copying to
855 @param address: Address of remote host(guest)
856 @param log_filename: If specified, log all output to this file (SCP only)
857 @param verbose: If True, log some stats using logging.debug (RSS only)
858 @param timeout: The time duration (in seconds) to wait for the transfer to
859 complete.
860 @raise: Whatever remote_scp() raises
861 """
862 if client == "scp":
863 scp_from_remote(address, port, username, password, remote_path,
864 local_path, log_filename, timeout)
865 elif client == "rss":
866 log_func = None
867 if verbose:
868 log_func = logging.debug
869 c = rss_file_transfer.FileDownloadClient(address, port, log_func)
870 c.download(remote_path, local_path, timeout)
871 c.close()
681 872
682 873
683 # The following are utility functions related to ports. 874 # The following are utility functions related to ports.
684 875
685 def is_port_free(port, address): 876 def is_port_free(port, address):
686 """ 877 """
687 Return True if the given port is available for use. 878 Return True if the given port is available for use.
688 879
689 @param port: Port number 880 @param port: Port number
690 """ 881 """
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after
859 @param steps: Time to sleep between attempts in seconds 1050 @param steps: Time to sleep between attempts in seconds
860 @param text: Text to print while waiting, for debug purposes 1051 @param text: Text to print while waiting, for debug purposes
861 """ 1052 """
862 start_time = time.time() 1053 start_time = time.time()
863 end_time = time.time() + timeout 1054 end_time = time.time() + timeout
864 1055
865 time.sleep(first) 1056 time.sleep(first)
866 1057
867 while time.time() < end_time: 1058 while time.time() < end_time:
868 if text: 1059 if text:
869 logging.debug("%s (%f secs)" % (text, time.time() - start_time)) 1060 logging.debug("%s (%f secs)", text, (time.time() - start_time))
870 1061
871 output = func() 1062 output = func()
872 if output: 1063 if output:
873 return output 1064 return output
874 1065
875 time.sleep(step) 1066 time.sleep(step)
876 1067
877 logging.debug("Timeout elapsed") 1068 logging.debug("Timeout elapsed")
878 return None 1069 return None
879 1070
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
971 def get_vendor_from_pci_id(pci_id): 1162 def get_vendor_from_pci_id(pci_id):
972 """ 1163 """
973 Check out the device vendor ID according to pci_id. 1164 Check out the device vendor ID according to pci_id.
974 1165
975 @param pci_id: PCI ID of a device. 1166 @param pci_id: PCI ID of a device.
976 """ 1167 """
977 cmd = "lspci -n | awk '/%s/ {print $3}'" % pci_id 1168 cmd = "lspci -n | awk '/%s/ {print $3}'" % pci_id
978 return re.sub(":", " ", commands.getoutput(cmd)) 1169 return re.sub(":", " ", commands.getoutput(cmd))
979 1170
980 1171
1172 class Thread(threading.Thread):
1173 """
1174 Run a function in a background thread.
1175 """
1176 def __init__(self, target, args=(), kwargs={}):
1177 """
1178 Initialize the instance.
1179
1180 @param target: Function to run in the thread.
1181 @param args: Arguments to pass to target.
1182 @param kwargs: Keyword arguments to pass to target.
1183 """
1184 threading.Thread.__init__(self)
1185 self._target = target
1186 self._args = args
1187 self._kwargs = kwargs
1188
1189
1190 def run(self):
1191 """
1192 Run target (passed to the constructor). No point in calling this
1193 function directly. Call start() to make this function run in a new
1194 thread.
1195 """
1196 self._e = None
1197 self._retval = None
1198 try:
1199 try:
1200 self._retval = self._target(*self._args, **self._kwargs)
1201 except:
1202 self._e = sys.exc_info()
1203 raise
1204 finally:
1205 # Avoid circular references (start() may be called only once so
1206 # it's OK to delete these)
1207 del self._target, self._args, self._kwargs
1208
1209
1210 def join(self, timeout=None, suppress_exception=False):
1211 """
1212 Join the thread. If target raised an exception, re-raise it.
1213 Otherwise, return the value returned by target.
1214
1215 @param timeout: Timeout value to pass to threading.Thread.join().
1216 @param suppress_exception: If True, don't re-raise the exception.
1217 """
1218 threading.Thread.join(self, timeout)
1219 try:
1220 if self._e:
1221 if not suppress_exception:
1222 # Because the exception was raised in another thread, we
1223 # need to explicitly insert the current context into it
1224 s = error.exception_context(self._e[1])
1225 s = error.join_contexts(error.get_context(), s)
1226 error.set_exception_context(self._e[1], s)
1227 raise self._e[0], self._e[1], self._e[2]
1228 else:
1229 return self._retval
1230 finally:
1231 # Avoid circular references (join() may be called multiple times
1232 # so we can't delete these)
1233 self._e = None
1234 self._retval = None
1235
1236
1237 def parallel(targets):
1238 """
1239 Run multiple functions in parallel.
1240
1241 @param targets: A sequence of tuples or functions. If it's a sequence of
1242 tuples, each tuple will be interpreted as (target, args, kwargs) or
1243 (target, args) or (target,) depending on its length. If it's a
1244 sequence of functions, the functions will be called without
1245 arguments.
1246 @return: A list of the values returned by the functions called.
1247 """
1248 threads = []
1249 for target in targets:
1250 if isinstance(target, tuple) or isinstance(target, list):
1251 t = Thread(*target)
1252 else:
1253 t = Thread(target)
1254 threads.append(t)
1255 t.start()
1256 return [t.join() for t in threads]
1257
1258
981 class KvmLoggingConfig(logging_config.LoggingConfig): 1259 class KvmLoggingConfig(logging_config.LoggingConfig):
982 """ 1260 """
983 Used with the sole purpose of providing convenient logging setup 1261 Used with the sole purpose of providing convenient logging setup
984 for the KVM test auxiliary programs. 1262 for the KVM test auxiliary programs.
985 """ 1263 """
986 def configure_logging(self, results_dir=None, verbose=False): 1264 def configure_logging(self, results_dir=None, verbose=False):
987 super(KvmLoggingConfig, self).configure_logging(use_console=True, 1265 super(KvmLoggingConfig, self).configure_logging(use_console=True,
988 verbose=verbose) 1266 verbose=verbose)
989 1267
990 1268
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after
1169 re_probe = True 1447 re_probe = True
1170 elif not self.check_vfs_count(): 1448 elif not self.check_vfs_count():
1171 os.system("modprobe -r %s" % self.driver) 1449 os.system("modprobe -r %s" % self.driver)
1172 re_probe = True 1450 re_probe = True
1173 else: 1451 else:
1174 return True 1452 return True
1175 1453
1176 # Re-probe driver with proper number of VFs 1454 # Re-probe driver with proper number of VFs
1177 if re_probe: 1455 if re_probe:
1178 cmd = "modprobe %s %s" % (self.driver, self.driver_option) 1456 cmd = "modprobe %s %s" % (self.driver, self.driver_option)
1179 logging.info("Loading the driver '%s' with option '%s'" % 1457 logging.info("Loading the driver '%s' with option '%s'",
1180 (self.driver, self.driver_option)) 1458 self.driver, self.driver_option)
1181 s, o = commands.getstatusoutput(cmd) 1459 s, o = commands.getstatusoutput(cmd)
1182 if s: 1460 if s:
1183 return False 1461 return False
1184 return True 1462 return True
1185 1463
1186 1464
1187 def request_devs(self): 1465 def request_devs(self):
1188 """ 1466 """
1189 Implement setup process: unbind the PCI device and then bind it 1467 Implement setup process: unbind the PCI device and then bind it
1190 to the pci-stub driver. 1468 to the pci-stub driver.
1191 1469
1192 @return: a list of successfully requested devices' PCI IDs. 1470 @return: a list of successfully requested devices' PCI IDs.
1193 """ 1471 """
1194 base_dir = "/sys/bus/pci" 1472 base_dir = "/sys/bus/pci"
1195 stub_path = os.path.join(base_dir, "drivers/pci-stub") 1473 stub_path = os.path.join(base_dir, "drivers/pci-stub")
1196 1474
1197 self.pci_ids = self.get_devs(self.devices_requested) 1475 self.pci_ids = self.get_devs(self.devices_requested)
1198 logging.debug("The following pci_ids were found: %s", self.pci_ids) 1476 logging.debug("The following pci_ids were found: %s", self.pci_ids)
1199 requested_pci_ids = [] 1477 requested_pci_ids = []
1200 self.dev_drivers = {} 1478 self.dev_drivers = {}
1201 1479
1202 # Setup all devices specified for assignment to guest 1480 # Setup all devices specified for assignment to guest
1203 for pci_id in self.pci_ids: 1481 for pci_id in self.pci_ids:
1204 full_id = get_full_pci_id(pci_id) 1482 full_id = get_full_pci_id(pci_id)
1205 if not full_id: 1483 if not full_id:
1206 continue 1484 continue
1207 drv_path = os.path.join(base_dir, "devices/%s/driver" % full_id) 1485 drv_path = os.path.join(base_dir, "devices/%s/driver" % full_id)
1208 dev_prev_driver= os.path.realpath(os.path.join(drv_path, 1486 dev_prev_driver = os.path.realpath(os.path.join(drv_path,
1209 os.readlink(drv_path))) 1487 os.readlink(drv_path)))
1210 self.dev_drivers[pci_id] = dev_prev_driver 1488 self.dev_drivers[pci_id] = dev_prev_driver
1211 1489
1212 # Judge whether the device driver has been binded to stub 1490 # Judge whether the device driver has been binded to stub
1213 if not self.is_binded_to_stub(full_id): 1491 if not self.is_binded_to_stub(full_id):
1214 logging.debug("Binding device %s to stub", full_id) 1492 logging.debug("Binding device %s to stub", full_id)
1215 vendor_id = get_vendor_from_pci_id(pci_id) 1493 vendor_id = get_vendor_from_pci_id(pci_id)
1216 stub_new_id = os.path.join(stub_path, 'new_id') 1494 stub_new_id = os.path.join(stub_path, 'new_id')
1217 unbind_dev = os.path.join(drv_path, 'unbind') 1495 unbind_dev = os.path.join(drv_path, 'unbind')
1218 stub_bind = os.path.join(stub_path, 'bind') 1496 stub_bind = os.path.join(stub_path, 'bind')
1219 1497
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
1340 if tag and build: 1618 if tag and build:
1341 logging.info("Both tag and build parameters provided, ignoring tag " 1619 logging.info("Both tag and build parameters provided, ignoring tag "
1342 "parameter...") 1620 "parameter...")
1343 1621
1344 if not tag and not build: 1622 if not tag and not build:
1345 raise ValueError("Koji install selected but neither koji_tag " 1623 raise ValueError("Koji install selected but neither koji_tag "
1346 "nor koji_build parameters provided. Please " 1624 "nor koji_build parameters provided. Please "
1347 "provide an appropriate tag or build name.") 1625 "provide an appropriate tag or build name.")
1348 1626
1349 if not build: 1627 if not build:
1350 builds = self.session.listTagged(tag, latest=True, 1628 builds = self.session.listTagged(tag, latest=True, inherit=True,
1351 package=src_package) 1629 package=src_package)
1352 if not builds: 1630 if not builds:
1353 raise ValueError("Tag %s has no builds of %s" % (tag, 1631 raise ValueError("Tag %s has no builds of %s" % (tag,
1354 src_package)) 1632 src_package))
1355 info = builds[0] 1633 info = builds[0]
1356 else: 1634 else:
1357 info = self.session.getBuild(build) 1635 info = self.session.getBuild(build)
1358 1636
1359 if info is None: 1637 if info is None:
1360 raise ValueError('No such brew/koji build: %s' % build) 1638 raise ValueError('No such brew/koji build: %s' % build)
(...skipping 22 matching lines...) Expand all
1383 download = False 1661 download = False
1384 else: 1662 else:
1385 download = True 1663 download = True
1386 1664
1387 if download: 1665 if download:
1388 r = utils.get_file(url, 1666 r = utils.get_file(url,
1389 os.path.join(dst_dir, os.path.basename(url))) 1667 os.path.join(dst_dir, os.path.basename(url)))
1390 rpm_paths.append(r) 1668 rpm_paths.append(r)
1391 1669
1392 return rpm_paths 1670 return rpm_paths
1671
1672
1673 def umount(src, mount_point, type):
1674 """
1675 Umount the src mounted in mount_point.
1676
1677 @src: mount source
1678 @mount_point: mount point
1679 @type: file system type
1680 """
1681
1682 mount_string = "%s %s %s" % (src, mount_point, type)
1683 if mount_string in file("/etc/mtab").read():
1684 umount_cmd = "umount %s" % mount_point
1685 try:
1686 utils.system(umount_cmd)
1687 return True
1688 except error.CmdError:
1689 return False
1690 else:
1691 logging.debug("%s is not mounted under %s", src, mount_point)
1692 return True
1693
1694
1695 def mount(src, mount_point, type, perm="rw"):
1696 """
1697 Mount the src into mount_point of the host.
1698
1699 @src: mount source
1700 @mount_point: mount point
1701 @type: file system type
1702 @perm: mount premission
1703 """
1704 umount(src, mount_point, type)
1705 mount_string = "%s %s %s %s" % (src, mount_point, type, perm)
1706
1707 if mount_string in file("/etc/mtab").read():
1708 logging.debug("%s is already mounted in %s with %s",
1709 src, mount_point, perm)
1710 return True
1711
1712 mount_cmd = "mount -t %s %s %s -o %s" % (type, src, mount_point, perm)
1713 try:
1714 utils.system(mount_cmd)
1715 except error.CmdError:
1716 return False
1717
1718 logging.debug("Verify the mount through /etc/mtab")
1719 if mount_string in file("/etc/mtab").read():
1720 logging.debug("%s is successfully mounted", src)
1721 return True
1722 else:
1723 logging.error("Can't find mounted NFS share - /etc/mtab contents \n%s",
1724 file("/etc/mtab").read())
1725 return False
OLDNEW
« cli/job.py ('K') | « client/tests/kvm/kvm_test_utils.py ('k') | client/tests/kvm/kvm_vm.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698