def __init__(self, cloud, cleanup=None, config=None, description=None, distro_name=None, early_exit=None, history_log=None, image_id=None, inject=None, instance_type=None, log_level=None, no_default_test_dirs=None, cloud_config=None, region=None, results_dir=None, running_instance_id=None, test_dirs=None, test_files=None, timeout=None, collect_vm_info=None, ssh_private_key_file=None, ssh_user=None, subnet_id=None, enable_secure_boot=None, enable_uefi=None, log_callback=None, prefix_name=None, retry_count=None): """Initialize base cloud framework class.""" super(IpaCloud, self).__init__() # Get command line values that are not None cmd_line_values = self._get_non_null_values(locals()) ipa_utils.clear_cache() self.cloud = cloud self.host_key_fingerprint = None self.instance_ip = None self.config = config or default_values['config'] log_level = log_level or default_values['log_level'] if log_callback: self.logger = log_callback else: self.logger = logging.getLogger('img_proof') self.logger.setLevel(log_level) self.logger.propagate = False try: self.ipa_config = ipa_utils.get_config_values( self.config, self.cloud, 'img_proof') self.logger.debug('Using img-proof config file: %s' % self.config) except IpaException: self.ipa_config = {} self.logger.debug('img-proof config file not found: %s' % self.config) # Chain map options in order: cmdline -> config -> defaults self.ipa_config = defaultdict( lambda: None, ChainMap(cmd_line_values, self.ipa_config, default_values)) self.description = self.ipa_config['description'] self.cleanup = self.ipa_config['cleanup'] self.distro_name = self.ipa_config['distro_name'] self.early_exit = self.ipa_config['early_exit'] self.image_id = self.ipa_config['image_id'] self.inject = self.ipa_config['inject'] self.instance_type = self.ipa_config['instance_type'] self.test_files = list(self.ipa_config['test_files']) self.timeout = int(self.ipa_config['timeout']) self.history_log = self.ipa_config['history_log'] self.region = self.ipa_config['region'] self.collect_vm_info = self.ipa_config['collect_vm_info'] self.cloud_config = self.ipa_config['cloud_config'] self.running_instance_id = self.ipa_config['running_instance_id'] self.results_dir = os.path.expanduser(self.ipa_config['results_dir']) self.ssh_private_key_file = self.ipa_config['ssh_private_key_file'] self.ssh_user = self.ipa_config['ssh_user'] self.subnet_id = self.ipa_config['subnet_id'] self.enable_secure_boot = self.ipa_config['enable_secure_boot'] self.enable_uefi = self.ipa_config['enable_uefi'] self.no_default_test_dirs = bool( strtobool(str(self.ipa_config['no_default_test_dirs']))) self.prefix_name = self.ipa_config['prefix_name'] self.retry_count = int(self.ipa_config['retry_count']) if self.enable_secure_boot and not self.enable_uefi: self.enable_uefi = True if self.cloud_config: self.cloud_config = os.path.expanduser(self.cloud_config) if self.ssh_private_key_file: self.ssh_private_key_file = os.path.expanduser( self.ssh_private_key_file) if not self.distro_name: raise IpaCloudException('Distro name is required.') else: self.distro_name = self.distro_name.lower() if self.cloud != 'ssh': if not self.image_id and not self.running_instance_id: raise IpaCloudException( 'Image ID or running instance is required.') self.results = { "tests": [], "summary": defaultdict(int, { "duration": 0, "passed": 0, "num_tests": 0 }) } self._parse_test_files(test_dirs, self.no_default_test_dirs)
def test_image(self): """ The entry point for testing an image. Creates new or initiates existing instance. Runs test suite on instance. Collects and returns results in json format. Returns: A tuple with the exit code and results json. """ self._set_distro() if self.cloud == 'ssh': # SSH cloud framework: instance must be running pass elif self.running_instance_id: # Use existing instance self._start_instance_if_stopped() self._set_image_id() # With a running instance default to no cleanup # if a value has not been provided. if self.cleanup is None: self.cleanup = False else: # Launch new instance self.logger.info('Launching new instance') try: self._launch_instance() except Exception as error: with ipa_utils.ignored(Exception): self._cleanup_instance(1) self.logger.error(error) raise if not self.instance_ip: self._set_instance_ip() self.logger.debug('IP of instance: %s' % self.instance_ip) self._set_results_dir() self._update_history() self._log_info() try: # Ensure instance running and SSH connection # can be established prior to testing instance. client = self._get_ssh_client() self.host_key_fingerprint = ipa_utils.get_host_key_fingerprint( client) except IpaSSHException as error: console_log = self.get_console_log() self._cleanup_instance(1) msg = 'Unable to connect to instance: %s' % error self._write_to_log(msg) self._write_to_log(console_log) raise IpaCloudException(msg) except Exception as error: console_log = self.get_console_log() self._cleanup_instance(1) msg = 'Unable to connect to instance: %s' % error self._write_to_log(msg) self._write_to_log(console_log) raise IpaCloudException(msg) if self.inject: self.process_injection_file(self._get_ssh_client()) status = 0 with ipa_utils.ssh_config(self.ssh_user, self.ssh_private_key_file)\ as ssh_config: for item in self.test_files: if item == 'test_hard_reboot' and self.cloud != 'ssh': self.logger.info('Testing hard reboot') start = time.time() result = 1 try: self.hard_reboot_instance() client = self._get_ssh_client() if self.host_key_fingerprint != \ ipa_utils.get_host_key_fingerprint(client): raise Exception('Host key has changed.') result = 0 except IpaSSHException as error: self.logger.error( 'Unable to connect to instance after ' 'hard reboot: %s' % error) break except Exception as error: self.logger.error('Instance failed hard reboot: %s' % error) break finally: duration = time.time() - start self._process_test_results(duration, 'test_hard_reboot', result) status = status or result elif item == 'test_soft_reboot': self.logger.info('Testing soft reboot') start = time.time() result = 1 try: self.distro.reboot(self._get_ssh_client()) client = self._get_ssh_client() if self.host_key_fingerprint != \ ipa_utils.get_host_key_fingerprint(client): raise Exception('Host key has changed.') result = 0 except IpaSSHException as error: self.logger.error( 'Unable to connect to instance after ' 'soft reboot: %s' % error) break except Exception as error: self.logger.error('Instance failed soft reboot: %s' % error) break finally: duration = time.time() - start self._process_test_results(duration, 'test_soft_reboot', result) status = status or result elif item == 'test_update': self.logger.info('Testing update') start = time.time() result = 1 try: out = self.distro.update(self._get_ssh_client()) result = 0 except Exception as error: self.logger.error('Instance failed to update') self.logger.debug(error) else: self._write_to_log(out) finally: duration = time.time() - start self._process_test_results(duration, 'test_update', result) status = status or result elif item == 'test_refresh': self.logger.info('Testing refresh') start = time.time() result = 1 try: out = self.distro.repo_refresh(self._get_ssh_client()) result = 0 except Exception as error: self.logger.error('Instance failed to refresh') self.logger.debug(error) else: self._write_to_log(out) finally: duration = time.time() - start self._process_test_results(duration, 'test_refresh', result) status = status or result elif isinstance(item, str): self.logger.info('Running test {name}'.format(name=item)) with open(self.log_file, 'a') as log_file: with ipa_utils.redirect_output(log_file): # Run tests result = self._run_test(item, ssh_config) status = status or result else: self.logger.error('Invalid test item in list: %s' % item) if status and self.early_exit: break # flag set to collect VM info if self.collect_vm_info: self._collect_vm_info() self._cleanup_instance(status) self._save_results() # Return status and results json return status, self.results