How to use remove_global_option method in autotest

Best Python code snippet using autotest_python Github


Full Screen

...266 :param key: option value or None for options with no values267 :return: None268 '''269 self.global_options_to_add[key] = val270 def remove_global_option(self, key, val=None):271 '''272 Removes a global option to the updated elilo configuration file273 :type key: string274 :param key: option name275 :type val: string or None276 :param key: option value or None for options with no values277 :return: None278 '''279 self.global_options_to_remove[key] = val280 def line_to_keyval(self, line):281 '''282 Transforms a text line from the configuration file into a tuple283 :type line: string284 :param line: line of text from the configuration file285 :return: a tuple with key and value286 '''287 parts = line.split('=', 1)288 key = parts[0].rstrip()289 if len(parts) == 1:290 val = None291 elif len(parts) == 2:292 val = parts[1].strip()293 return (key, val)294 def keyval_to_line(self, keyval):295 '''296 Transforms a tuple into a text line suitable for the config file297 :type keyval: tuple298 :param keyval: a tuple containing key and value299 :return: a text line suitable for the config file300 '''301 key, val = keyval302 if val is None:303 return '%s\n' % key304 else:305 return '%s=%s\n' % (key, val)306 def matches_global_option_to_remove(self, line):307 '''308 Utility method to check if option is to be removed309 :type line: string310 :param line: line of text from the configuration file311 :return: True or False312 '''313 key, val = self.line_to_keyval(line)314 if key in self.global_options_to_remove:315 return True316 else:317 return False318 def matches_global_option_to_add(self, line):319 '''320 Utility method to check if option is to be added321 :type line: string322 :param line: line of text from the configuration file323 :return: True or False324 '''325 key, val = self.line_to_keyval(line)326 if key in self.global_options_to_add:327 return True328 else:329 return False330 def get_updated_content(self):331 '''332 Returns the config file content with options to add and remove applied333 '''334 output = ''335 for key, val in self.global_options_to_add.items():336 output += self.keyval_to_line((key, val))337 eliloconf = open(self.path, 'r')338 for line in eliloconf.readlines():339 if self.matches_global_option_to_remove(line):340 continue341 if self.matches_global_option_to_add(line):342 continue343 else:344 output += line345 eliloconf.close()346 return output347 def update(self):348 '''349 Writes the updated content to the configuration file350 '''351 content = self.get_updated_content()352 eliloconf_write = open(self.path, 'w')353 eliloconf_write.write(content)354 eliloconf_write.close()355def find_executable(executable, favorite_path=None):356 '''357 Returns whether the system has a given executable358 :type executable: string359 :param executable: the name of a file that can be read and executed360 '''361 if os.path.isabs(executable):362 paths = [os.path.dirname(executable)]363 executable = os.path.basename(executable)364 else:365 paths = os.environ['PATH'].split(':')366 if favorite_path is not None and favorite_path not in paths:367 paths.insert(0, favorite_path)368 for d in paths:369 f = os.path.join(d, executable)370 if os.path.exists(f) and os.access(f, os.R_OK | os.X_OK):371 return f372 return None373def parse_entry(entry_str, separator='='):374 """375 Parse entry as returned by boottool.376 :param entry_str: one entry information as returned by boottool377 :return: dictionary of key -> value where key is the string before378 the first ":" in an entry line and value is the string after379 it380 """381 entry = {}382 for line in entry_str.splitlines():383 if len(line) == 0:384 continue385 try:386 name, value = line.split(separator, 1)387 except ValueError:388 continue389 name = name.strip()390 value = value.strip()391 if name == 'index':392 # index values are integrals393 value = int(value)394 entry[name] = value395 return entry396def detect_distro_type():397 '''398 Simple distro detection based on release/version files399 '''400 if os.path.exists('/etc/redhat-release'):401 return 'redhat'402 elif os.path.exists('/etc/debian_version'):403 return 'debian'404 elif os.path.exists('/etc/SuSE-release'):405 return 'suse'406 else:407 return None408class DebianBuildDeps(object):409 '''410 Checks and install grubby build dependencies on Debian (like) systems411 Tested on:412 * Debian Squeeze (6.0)413 * Ubuntu 12.04 LTS414 '''415 PKGS = ['gcc', 'make', 'libpopt-dev', 'libblkid-dev']416 def check(self):417 '''418 Checks if necessary packages are already installed419 '''420 result = True421 for p in self.PKGS:422 args = ['dpkg-query', '--show', '--showformat=${Status}', p]423 output = subprocess.Popen(args, shell=False,424 stdin=subprocess.PIPE,425 stdout=subprocess.PIPE,426 stderr=subprocess.PIPE,427 close_fds=True) if output != 'install ok installed':429 result = False430 return result431 def install(self):432 '''433 Attempt to install the build dependencies via a package manager434 '''435 if self.check():436 return True437 else:438 try:439 args = ['apt-get', 'update', '-qq']440,441 stdout=subprocess.PIPE,442 stderr=subprocess.PIPE)443 args = ['apt-get', 'install', '-qq'] + self.PKGS444,445 stdout=subprocess.PIPE,446 stderr=subprocess.PIPE)447 except OSError:448 pass449 return self.check()450class RPMBuildDeps(object):451 '''452 Base class for RPM based systems453 '''454 def check(self):455 '''456 Checks if necessary packages are already installed457 '''458 result = True459 for p in self.PKGS:460 args = ['rpm', '-q', '--qf=%{NAME}', p]461 output = subprocess.Popen(args, shell=False,462 stdin=subprocess.PIPE,463 stdout=subprocess.PIPE,464 stderr=subprocess.PIPE,465 close_fds=True) if not output.startswith(p):467 result = False468 return result469class SuseBuildDeps(RPMBuildDeps):470 '''471 Checks and install grubby build dependencies on SuSE (like) systems472 Tested on:473 * OpenSuSE 12.2474 '''475 PKGS = ['gcc', 'make', 'popt-devel', 'libblkid-devel']476 def install(self):477 '''478 Attempt to install the build dependencies via a package manager479 '''480 if self.check():481 return True482 else:483 try:484 args = ['zypper', '-n', '--no-cd', 'install'] + self.PKGS485 result =,486 stdout=subprocess.PIPE,487 stderr=subprocess.PIPE)488 except OSError:489 pass490 return self.check()491class RedHatBuildDeps(RPMBuildDeps):492 '''493 Checks and install grubby build dependencies on RedHat (like) systems494 Tested on:495 * Fedora 17496 * RHEL 5497 * RHEL 6498 '''499 PKGS = ['gcc', 'make']500 REDHAT_RELEASE_RE = re.compile('.*\srelease\s(\d)\.(\d)\s.*')501 def __init__(self):502 '''503 Initializes a new dep installer, taking into account RHEL version504 '''505 match = self.REDHAT_RELEASE_RE.match(open('/etc/redhat-release').read())506 if match:507 major, minor = match.groups()508 if int(major) <= 5:509 self.PKGS += ['popt', 'e2fsprogs-devel']510 else:511 self.PKGS += ['popt-devel', 'libblkid-devel']512 def install(self):513 '''514 Attempt to install the build dependencies via a package manager515 '''516 if self.check():517 return True518 else:519 try:520 args = ['yum', 'install', '-q', '-y'] + self.PKGS521 # This is an extra safety step, to install the needed header522 # in case the blkid headers package could not be detected523 args += ['/usr/include/popt.h',524 '/usr/include/blkid/blkid.h']525 result =,526 stdout=subprocess.PIPE,527 stderr=subprocess.PIPE)528 except OSError:529 pass530 return self.check()531DISTRO_DEPS_MAPPING = {532 'debian': DebianBuildDeps,533 'redhat': RedHatBuildDeps,534 'suse': SuseBuildDeps535}536def install_grubby_if_necessary(path=None):537 '''538 Installs grubby if it's necessary on this system539 Or if the required version is not sufficient for the needs of boottool540 '''541 installed_grubby = False542 if path is None:543 if find_executable(GRUBBY_DEFAULT_USER_PATH):544 executable = GRUBBY_DEFAULT_USER_PATH545 else:546 executable = find_executable(GRUBBY_DEFAULT_SYSTEM_PATH)547 else:548 executable = find_executable(path)549 if executable is None:550'Installing grubby because it was not found on this system')551 grubby = Grubby()552 path = grubby.grubby_install()553 installed_grubby = True554 else:555 grubby = Grubby(executable)556 current_version = grubby.get_grubby_version()557 if current_version is None:558 log.error('Could not find version for grubby executable "%s"',559 executable)560 path = grubby.grubby_install()561 installed_grubby = True562 elif current_version < GRUBBY_REQ_VERSION:563'Installing grubby because currently installed '564 'version (%s.%s) is not recent enough',565 current_version[0], current_version[1])566 path = grubby.grubby_install()567 installed_grubby = True568 if installed_grubby:569 grubby = Grubby(path)570 installed_version = grubby.get_grubby_version_raw()571 log.debug('Installed: %s', installed_version)572class GrubbyInstallException(Exception):573 '''574 Exception that signals failure when doing grubby installation575 '''576 pass577class Grubby(object):578 '''579 Grubby wrapper580 This class calls the grubby binary for most commands, but also581 adds some functionality that is not really suited to be included582 in int, such as boot-once.583 '''584 SUPPORTED_BOOTLOADERS = ('lilo', 'grub2', 'grub', 'extlinux', 'yaboot',585 'elilo')586 def __init__(self, path=None, opts=None):587 self._set_path(path)588 self.bootloader = None589 self.opts = opts590 self.log = logging.getLogger(self.__class__.__name__)591 if os.environ.has_key('BOOTTOOL_DEBUG_RUN'):592 self.debug_run = True593 else:594 self.debug_run = False595 self._check_grubby_version()596 self._set_bootloader()597 def _set_path(self, path=None):598 """599 Set grubby path.600 If path is not provided, check first if there's a built grubby,601 then look for the system grubby.602 :param path: Alternate grubby path.603 """604 if path is None:605 if os.path.exists(GRUBBY_DEFAULT_USER_PATH):606 self.path = GRUBBY_DEFAULT_USER_PATH607 else:608 self.path = GRUBBY_DEFAULT_SYSTEM_PATH609 else:610 self.path = path611 #612 # The following block contain utility functions that are used to build613 # most of these class methods, such as methods for running commands614 # and preparing grubby command line switches.615 #616 def _check_grubby_version(self):617 '''618 Checks the version of grubby in use and warns if it's not good enough619 '''620 current_version = self.get_grubby_version()621 if current_version is None:622 self.log.warn('Could not detect current grubby version. It may '623 'be that you are running an unsupported version '624 'of grubby')625 elif current_version < GRUBBY_REQ_VERSION:626 self.log.warn('version %s.%s being used is not guaranteed to '627 'work properly. Mininum required version is %s.%s.',628 current_version[0], current_version[1],629 GRUBBY_REQ_VERSION[0], GRUBBY_REQ_VERSION[1])630 def _run_get_output(self, arguments):631 '''632 Utility function that runs a command and returns command output633 '''634 if self.debug_run:635 self.log.debug('running: "%s"', ' '.join(arguments))636 result = None637 try:638 result = subprocess.Popen(arguments, shell=False,639 stdin=subprocess.PIPE,640 stdout=subprocess.PIPE,641 close_fds=True) except Exception:643 pass644 if result is not None:645 result = result.strip()646 if self.debug_run:647 logging.debug('previous command output: "%s"', result)648 else:649 self.log.error('_run_get_output error while running: "%s"',650 ' '.join(arguments))651 return result652 def _run_get_output_err(self, arguments):653 '''654 Utility function that runs a command and returns command output655 '''656 if self.debug_run:657 self.log.debug('running: "%s"', ' '.join(arguments))658 result = None659 try:660 result = subprocess.Popen(arguments, shell=False,661 stdin=subprocess.PIPE,662 stdout=subprocess.PIPE,663 stderr=subprocess.PIPE,664 close_fds=True) except Exception:666 pass667 if result is not None:668 result = result.strip()669 if self.debug_run:670 logging.debug('previous command output/error: "%s"', result)671 else:672 self.log.error('_run_get_output_err error while running: "%s"',673 ' '.join(arguments))674 return result675 def _run_get_return(self, arguments):676 '''677 Utility function that runs a command and returns status code678 '''679 if self.debug_run:680 self.log.debug('running: "%s"', ' '.join(arguments))681 result = None682 try:683 result = if self.debug_run:685 logging.debug('previous command result: %s', result)686 except OSError:687 result = -1688 self.log.error('caught OSError, returning %s', result)689 return result690 def _set_bootloader(self, bootloader=None):691 '''692 Attempts to detect what bootloader is installed on the system693 The result of this method is used in all other calls to grubby,694 so that it acts accordingly to the bootloader detected.695 '''696 if bootloader is None:697 result = self.get_bootloader()698 if result is not None:699 self.bootloader = result700 else:701 if bootloader in self.SUPPORTED_BOOTLOADERS:702 self.bootloader = bootloader703 else:704 raise ValueError('Bootloader "%s" is not supported' %705 bootloader)706 def _dist_uses_grub2(self):707 if self.get_architecture().startswith('ppc64'):708 (d_name, d_version, d_id) = platform.dist()709 if d_name.lower() == 'redhat' and d_version >= 7:710 return True711 if d_name.lower() == 'suse' and d_version >= 12:712 return True713 return False714 def _run_grubby_prepare_args(self, arguments, include_bootloader=True):715 '''716 Prepares the argument list when running a grubby command717 '''718 args = []719 if self.path is None:720 self._set_path()721 args.append(self.path)722 if self.path is not None and not os.path.exists(self.path):723 self.log.error('grubby executable does not exist: "%s"', self.path)724 if not os.access(self.path, os.R_OK | os.X_OK):725 self.log.error('insufficient permissions (read and execute) '726 'for grubby executable: "%s"', self.path)727 # If a bootloader has been detected, that is, a mode has been set,728 # it's passed as the first command line argument to grubby729 if include_bootloader and self.bootloader is not None:730 args.append('--%s' % self.bootloader)731 # Override configuration file732 if self.opts is not None and self.opts.config_file:733 args.append('--config-file=%s' % self.opts.config_file)734 elif self._dist_uses_grub2():735 args.append('--config-file=/boot/grub2/grub.cfg')736 args += arguments737 return args738 def _run_grubby_get_output(self, arguments, include_bootloader=True):739 '''740 Utility function that runs grubby with arguments and returns output741 '''742 args = self._run_grubby_prepare_args(arguments, include_bootloader)743 return self._run_get_output(args)744 def _run_grubby_get_return(self, arguments, include_bootloader=True):745 '''746 Utility function that runs grubby with and returns status code747 '''748 args = self._run_grubby_prepare_args(arguments, include_bootloader)749 return self._run_get_return(args)750 def _extract_tarball(self, tarball, directory):751 '''752 Extract tarball into the an directory753 This code assume the first (or only) entry is the main directory754 :type tarball: string755 :param tarball: tarball file path756 :type directory: string757 :param directory: directory path758 :return: path of toplevel directory as extracted from tarball759 '''760 f = members = f.getmembers()762 topdir = members[0]763 assert topdir.isdir()764 # we can not use extractall() because it is not available on python 2.4765 for m in members:766 f.extract(m, directory)767 return os.path.join(directory, def _get_entry_indexes(self, info):769 '''770 Returns the indexes found in a get_info() output771 :type info: list of lines772 :param info: result of utility method get_info()773 :return: maximum index number774 '''775 indexes = []776 for line in self.get_info_lines():777 try:778 key, value = line.split("=")779 if key == 'index':780 indexes.append(int(value))781 except ValueError:782 pass783 return indexes784 def _index_for_title(self, title):785 '''786 Returns the index of an entry based on the title of the entry787 :type title: string788 :param title: the title of the entry789 :return: the index of the given entry or None790 '''791 if self._is_number(title):792 return title793 info = self.get_info_lines()794 for i in self._get_entry_indexes(info):795 info = self.get_info(i)796 if info is None:797 continue798 lines = info.splitlines()799 looking_for = ('title=%s' % title,800 'label=%s' % title)801 for line in lines:802 if line in looking_for:803 return i804 return None805 def _info_filter(self, info, key, value=None):806 '''807 Filters info, looking for keys, optionally set with a given value808 :type info: list of lines809 :param info: result of utility method get_info()810 :type key: string811 :param key: filter based on this key812 :type value: string813 :param value: filter based on this value814 :return: value or None815 '''816 for line in info:817 if value is not None:818 looking_for = '%s=%s' % (key, value)819 if line == looking_for:820 return line.split("=")[1]821 else:822 if line.startswith("%s=" % key):823 return line.split("=")[1]824 return None825 def _kernel_for_title(self, title):826 '''827 Returns the kernel path for an entry based on its title828 :type title: string829 :param title: the title of the entry830 :return: the kernel path of None831 '''832 index = self._index_for_title(title)833 if index is not None:834 info = self.get_info_lines(index)835 kernel = self._info_filter(info, 'kernel')836 return kernel837 else:838 return None839 def _is_number(self, data):840 '''841 Returns true if supplied data is an int or string with digits842 '''843 if isinstance(data, int):844 return True845 elif isinstance(data, str) and data.isdigit():846 return True847 return False848 def _get_entry_selection(self, data):849 '''850 Returns a valid grubby parameter for commands such as --update-kernel851 '''852 if self._is_number(data):853 return data854 elif isinstance(data, str) and data.startswith('/'):855 # assume it's the kernel filename856 return data857 elif isinstance(data, str):858 return self._kernel_for_title(data)859 else:860 raise ValueError("Bad value for 'kernel' parameter. Expecting "861 "either and int (index) or string (kernel or "862 "title)")863 def _remove_duplicate_cmdline_args(self, cmdline):864 """865 Remove the duplicate entries in cmdline making sure that the first866 duplicate occurrences are the ones removed and the last one remains867 (this is in order to not change the semantics of the "console"868 parameter where the last occurrence has special meaning)869 :param cmdline: a space separate list of kernel boot parameters870 (ex. 'console=ttyS0,57600n8 nmi_watchdog=1')871 :return: a space separated list of kernel boot parameters without872 duplicates873 """874 copied = set()875 new_args = []876 for arg in reversed(cmdline.split()):877 if arg not in copied:878 new_args.insert(0, arg)879 copied.add(arg)880 return ' '.join(new_args)881 #882 # The following methods implement a form of "API" that action methods883 # can rely on. Another goal is to maintain compatibility with the current884 # client side API in autotest (client/shared/ #886 def get_bootloader(self):887 '''888 Get the bootloader name that is detected on this machine889 This module performs the same action as client side boottool.py890 get_type() method, but with a better name IMHO.891 :return: name of detected bootloader892 '''893 args = [self.path, '--bootloader-probe']894 output = self._run_get_output_err(args)895 if output is None:896 return None897 if output.startswith('grubby: bad argument'):898 return None899 elif output not in self.SUPPORTED_BOOTLOADERS:900 return None901 return output902 # Alias for client side API903 get_type = get_bootloader904 # Alias for boottool app905 bootloader_probe = get_bootloader906 def get_architecture(self):907 '''908 Get the system architecture909 This is much simpler version then the original boottool version, that910 does not attempt to filter the result of the command / system call911 that returns the archicture.912 :return: string with system archicteture, such as x86_64, ppc64, etc913 '''914 return os.uname()[4]915 # Alias for boottool app916 arch_probe = get_architecture917 def get_titles(self):918 '''919 Get the title of all boot entries.920 :return: list with titles of boot entries921 '''922 titles = []923 for line in self.get_info_lines():924 try:925 key, value = line.split("=")926 if key in ['title', 'label']:927 titles.append(value)928 except ValueError:929 pass930 return titles931 def get_default_index(self):932 '''933 Get the default entry index.934 This module performs the same action as client side boottool.py935 get_default() method, but with a better name IMHO.936 :return: an integer with the the default entry.937 '''938 default_index = self._run_grubby_get_output(['--default-index'])939 if default_index is not None and default_index:940 default_index = int(default_index)941 return default_index942 # Alias for client side API943 get_default = get_default_index944 # Alias for boottool app945 default = get_default_index946 def set_default_by_index(self, index):947 """948 Sets the given entry number to be the default on every next boot949 To set a default only for the next boot, use boot_once() instead.950 This module performs the same action as client side boottool.py951 set_default() method, but with a better name IMHO.952 Note: both --set-default=<kernel> and --set-default-index=<index>953 on grubby returns no error when it doesn't find the kernel or954 index. So this method will, until grubby gets fixed, always return955 success.956 :param index: entry index number to set as the default.957 """958 return self._run_grubby_get_return(['--set-default-index=%s' % index])959 # Alias for client side API960 set_default = set_default_by_index961 def get_default_title(self):962 '''963 Get the default entry title.964 Conforms to the client side API, but rely directly on965 grubby functionality.966 :return: a string of the default entry title.967 '''968 return self._run_grubby_get_output(['--default-title'])969 def get_entry(self, search_info):970 """971 Get a single bootloader entry information.972 NOTE: if entry is "fallback" and bootloader is grub973 use index instead of kernel title ("fallback") as fallback is974 a special option in grub975 :param search_info: can be 'default', position number or title976 :return: a dictionary of key->value where key is the type of entry977 information (ex. 'title', 'args', 'kernel', etc) and value978 is the value for that piece of information.979 """980 info = self.get_info(search_info)981 return parse_entry(info)982 def get_entries(self):983 """984 Get all entries information.985 :return: a dictionary of index -> entry where entry is a dictionary986 of entry information as described for get_entry().987 """988 raw = self.get_info()989 entries = {}990 for entry_str in re.split("index", raw):991 if len(entry_str.strip()) == 0:992 continue993 if entry_str.startswith('boot='):994 continue995 if 'non linux entry' in entry_str:996 continue997 entry = parse_entry("index" + entry_str)998 try:999 entries[entry["index"]] = entry1000 except KeyError:1001 continue1002 return entries1003 def get_info(self, entry='ALL'):1004 '''1005 Returns information on a given entry, or all of them if not specified1006 The information is returned as a set of lines, that match the output1007 of 'grubby --info=<entry>'1008 :type entry: string1009 :param entry: entry description, usually an index starting from 01010 :return: set of lines1011 '''1012 command = '--info=%s' % entry1013 info = self._run_grubby_get_output([command])1014 if info:1015 return info1016 def get_title_for_kernel(self, path):1017 """1018 Returns a title for a particular kernel.1019 :param path: path of the kernel image configured in the boot config1020 :return: if the given kernel path is found it will return a string1021 with the title for the found entry, otherwise returns None1022 """1023 entries = self.get_entries()1024 for entry in entries.itervalues():1025 if entry.get('kernel') == path:1026 return entry['title']1027 return None1028 def add_args(self, kernel, args):1029 """1030 Add cmdline arguments for the specified kernel.1031 :param kernel: can be a position number (index) or title1032 :param args: argument to be added to the current list of args1033 """1034 entry_selection = self._get_entry_selection(kernel)1035 command_arguments = ['--update-kernel=%s' % entry_selection,1036 '--args=%s' % args]1037 self._run_grubby_get_return(command_arguments)1038 def remove_args(self, kernel, args):1039 """1040 Removes specified cmdline arguments.1041 :param kernel: can be a position number (index) or title1042 :param args: argument to be removed of the current list of args1043 """1044 entry_selection = self._get_entry_selection(kernel)1045 command_arguments = ['--update-kernel=%s' % entry_selection,1046 '--remove-args=%s' % args]1047 self._run_grubby_get_return(command_arguments)1048 def add_kernel(self, path, title='autoserv', root=None, args=None,1049 initrd=None, default=False, position='end'):1050 """1051 Add a kernel entry to the bootloader (or replace if one exists1052 already with the same title).1053 :param path: string path to the kernel image file1054 :param title: title of this entry in the bootloader config1055 :param root: string of the root device1056 :param args: string with cmdline args1057 :param initrd: string path to the initrd file1058 :param default: set to True to make this entry the default one1059 (default False)1060 :param position: where to insert the new entry in the bootloader1061 config file (default 'end', other valid input 'start', or1062 # of the title)1063 :param xen_hypervisor: xen hypervisor image file (valid only when1064 xen mode is enabled)1065 """1066 if title in self.get_titles():1067 self.remove_kernel(title)1068 parameters = ['--add-kernel=%s' % path, '--title=%s' % title]1069 # FIXME: grubby takes no --root parameter1070 # if root:1071 # parameters.append('--root=%s' % root)1072 if args:1073 parameters.append('--args=%s' %1074 self._remove_duplicate_cmdline_args(args))1075 if initrd:1076 parameters.append('--initrd=%s' % initrd)1077 if default:1078 parameters.append('--make-default')1079 # There's currently an issue with grubby '--add-to-bottom' feature.1080 # Because it uses the tail instead of the head of the list to add1081 # a new entry, when copying a default entry as a template1082 # (--copy-default), it usually copies the "recover" entries that1083 # usually go along a regular boot entry, specially on grub2.1084 #1085 # So, for now, until I fix grubby, we'll *not* respect the position1086 # (--position=end) command line option.1087 #1088 # if opts.position == 'end':1089 # parameters.append('--add-to-bottom')1090 parameters.append("--copy-default")1091 return self._run_grubby_get_return(parameters)1092 def remove_kernel(self, kernel):1093 """1094 Removes a specific entry from the bootloader configuration.1095 :param kernel: entry position or entry title.1096 FIXME: param kernel should also take 'start' or 'end'.1097 """1098 entry_selection = self._get_entry_selection(kernel)1099 if entry_selection is None:1100 self.log.debug('remove_kernel for title "%s" did not find an '1101 'entry. This is most probably NOT an error', kernel)1102 return 01103 command_arguments = ['--remove-kernel=%s' % entry_selection]1104 return self._run_grubby_get_return(command_arguments)1105 #1106 # The following methods are not present in the original client side1107 # boottool.py1108 #1109 def get_info_lines(self, entry='ALL'):1110 '''1111 Returns information on a given entry, or all of them if not specified1112 The information is returned as a set of lines, that match the output1113 of 'grubby --info=<entry>'1114 :type entry: string1115 :param entry: entry description, usually an index starting from 01116 :return: set of lines1117 '''1118 info = self.get_info(entry)1119 if info:1120 return info.splitlines()1121 def get_grubby_version_raw(self):1122 '''1123 Get the version of grubby that is installed on this machine as is1124 :return: string with raw output from grubby --version1125 '''1126 return self._run_grubby_get_output(['--version'], False)1127 def get_grubby_version(self):1128 '''1129 Get the version of grubby that is installed on this machine1130 :return: tuple with (major, minor) grubby version1131 '''1132 output = self.get_grubby_version_raw()1133 if output is None:1134 self.log.warn('Could not run grubby to fetch its version')1135 return None1136 match = re.match('(grubby version)?(\s)?(\d+)\.(\d+)(.*)', output)1137 if match:1138 groups = match.groups()1139 return (int(groups[2]), int(groups[3]))1140 else:1141 return None1142 def grubby_install_patch_makefile(self):1143 '''1144 Patch makefile, making CFLAGS more forgivable to older toolchains1145 '''1146 cflags_line = 'CFLAGS += $(RPM_OPT_FLAGS) -std=gnu99 -ggdb\n'1147 libs_line = 'grubby_LIBS = -lblkid -lpopt -luuid\n'1148 shutil.move('Makefile', 'Makefile.boottool.bak')1149 o = open('Makefile', 'w')1150 for l in open('Makefile.boottool.bak').readlines():1151 if l.startswith('CFLAGS += '):1152 o.write(cflags_line)1153 elif l.startswith('grubby_LIBS = -lblkid -lpopt'):1154 o.write(libs_line)1155 else:1156 o.write(l)1157 o.close()1158 def grubby_install_backup(self, path):1159 '''1160 Backs up the current grubby binary to make room the one we'll build1161 :type path: string1162 :param path: path to the binary that should be backed up1163 '''1164 backup_path = '%s.boottool.bkp' % path1165 if (os.path.exists(path) and not os.path.exists(backup_path)):1166 try:1167 shutil.move(path, backup_path)1168 except Exception:1169 self.log.warn('Failed to backup the current grubby binary')1170 def grubby_install_fetch_tarball(self, topdir):1171 '''1172 Fetches and verifies the grubby source tarball1173 '''1174 tarball_name = os.path.basename(GRUBBY_TARBALL_URI)1175 # first look in the current directory1176 try:1177 tarball = tarball_name1178 f = open(tarball)1179 except Exception:1180 try:1181 # then the autotest source directory1182 # pylint: disable=E06111183 from autotest.client.shared.settings import settings1184 top_path = settings.get_value('COMMON', 'autotest_top_path')1185 tarball = os.path.join(top_path, tarball_name)1186 f = open(tarball)1187 except Exception:1188 # then try to grab it from github1189 try:1190 tarball = os.path.join(topdir, tarball_name)1191 urllib.urlretrieve(GRUBBY_TARBALL_URI, tarball)1192 f = open(tarball)1193 except Exception:1194 return None1195 tarball_md5 = md5.md5( if tarball_md5 != GRUBBY_TARBALL_MD5:1197 return None1198 return tarball1199 def grubby_build(self, topdir, tarball):1200 '''1201 Attempts to build grubby from the source tarball1202 '''1203 def log_lines(lines):1204 for line in lines:1205 self.log.debug(line.strip())1206 try:1207 find_header('popt.h')1208 except ValueError:1209 self.log.debug('No popt.h header present, skipping build')1210 return False1211 tarball_name = os.path.basename(tarball)1212 srcdir = os.path.join(topdir, 'src')1213 srcdir = self._extract_tarball(tarball, srcdir)1214 os.chdir(srcdir)1215 self.grubby_install_patch_makefile()1216 result = subprocess.Popen(['make'],1217 stdout=subprocess.PIPE,1218 stderr=subprocess.PIPE)1219 if result.wait() != 0:1220 self.log.debug('Failed to build grubby during "make" step')1221 log_lines( return False1223 install_root = os.path.join(topdir, 'install_root')1224 os.environ['DESTDIR'] = install_root1225 result = subprocess.Popen(['make', 'install'],1226 stdout=subprocess.PIPE,1227 stderr=subprocess.PIPE)1228 if result.wait() != 0:1229 self.log.debug('Failed to build grubby during "make install" step')1230 log_lines( return False1232 return True1233 def grubby_install(self, path=None):1234 '''1235 Attempts to install a recent enough version of grubby1236 So far tested on:1237 * Fedora 16 x86_641238 * Debian 6 x86_641239 * SuSE 12.1 x86_641240 * RHEL 4 on ia64 (with updated python 2.4)1241 * RHEL 5 on ia641242 * RHEL 6 on ppc641243 '''1244 if path is None:1245 if os.geteuid() == 0:1246 path = GRUBBY_DEFAULT_SYSTEM_PATH1247 else:1248 path = GRUBBY_DEFAULT_USER_PATH1249 topdir = tempfile.mkdtemp()1250 deps_klass = DISTRO_DEPS_MAPPING.get(detect_distro_type(), None)1251 if deps_klass is not None:1252 deps = deps_klass()1253 if not deps.check():1254 self.log.warn('Installing distro build deps for grubby. This '1255 'may take a while, depending on bandwidth and '1256 'actual number of packages to install')1257 if not deps.install():1258 self.log.error('Failed to install distro build deps for '1259 'grubby')1260 tarball = self.grubby_install_fetch_tarball(topdir)1261 if tarball is None:1262 raise GrubbyInstallException('Failed to fetch grubby tarball')1263 srcdir = os.path.join(topdir, 'src')1264 install_root = os.path.join(topdir, 'install_root')1265 os.mkdir(install_root)1266 if not self.grubby_build(topdir, tarball):1267 raise GrubbyInstallException('Failed to build grubby')1268 self.grubby_install_backup(path)1269 grubby_bin = os.path.join(install_root, 'sbin', 'grubby')1270 inst_dir = os.path.dirname(path)1271 if not os.access(inst_dir, os.W_OK):1272 raise GrubbyInstallException('No permission to copy grubby '1273 'binary to directory "%s"' % inst_dir)1274 try:1275 shutil.copy(grubby_bin, path)1276 except Exception:1277 raise GrubbyInstallException('Failed to copy grubby binary to '1278 'directory "%s"' % inst_dir)1279 return path1280 def boot_once(self, title=None):1281 '''1282 Configures the bootloader to boot an entry only once1283 This is not implemented by grubby, but directly implemented here, via1284 the 'boot_once_<bootloader>' method.1285 '''1286 self.log.debug('Title chosen to boot once: %s', title)1287 available_titles = self.get_titles()1288 if title not in available_titles:1289 self.log.error('Entry with title "%s" was not found', title)1290 return -11291 default_title = self.get_default_title()1292 self.log.debug('Title actually set as default: %s', default_title)1293 if default_title == title:1294'Doing nothing: entry to boot once is the same as '1295 'default entry')1296 return1297 else:1298 self.log.debug('Setting boot once for entry: %s', title)1299 bootloader = self.get_bootloader()1300 if bootloader in ('grub', 'grub2', 'elilo'):1301 entry_index = self._index_for_title(title)1302 if entry_index is None:1303 self.log.error('Could not find index for entry with title '1304 '"%s"', title)1305 return -11306 if bootloader == 'grub':1307 return self.boot_once_grub(entry_index)1308 elif bootloader == 'grub2':1309 return self.boot_once_grub2(entry_index)1310 elif bootloader == 'yaboot':1311 return self.boot_once_yaboot(title)1312 elif bootloader == 'elilo':1313 return self.boot_once_elilo(entry_index)1314 else:1315 self.log.error("Detected bootloader does not implement boot once")1316 return -11317 def boot_once_grub(self, entry_index):1318 '''1319 Implements the boot once feature for the grub bootloader1320 '''1321 # grubonce is a hack present in distros like OpenSUSE1322 grubonce_cmd = find_executable('grubonce')1323 if grubonce_cmd is None:1324 # XXX: check the type of default set (numeric or "saved")1325 grub_instructions = ['savedefault --default=%s --once' %1326 entry_index, 'quit']1327 grub_instructions_text = '\n'.join(grub_instructions)1328 grub_binary = find_executable('grub')1329 if grub_binary is None:1330 self.log.error("Could not find the 'grub' binary, aborting")1331 return -11332 p = subprocess.Popen([grub_binary, '--batch'],1333 stdin=subprocess.PIPE,1334 stdout=subprocess.PIPE,1335 stderr=subprocess.PIPE)1336 out, err = p.communicate(grub_instructions_text)1337 complete_out = ''1338 if out is not None:1339 complete_out = out1340 if err is not None:1341 complete_out += "\n%s" % err1342 grub_batch_err = []1343 if complete_out:1344 for l in complete_out.splitlines():1345 if'error', l, re.IGNORECASE):1346 grub_batch_err.append(l)1347 if grub_batch_err:1348 self.log.error("Error while running grub to set boot "1349 "once: %s", "\n".join(grub_batch_err))1350 return -11351 self.log.debug('No error detected while running grub to set boot '1352 'once')1353 return 01354 else:1355 rc = self._run_get_return([grubonce_cmd, str(entry_index)])1356 if rc:1357 self.log.error('Error running %s', grubonce_cmd)1358 else:1359 self.log.debug('No error detected while running %s',1360 grubonce_cmd)1361 return rc1362 def boot_once_grub2(self, entry_index):1363 '''1364 Implements the boot once feature for the grub2 bootloader1365 Caveat: this assumes the default set is of type "saved", and not a1366 numeric value.1367 '''1368 default_index_re = re.compile('\s*set\s+default\s*=\s*\"+(\d+)\"+')1369 grub_reboot_names = ['grub-reboot', 'grub2-reboot']1370 grub_reboot_exec = None1371 for grub_reboot in grub_reboot_names:1372 grub_reboot_exec = find_executable(grub_reboot)1373 if grub_reboot_exec is not None:1374 break1375 if grub_reboot_exec is None:1376 self.log.error('Could not find executable among searched names: '1377 '%s', ' ,'.join(grub_reboot_names))1378 return -11379 grub_set_default_names = ['grub-set-default', 'grub2-set-default']1380 grub_set_default_exec = None1381 for grub_set_default in grub_set_default_names:1382 grub_set_default_exec = find_executable(grub_set_default)1383 if grub_set_default_exec is not None:1384 break1385 if grub_set_default_exec is None:1386 self.log.error('Could not find executable among searched names: '1387 '%s', ' ,'.join(grub_set_default_names))1388 return -11389 # Make sure the "set default" entry in the configuration file is set1390 # to "${saved_entry}. Assuming the config file is at /boot/grub/grub.cfg1391 deb_grub_cfg_path = '/boot/grub/grub.cfg'1392 if self._dist_uses_grub2():1393 deb_grub_cfg_path = '/boot/grub2/grub.cfg'1394 deb_grub_cfg_bkp_path = '%s.boottool.bak' % deb_grub_cfg_path1395 default_index = None1396 if os.path.exists(deb_grub_cfg_path):1397 shutil.move(deb_grub_cfg_path, deb_grub_cfg_bkp_path)1398 o = open(deb_grub_cfg_path, 'w')1399 for l in open(deb_grub_cfg_bkp_path).readlines():1400 m = default_index_re.match(l)1401 if m is not None:1402 default_index = int(m.groups()[0])1403 o.write('set default="${saved_entry}"\n')1404 else:1405 o.write(l)1406 o.close()1407 # Make the current default entry the "previous saved entry"1408 if default_index is None:1409 default_index = self.get_default_index()1410 else:1411 # grubby adds entries to top. this assumes a new entry to boot once1412 # has already been added to the top, so fallback to the second1413 # entry (index 1) if the boot once entry fails to boot1414 if entry_index == 0:1415 default_index = 11416 else:1417 default_index = 01418 # A negative index is never acceptable1419 if default_index >= 0:1420 prev_saved_return = self._run_get_return([grub_set_default_exec,1421 '%s' % default_index])1422 if prev_saved_return != 0:1423 self.log.error('Could not make entry %s the previous saved entry',1424 default_index)1425 return prev_saved_return1426 # Finally set the boot once entry1427 return self._run_get_return([grub_reboot_exec,1428 '%s' % entry_index])1429 def boot_once_yaboot(self, entry_title):1430 '''1431 Implements the boot once feature for the yaboot bootloader1432 '''1433 nvsetenv_cmd = find_executable('nvsetenv')1434 if nvsetenv_cmd is None:1435 self.log.error("Could not find nvsetenv in PATH")1436 return -11437 return self._run_get_return([nvsetenv_cmd,1438 'boot-once',1439 entry_title])1440 def boot_once_elilo(self, entry_index):1441 '''1442 Implements boot once for machines with kernel >= 2.61443 This manipulates EFI variables via the interface available at1444 /sys/firmware/efi/vars1445 '''1446 info = self.get_entry(entry_index)1447 kernel = os.path.basename(info['kernel'])1448 # remove quotes1449 args = info['args']1450 if args[0] == '"':1451 args = args[1:]1452 if args[-1] == '"':1453 args = args[:-1]1454 params = "root=%s %s" % (info['root'], args)1455 data = "%s %s" % (kernel, params)1456 efi = EfiToolSys()1457 if not (efi.create_variable('EliloAlt', data)):1458 return -11459 eliloconf = EliloConf()1460 eliloconf.add_global_option('checkalt')1461 eliloconf.add_global_option('initrd', os.path.basename(info['initrd']))1462 eliloconf.remove_global_option('prompt')1463 eliloconf.update()1464 return 01465class OptionParser(optparse.OptionParser):1466 '''1467 Command line option parser1468 Aims to maintain compatibility at the command line level with boottool1469 '''1470 option_parser_usage = '''%prog [options]'''1471 def __init__(self, **kwargs):1472 optparse.OptionParser.__init__(self,1473 usage=self.option_parser_usage,1474 **kwargs)1475 misc = self.add_option_group('MISCELLANEOUS OPTIONS')1476 misc.add_option('--config-file',...

Full Screen

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:


You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Run autotest automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?