Exemple #1
0
    def test_config_sections_from_home_base_config(self, mock_Cli):
        cli = Mock()
        cli.get_global_args.return_value = {}
        mock_Cli.return_value = cli
        with patch.dict('os.environ', {'HOME': '../data/kiwi_config/ok'}):
            runtime_config = RuntimeConfig(reread=True)

        assert runtime_config.get_xz_options() == ['-a', '-b', 'xxx']
        assert runtime_config.is_obs_public() is True
        assert runtime_config.get_bundle_compression() is True
        assert runtime_config.get_obs_download_server_url() == \
            'http://example.com'
        assert runtime_config.get_obs_api_server_url() == \
            'https://api.example.com'
        assert runtime_config.get_container_compression() is None
        assert runtime_config.get_iso_tool_category() == 'cdrtools'
        assert runtime_config.get_oci_archive_tool() == 'umoci'
        assert runtime_config.get_package_changes() is True
        assert runtime_config.get_disabled_runtime_checks() == [
            'check_dracut_module_for_oem_install_in_package_list',
            'check_container_tool_chain_installed'
        ]
        assert runtime_config.get_obs_api_credentials() == [{
            'user_name':
            'user_credentials'
        }]
class TestRuntimeConfig:
    def setup(self):
        with patch.dict('os.environ', {'HOME': '../data'}):
            self.runtime_config = RuntimeConfig()

        # pretend that none of the runtime config files exist, even if they do
        # (e.g. the system wide config file in /etc/kiwi.yml)
        # => this will give us the defaults
        with patch('os.path.exists', return_value=False):
            self.default_runtime_config = RuntimeConfig()

    @patch('os.path.exists')
    @patch('yaml.safe_load')
    def test_reading_system_wide_config_file(self, mock_yaml, mock_exists):
        exists_call_results = [True, False]

        def os_path_exists(config):
            return exists_call_results.pop()

        mock_exists.side_effect = os_path_exists
        with patch('builtins.open') as m_open:
            self.runtime_config = RuntimeConfig()
            m_open.assert_called_once_with('/etc/kiwi.yml', 'r')

    def test_invalid_yaml_format(self):
        self.runtime_config.config_data = {'xz': None}
        with raises(KiwiRuntimeConfigFormatError):
            self.runtime_config.get_xz_options()

    def test_get_xz_options(self):
        assert self.runtime_config.get_xz_options() == ['-a', '-b', 'xxx']

    def test_is_obs_public(self):
        assert self.runtime_config.is_obs_public() is True

    def test_get_bundle_compression(self):
        assert self.runtime_config.get_bundle_compression() is True

    def test_get_bundle_compression_default(self):
        assert self.default_runtime_config.get_bundle_compression(
            default=True) is True
        assert self.default_runtime_config.get_bundle_compression(
            default=False) is False

    def test_is_obs_public_default(self):
        assert self.default_runtime_config.is_obs_public() is True

    def test_get_obs_download_server_url(self):
        assert self.runtime_config.get_obs_download_server_url() == \
            'http://example.com'

    def test_get_obs_download_server_url_default(self):
        assert self.default_runtime_config.get_obs_download_server_url() == \
            Defaults.get_obs_download_server_url()

    def test_get_container_compression(self):
        assert self.runtime_config.get_container_compression() is None

    def test_get_container_compression_default(self):
        assert self.default_runtime_config.get_container_compression() == 'xz'

    @patch.object(RuntimeConfig, '_get_attribute')
    @patch('kiwi.logger.log.warning')
    def test_get_container_compression_invalid(self, mock_warning,
                                               mock_get_attribute):
        mock_get_attribute.return_value = 'foo'
        assert self.runtime_config.get_container_compression() == 'xz'
        mock_warning.assert_called_once_with(
            'Skipping invalid container compression: foo')

    @patch.object(RuntimeConfig, '_get_attribute')
    def test_get_container_compression_xz(self, mock_get_attribute):
        mock_get_attribute.return_value = 'xz'
        assert self.runtime_config.get_container_compression() == 'xz'

    def test_get_iso_tool_category(self):
        assert self.runtime_config.get_iso_tool_category() == 'cdrtools'

    def test_get_iso_tool_category_default(self):
        assert self.default_runtime_config.get_iso_tool_category() == 'xorriso'

    @patch.object(RuntimeConfig, '_get_attribute')
    @patch('kiwi.logger.log.warning')
    def test_get_iso_tool_category_invalid(self, mock_warning,
                                           mock_get_attribute):
        mock_get_attribute.return_value = 'foo'
        assert self.runtime_config.get_iso_tool_category() == 'xorriso'
        mock_warning.assert_called_once_with(
            'Skipping invalid iso tool category: foo')

    def test_get_oci_archive_tool(self):
        assert self.runtime_config.get_oci_archive_tool() == 'umoci'

    def test_get_oci_archive_tool_default(self):
        assert self.default_runtime_config.get_oci_archive_tool() == 'umoci'

    def test_get_disabled_runtime_checks(self):
        assert self.runtime_config.get_disabled_runtime_checks() == [
            'check_dracut_module_for_oem_install_in_package_list',
            'check_container_tool_chain_installed'
        ]
