Exemple #1
0
    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)
Exemple #2
0
    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