def _execute_code(self, code_file, namespace, protect=True): """ Execute code using a copy of namespace as a server control script. Unless protect_namespace is explicitly set to False, the dict will not be modified. Args: code_file: The filename of the control file to execute. namespace: A dict containing names to make available during execution. protect: Boolean. If True (the default) a copy of the namespace dict is used during execution to prevent the code from modifying its contents outside of this function. If False the raw dict is passed in and modifications will be allowed. """ if protect: namespace = namespace.copy() self._fill_server_control_namespace(namespace, protect=protect) # TODO: Simplify and get rid of the special cases for only 1 machine. if len(self.machines) > 1: machines_text = '\n'.join(self.machines) + '\n' # Only rewrite the file if it does not match our machine list. try: machines_f = open(MACHINES_FILENAME, 'r') existing_machines_text = machines_f.read() machines_f.close() except EnvironmentError: existing_machines_text = None if machines_text != existing_machines_text: utils.open_write_close(MACHINES_FILENAME, machines_text) execfile(code_file, namespace, namespace)
def test_simple_functionality(self): data = "\n\nwhee\n" test_file = mock.SaveDataAfterCloseStringIO() utils.open.expect_call("filename", "w").and_return(test_file) utils.open_write_close("filename", data) self.god.check_playback() self.assertEqual(data, test_file.final_data)
def configure_crash_handler(self): """ Configure the crash handler by: * Setting up core size to unlimited * Putting an appropriate crash handler on /proc/sys/kernel/core_pattern * Create files that the crash handler will use to figure which tests are active at a given moment The crash handler will pick up the core file and write it to self.debugdir, and perform analysis on it to generate a report. The program also outputs some results to syslog. If multiple tests are running, an attempt to verify if we still have the old PID on the system process table to determine whether it is a parent of the current test execution. If we can't determine it, the core file and the report file will be copied to all test debug dirs. """ self.crash_handling_enabled = False # make sure this script will run with a new enough python to work cmd = ("python3 -c 'import sys; " "print(sys.version_info[0], sys.version_info[1])'") result = utils.run(cmd, ignore_status=True, verbose=False) if result.exit_status != 0: logging.warning( 'System python is too old, crash handling disabled') return major, minor = [int(x) for x in result.stdout.strip().split()] if (major, minor) < (2, 4): logging.warning( 'System python is too old, crash handling disabled') return if not settings.settings.get_value( 'COMMON', 'crash_handling_enabled', type=bool): return self.pattern_file = '/proc/sys/kernel/core_pattern' try: # Enable core dumps resource.setrlimit(resource.RLIMIT_CORE, (-1, -1)) # Trying to backup core pattern and register our script self.core_pattern_backup = open(self.pattern_file, 'r').read() pattern_file = open(self.pattern_file, 'w') tools_dir = os.path.join(self.autodir, 'tools') crash_handler_path = os.path.join(tools_dir, 'crash_handler.py') pattern_file.write('|' + crash_handler_path + ' %p %t %u %s %h %e') # Writing the files that the crash handler is going to use self.debugdir_tmp_file = ('/tmp/autotest_results_dir.%s' % os.getpid()) utils.open_write_close(self.debugdir_tmp_file, self.debugdir + "\n") except Exception as e: logging.warning('Crash handling disabled: %s', e) else: self.crash_handling_enabled = True try: os_dep.command('gdb') except ValueError: logging.warning('Could not find GDB installed. Crash handling ' 'will operate with limited functionality')
def request_devs(self, devices=None): """ Implement setup process: unbind the PCI device and then bind it to the device driver. :param devices: List of device dict :type devices: List of dict :return: List of successfully requested devices' PCI IDs. :rtype: List of string """ if not self.pf_vf_info: self.pf_vf_info = self.get_pf_vf_info() base_dir = "/sys/bus/pci" stub_path = os.path.join(base_dir, "drivers/%s" % self.device_driver) self.pci_ids = self.get_devs(devices) logging.info("The following pci_ids were found: %s", self.pci_ids) requested_pci_ids = [] # Setup all devices specified for assignment to guest for p_id in self.pci_ids: if self.device_driver == "vfio-pci": pci_ids = self.get_same_group_devs(p_id) logging.info("Following devices are in same group: %s", pci_ids) else: pci_ids = [p_id] for pci_id in pci_ids: short_id = pci_id[5:] drv_path = os.path.join(base_dir, "devices/%s/driver" % pci_id) dev_prev_driver = os.path.realpath(os.path.join(drv_path, os.readlink(drv_path))) self.dev_drivers[pci_id] = dev_prev_driver # Judge whether the device driver has been binded to stub if not self.is_binded_to_stub(pci_id): error.context("Bind device %s to stub" % pci_id, logging.info) vendor_id = utils_misc.get_vendor_from_pci_id(short_id) stub_new_id = os.path.join(stub_path, "new_id") unbind_dev = os.path.join(drv_path, "unbind") stub_bind = os.path.join(stub_path, "bind") info_write_to_files = [(vendor_id, stub_new_id), (pci_id, unbind_dev), (pci_id, stub_bind)] for content, f_name in info_write_to_files: try: logging.info("Write '%s' to file '%s'", content, f_name) utils.open_write_close(f_name, content) except IOError: logging.debug("Failed to write %s to file %s", content, f_name) continue if not self.is_binded_to_stub(pci_id): logging.error("Binding device %s to stub failed", pci_id) continue else: logging.debug("Device %s already binded to stub", pci_id) requested_pci_ids.append(p_id) return requested_pci_ids
def request_devs(self, count=None): """ Implement setup process: unbind the PCI device and then bind it to the pci-stub driver. @param count: count number of PCI devices needed for pass through @return: a list of successfully requested devices' PCI IDs. """ if count is None: count = self.devices_requested base_dir = "/sys/bus/pci" stub_path = os.path.join(base_dir, "drivers/pci-stub") self.pci_ids = self.get_devs(count) logging.info("The following pci_ids were found: %s", self.pci_ids) requested_pci_ids = [] # Setup all devices specified for assignment to guest for pci_id in self.pci_ids: full_id = utils_misc.get_full_pci_id(pci_id) if not full_id: continue drv_path = os.path.join(base_dir, "devices/%s/driver" % full_id) dev_prev_driver = os.path.realpath( os.path.join(drv_path, os.readlink(drv_path))) self.dev_drivers[pci_id] = dev_prev_driver # Judge whether the device driver has been binded to stub if not self.is_binded_to_stub(full_id): error.context("Bind device %s to stub" % full_id, logging.info) vendor_id = utils_misc.get_vendor_from_pci_id(pci_id) stub_new_id = os.path.join(stub_path, 'new_id') unbind_dev = os.path.join(drv_path, 'unbind') stub_bind = os.path.join(stub_path, 'bind') info_write_to_files = [(vendor_id, stub_new_id), (full_id, unbind_dev), (full_id, stub_bind)] for content, file in info_write_to_files: try: utils.open_write_close(file, content) except IOError: logging.debug("Failed to write %s to file %s", content, file) continue if not self.is_binded_to_stub(full_id): logging.error("Binding device %s to stub failed", pci_id) continue else: logging.debug("Device %s already binded to stub", pci_id) requested_pci_ids.append(pci_id) return requested_pci_ids
def request_devs(self, count=None): """ Implement setup process: unbind the PCI device and then bind it to the pci-stub driver. @param count: count number of PCI devices needed for pass through @return: a list of successfully requested devices' PCI IDs. """ if count is None: count = self.devices_requested base_dir = "/sys/bus/pci" stub_path = os.path.join(base_dir, "drivers/pci-stub") self.pci_ids = self.get_devs(count) logging.info("The following pci_ids were found: %s", self.pci_ids) requested_pci_ids = [] # Setup all devices specified for assignment to guest for pci_id in self.pci_ids: full_id = utils_misc.get_full_pci_id(pci_id) if not full_id: continue drv_path = os.path.join(base_dir, "devices/%s/driver" % full_id) dev_prev_driver = os.path.realpath(os.path.join(drv_path, os.readlink(drv_path))) self.dev_drivers[pci_id] = dev_prev_driver # Judge whether the device driver has been binded to stub if not self.is_binded_to_stub(full_id): error.context("Bind device %s to stub" % full_id, logging.info) vendor_id = utils_misc.get_vendor_from_pci_id(pci_id) stub_new_id = os.path.join(stub_path, 'new_id') unbind_dev = os.path.join(drv_path, 'unbind') stub_bind = os.path.join(stub_path, 'bind') info_write_to_files = [(vendor_id, stub_new_id), (full_id, unbind_dev), (full_id, stub_bind)] for content, file in info_write_to_files: try: utils.open_write_close(file, content) except IOError: logging.debug("Failed to write %s to file %s", content, file) continue if not self.is_binded_to_stub(full_id): logging.error("Binding device %s to stub failed", pci_id) continue else: logging.debug("Device %s already binded to stub", pci_id) requested_pci_ids.append(pci_id) return requested_pci_ids
def configure_crash_handler(self): """ Configure the crash handler by: * Setting up core size to unlimited * Putting an appropriate crash handler on /proc/sys/kernel/core_pattern * Create files that the crash handler will use to figure which tests are active at a given moment The crash handler will pick up the core file and write it to self.debugdir, and perform analysis on it to generate a report. The program also outputs some results to syslog. If multiple tests are running, an attempt to verify if we still have the old PID on the system process table to determine whether it is a parent of the current test execution. If we can't determine it, the core file and the report file will be copied to all test debug dirs. """ self.crash_handling_enabled = False # make sure this script will run with a new enough python to work cmd = ("python -c 'import sys; " "print sys.version_info[0], sys.version_info[1]'") result = utils.run(cmd, ignore_status=True, verbose=False) if result.exit_status != 0: logging.warning('System python is too old, crash handling disabled') return major, minor = [int(x) for x in result.stdout.strip().split()] if (major, minor) < (2, 4): logging.warning('System python is too old, crash handling disabled') return if not settings.settings.get_value('COMMON', 'crash_handling_enabled', type=bool): return self.pattern_file = '/proc/sys/kernel/core_pattern' try: # Enable core dumps resource.setrlimit(resource.RLIMIT_CORE, (-1, -1)) # Trying to backup core pattern and register our script self.core_pattern_backup = open(self.pattern_file, 'r').read() pattern_file = open(self.pattern_file, 'w') tools_dir = os.path.join(self.autodir, 'tools') crash_handler_path = os.path.join(tools_dir, 'crash_handler.py') pattern_file.write('|' + crash_handler_path + ' %p %t %u %s %h %e') # Writing the files that the crash handler is going to use self.debugdir_tmp_file = ('/tmp/autotest_results_dir.%s' % os.getpid()) utils.open_write_close(self.debugdir_tmp_file, self.debugdir + "\n") except Exception, e: logging.warning('Crash handling disabled: %s', e)
def crash_handler_report(self): """ If core dumps are found on the debugdir after the execution of the test, let the user know. """ if self.crash_handling_enabled: # Remove the debugdir info file os.unlink(self.debugdir_tmp_file) # Restore the core pattern backup try: utils.open_write_close(self.pattern_file, self.core_pattern_backup) except EnvironmentError: pass # Let the user know if core dumps were generated during the test core_dirs = glob.glob('%s/crash.*' % self.debugdir) if core_dirs: logging.warning('Programs crashed during test execution') for dir in core_dirs: logging.warning('Please verify %s for more info', dir)
def run(self, cleanup=False, install_before=False, install_after=False, collect_crashdumps=True, namespace={}, control=None, control_file_dir=None, only_collect_crashinfo=False): # for a normal job, make sure the uncollected logs file exists # for a crashinfo-only run it should already exist, bail out otherwise created_uncollected_logs = False if self.resultdir and not os.path.exists(self._uncollected_log_file): if only_collect_crashinfo: # if this is a crashinfo-only run, and there were no existing # uncollected logs, just bail out early logging.info("No existing uncollected logs, " "skipping crashinfo collection") return else: log_file = open(self._uncollected_log_file, "w") pickle.dump([], log_file) log_file.close() created_uncollected_logs = True # use a copy so changes don't affect the original dictionary namespace = namespace.copy() machines = self.machines if control is None: if self.control is None: control = '' else: control = self._load_control_file(self.control) if control_file_dir is None: control_file_dir = self.resultdir self.aborted = False namespace['machines'] = machines namespace['args'] = self.args namespace['job'] = self namespace['ssh_user'] = self._ssh_user namespace['ssh_port'] = self._ssh_port namespace['ssh_pass'] = self._ssh_pass test_start_time = int(time.time()) if self.resultdir: os.chdir(self.resultdir) # touch status.log so that the parser knows a job is running here open(self.get_status_log_path(), 'a').close() self.enable_external_logging() collect_crashinfo = True temp_control_file_dir = None try: try: if install_before and machines: self._execute_code(INSTALL_CONTROL_FILE, namespace) if only_collect_crashinfo: return # determine the dir to write the control files to cfd_specified = (control_file_dir and control_file_dir is not self._USE_TEMP_DIR) if cfd_specified: temp_control_file_dir = None else: temp_control_file_dir = tempfile.mkdtemp( suffix='temp_control_file_dir') control_file_dir = temp_control_file_dir server_control_file = os.path.join(control_file_dir, self._control_filename) client_control_file = os.path.join(control_file_dir, CLIENT_CONTROL_FILENAME) if self._client: namespace['control'] = control utils.open_write_close(client_control_file, control) shutil.copyfile(CLIENT_WRAPPER_CONTROL_FILE, server_control_file) else: utils.open_write_close(server_control_file, control) logging.info("Processing control file") self._execute_code(server_control_file, namespace) logging.info("Finished processing control file") # no error occured, so we don't need to collect crashinfo collect_crashinfo = False except Exception, e: try: logging.exception( 'Exception escaped control file, job aborting:') self.record('INFO', None, None, str(e), {'job_abort_reason': str(e)}) except: pass # don't let logging exceptions here interfere raise finally: if temp_control_file_dir: # Clean up temp directory used for copies of the control files try: shutil.rmtree(temp_control_file_dir) except Exception, e: logging.warn('Could not remove temp directory %s: %s', temp_control_file_dir, e) if machines and (collect_crashdumps or collect_crashinfo): namespace['test_start_time'] = test_start_time if collect_crashinfo: # includes crashdumps self._execute_code(CRASHINFO_CONTROL_FILE, namespace) else: self._execute_code(CRASHDUMPS_CONTROL_FILE, namespace) if self._uncollected_log_file and created_uncollected_logs: os.remove(self._uncollected_log_file) self.disable_external_logging() if cleanup and machines: self._execute_code(CLEANUP_CONTROL_FILE, namespace) if install_after and machines: self._execute_code(INSTALL_CONTROL_FILE, namespace)
def request_devs(self, devices=None): """ Implement setup process: unbind the PCI device and then bind it to the device driver. :param devices: List of device dict :type devices: List of dict :return: List of successfully requested devices' PCI IDs. :rtype: List of string """ if not self.pf_vf_info: self.pf_vf_info = self.get_pf_vf_info() base_dir = "/sys/bus/pci" stub_path = os.path.join(base_dir, "drivers/%s" % self.device_driver) self.pci_ids = self.get_devs(devices) logging.info("The following pci_ids were found: %s", self.pci_ids) requested_pci_ids = [] # Setup all devices specified for assignment to guest for p_id in self.pci_ids: if self.device_driver == "vfio-pci": pci_ids = self.get_same_group_devs(p_id) logging.info("Following devices are in same group: %s", pci_ids) else: pci_ids = [p_id] for pci_id in pci_ids: short_id = pci_id[5:] drv_path = os.path.join(base_dir, "devices/%s/driver" % pci_id) dev_prev_driver = os.path.realpath(os.path.join(drv_path, os.readlink(drv_path))) self.dev_drivers[pci_id] = dev_prev_driver # Judge whether the device driver has been binded to stub if not self.is_binded_to_stub(pci_id): error.context("Bind device %s to stub" % pci_id, logging.info) vendor_id = utils_misc.get_vendor_from_pci_id(short_id) stub_new_id = os.path.join(stub_path, 'new_id') unbind_dev = os.path.join(drv_path, 'unbind') stub_bind = os.path.join(stub_path, 'bind') info_write_to_files = [(vendor_id, stub_new_id), (pci_id, unbind_dev), (pci_id, stub_bind)] for content, f_name in info_write_to_files: try: logging.info("Write '%s' to file '%s'", content, f_name) utils.open_write_close(f_name, content) except IOError: logging.debug("Failed to write %s to file %s", content, f_name) continue if not self.is_binded_to_stub(pci_id): logging.error("Binding device %s to stub failed", pci_id) continue else: logging.debug("Device %s already binded to stub", pci_id) requested_pci_ids.append(p_id) return requested_pci_ids