Exemple #3
0
class CliTask:
    """
    Base class for all task classes, loads the task and provides
    the interface to the command options and the XML description

    Attributes

    * :attr:`should_perform_task_setup`
        Indicates if the task should perform the setup steps
        which covers the following task configurations:
        * setup debug level
        * setup logfile
        * setup color output
    """
    def __init__(self, should_perform_task_setup=True):
        self.cli = Cli()

        # initialize runtime checker
        self.runtime_checker = None

        # initialize runtime configuration
        self.runtime_config = RuntimeConfig()

        # help requested
        self.cli.show_and_exit_on_help_request()

        # load/import task module
        self.task = self.cli.load_command()

        # get command specific args
        self.command_args = self.cli.get_command_args()

        # get global args
        self.global_args = self.cli.get_global_args()

        # initialize generic runtime check dicts
        self.checks_before_command_args = {
            'check_minimal_required_preferences': [],
            'check_efi_mode_for_disk_overlay_correctly_setup': [],
            'check_initrd_selection_required': [],
            'check_boot_description_exists': [],
            'check_consistent_kernel_in_boot_and_system_image': [],
            'check_container_tool_chain_installed': [],
            'check_volume_setup_defines_reserved_labels': [],
            'check_volume_setup_defines_multiple_fullsize_volumes': [],
            'check_volume_setup_has_no_root_definition': [],
            'check_volume_label_used_with_lvm': [],
            'check_xen_uniquely_setup_as_server_or_guest': [],
            'check_mediacheck_installed': [],
            'check_dracut_module_for_live_iso_in_package_list': [],
            'check_dracut_module_for_disk_overlay_in_package_list': [],
            'check_dracut_module_for_disk_oem_in_package_list': [],
            'check_dracut_module_for_oem_install_in_package_list': [],
            'check_architecture_supports_iso_firmware_setup': [],
            'check_appx_naming_conventions_valid': [],
            'check_syslinux_installed_if_isolinux_is_used': [],
            'check_image_type_unique': []
        }
        self.checks_after_command_args = {
            'check_repositories_configured': [],
            'check_image_include_repos_publicly_resolvable': []
        }

        if should_perform_task_setup:
            # set log level
            if self.global_args['--debug']:
                log.setLogLevel(logging.DEBUG)
            else:
                log.setLogLevel(logging.INFO)

            # set log file
            if self.global_args['--logfile']:
                log.set_logfile(self.global_args['--logfile'])

            if self.global_args['--color-output']:
                log.set_color_format()

    def load_xml_description(self, description_directory):
        """
        Load, upgrade, validate XML description

        Attributes

        * :attr:`xml_data`
            instance of XML data toplevel domain (image), stateless data

        * :attr:`config_file`
            used config file path

        * :attr:`xml_state`
            Instance of XMLState, stateful data
        """
        log.info('Loading XML description')
        config_file = description_directory + '/config.xml'
        if not os.path.exists(config_file):
            # alternative config file lookup location
            config_file = description_directory + '/image/config.xml'
        if not os.path.exists(config_file):
            # glob config file search, first match wins
            glob_match = description_directory + '/*.kiwi'
            for kiwi_file in sorted(glob.iglob(glob_match)):
                config_file = kiwi_file
                break

        if not os.path.exists(config_file):
            raise KiwiConfigFileNotFound('no XML description found in %s' %
                                         description_directory)

        self.description = XMLDescription(config_file)
        self.xml_data = self.description.load()
        self.config_file = config_file.replace('//', '/')
        self.xml_state = XMLState(self.xml_data, self.global_args['--profile'],
                                  self.global_args['--type'])

        log.info('--> loaded %s', self.config_file)
        if self.xml_state.build_type:
            log.info('--> Selected build type: %s',
                     self.xml_state.get_build_type_name())
        if self.xml_state.profiles:
            log.info('--> Selected profiles: %s',
                     ','.join(self.xml_state.profiles))

        self.runtime_checker = RuntimeChecker(self.xml_state)

    def quadruple_token(self, option):
        """
        Helper method for commandline options of the form --option a,b,c,d

        Make sure to provide a common result for option values which
        separates the information in a comma separated list of values

        :return: common option value representation
        :rtype: str
        """
        tokens = option.split(',', 3)
        return [
            self._pop_token(tokens) if len(tokens) else None
            for _ in range(0, 4)
        ]

    def sextuple_token(self, option):
        """
        Helper method for commandline options of the form --option a,b,c,d,e,f

        Make sure to provide a common result for option values which
        separates the information in a comma separated list of values

        :return: common option value representation
        :rtype: str
        """
        tokens = option.split(',', 5)
        return [
            self._pop_token(tokens) if len(tokens) else None
            for _ in range(0, 6)
        ]

    def run_checks(self, checks):
        """
        This method runs the given runtime checks excluding the ones disabled
        in the runtime configuration file.

        :param dict checks: A dictionary with the runtime method names as keys
            and their arguments list as the values.
        """
        exclude_list = self.runtime_config.get_disabled_runtime_checks()
        if self.runtime_checker is not None:
            for method, args in {
                    key: value
                    for key, value in checks.items() if key not in exclude_list
            }.items():
                attrgetter(method)(self.runtime_checker)(*args)

    def _pop_token(self, tokens):
        token = tokens.pop(0)
        if len(token) > 0 and token == 'true':
            return True
        elif len(token) > 0 and token == 'false':
            return False
        else:
            return token