Ejemplo n.º 1
0
async def async_from_config_file(config_path: str,
                                 hass: core.HomeAssistant,
                                 verbose: bool = False,
                                 skip_pip: bool = True,
                                 log_rotate_days: Any = None,
                                 log_file: Any = None,
                                 log_no_color: bool = False)\
        -> Optional[core.HomeAssistant]:
    """Read the configuration file and try to start all the functionality.

    Will add functionality to 'hass' parameter.
    This method is a coroutine.
    """
    # Set config dir to directory holding config file
    config_dir = os.path.abspath(os.path.dirname(config_path))
    hass.config.config_dir = config_dir

    if not is_virtual_env():
        await async_mount_local_lib_path(config_dir)

    async_enable_logging(hass, verbose, log_rotate_days, log_file,
                         log_no_color)

    try:
        config_dict = await hass.async_add_executor_job(
            conf_util.load_yaml_config_file, config_path)
    except HomeAssistantError as err:
        _LOGGER.error("Error loading %s: %s", config_path, err)
        return None
    finally:
        clear_secret_cache()

    return await async_from_config_dict(
        config_dict, hass, enable_log=False, skip_pip=skip_pip)
Ejemplo n.º 2
0
    def setUp(self):
        """Create & load secrets file."""
        config_dir = get_test_config_dir()
        yaml.clear_secret_cache()
        self._yaml_path = os.path.join(config_dir, YAML_CONFIG_FILE)
        self._secret_path = os.path.join(config_dir, yaml.SECRET_YAML)
        self._sub_folder_path = os.path.join(config_dir, "subFolder")
        self._unrelated_path = os.path.join(config_dir, "unrelated")

        load_yaml(
            self._secret_path,
            "http_pw: pwhttp\n"
            "comp1_un: un1\n"
            "comp1_pw: pw1\n"
            "stale_pw: not_used\n"
            "logger: debug\n",
        )
        self._yaml = load_yaml(
            self._yaml_path,
            "http:\n"
            "  api_password: !secret http_pw\n"
            "component:\n"
            "  username: !secret comp1_un\n"
            "  password: !secret comp1_pw\n"
            "",
        )
Ejemplo n.º 3
0
 def test_bad_logger_value(self, mock_error):
     """Ensure logger: debug was removed."""
     yaml.clear_secret_cache()
     load_yaml(self._secret_path, 'logger: info\npw: abc')
     load_yaml(self._yaml_path, 'api_password: !secret pw')
     assert mock_error.call_count == 1, \
         "Expected an error about logger: value"
Ejemplo n.º 4
0
    def setUp(self):  # pylint: disable=invalid-name
        """Create & load secrets file."""
        config_dir = get_test_config_dir()
        yaml.clear_secret_cache()
        self._yaml_path = os.path.join(config_dir,
                                       config_util.YAML_CONFIG_FILE)
        self._secret_path = os.path.join(config_dir, yaml._SECRET_YAML)
        self._sub_folder_path = os.path.join(config_dir, 'subFolder')
        if not os.path.exists(self._sub_folder_path):
            os.makedirs(self._sub_folder_path)
        self._unrelated_path = os.path.join(config_dir, 'unrelated')
        if not os.path.exists(self._unrelated_path):
            os.makedirs(self._unrelated_path)

        load_yaml(self._secret_path,
                  'http_pw: pwhttp\n'
                  'comp1_un: un1\n'
                  'comp1_pw: pw1\n'
                  'stale_pw: not_used\n'
                  'logger: debug\n')
        self._yaml = load_yaml(self._yaml_path,
                               'http:\n'
                               '  api_password: !secret http_pw\n'
                               'component:\n'
                               '  username: !secret comp1_un\n'
                               '  password: !secret comp1_pw\n'
                               '')
Ejemplo n.º 5
0
    def setUp(self):  # pylint: disable=invalid-name
        """Create & load secrets file."""
        config_dir = get_test_config_dir()
        yaml.clear_secret_cache()
        self._yaml_path = os.path.join(config_dir,
                                       config_util.YAML_CONFIG_FILE)
        self._secret_path = os.path.join(config_dir, yaml._SECRET_YAML)
        self._sub_folder_path = os.path.join(config_dir, 'subFolder')
        if not os.path.exists(self._sub_folder_path):
            os.makedirs(self._sub_folder_path)
        self._unrelated_path = os.path.join(config_dir, 'unrelated')
        if not os.path.exists(self._unrelated_path):
            os.makedirs(self._unrelated_path)

        load_yaml(
            self._secret_path, 'http_pw: pwhttp\n'
            'comp1_un: un1\n'
            'comp1_pw: pw1\n'
            'stale_pw: not_used\n'
            'logger: debug\n')
        self._yaml = load_yaml(
            self._yaml_path, 'http:\n'
            '  api_password: !secret http_pw\n'
            'component:\n'
            '  username: !secret comp1_un\n'
            '  password: !secret comp1_pw\n'
            '')
Ejemplo n.º 6
0
def from_config_file(config_path: str,
                     hass: Optional[core.HomeAssistant] = None,
                     verbose: bool = False,
                     skip_pip: bool = True,
                     log_rotate_days: Any = None):
    """Read the configuration file and try to start all the functionality.

    Will add functionality to 'hass' parameter if given,
    instantiates a new Home Assistant object if 'hass' is not given.
    """
    if hass is None:
        hass = core.HomeAssistant()

    # Set config dir to directory holding config file
    config_dir = os.path.abspath(os.path.dirname(config_path))
    hass.config.config_dir = config_dir
    mount_local_lib_path(config_dir)

    enable_logging(hass, verbose, log_rotate_days)

    try:
        config_dict = conf_util.load_yaml_config_file(config_path)
    except HomeAssistantError:
        return None
    finally:
        clear_secret_cache()

    return from_config_dict(config_dict,
                            hass,
                            enable_log=False,
                            skip_pip=skip_pip)
Ejemplo n.º 7
0
def async_from_config_file(config_path: str,
                           hass: core.HomeAssistant,
                           verbose: bool=False,
                           skip_pip: bool=True,
                           log_rotate_days: Any=None):
    """Read the configuration file and try to start all the functionality.

    Will add functionality to 'hass' parameter.
    This method is a coroutine.
    """
    # Set config dir to directory holding config file
    config_dir = os.path.abspath(os.path.dirname(config_path))
    hass.config.config_dir = config_dir
    yield from hass.loop.run_in_executor(
        None, mount_local_lib_path, config_dir)

    async_enable_logging(hass, verbose, log_rotate_days)

    try:
        config_dict = yield from hass.loop.run_in_executor(
            None, conf_util.load_yaml_config_file, config_path)
    except HomeAssistantError as err:
        _LOGGER.error('Error loading %s: %s', config_path, err)
        return None
    finally:
        clear_secret_cache()

    hass = yield from async_from_config_dict(
        config_dict, hass, enable_log=False, skip_pip=skip_pip)
    return hass
Ejemplo n.º 8
0
def from_config_file(
    config_path: str,
    hass: Optional[core.HomeAssistant] = None,
    verbose: bool = False,
    skip_pip: bool = True,
    log_rotate_days: Any = None,
):
    """Read the configuration file and try to start all the functionality.

    Will add functionality to 'hass' parameter if given,
    instantiates a new Home Assistant object if 'hass' is not given.
    """
    if hass is None:
        hass = core.HomeAssistant()

    # Set config dir to directory holding config file
    config_dir = os.path.abspath(os.path.dirname(config_path))
    hass.config.config_dir = config_dir
    mount_local_lib_path(config_dir)

    enable_logging(hass, verbose, log_rotate_days)

    try:
        config_dict = conf_util.load_yaml_config_file(config_path)
    except HomeAssistantError:
        return None
    finally:
        clear_secret_cache()

    return from_config_dict(config_dict, hass, enable_log=False, skip_pip=skip_pip)
Ejemplo n.º 9
0
def async_from_config_file(config_path: str,
                           hass: core.HomeAssistant,
                           verbose: bool = False,
                           skip_pip: bool = True,
                           log_rotate_days: Any = None):
    """Read the configuration file and try to start all the functionality.

    Will add functionality to 'hass' parameter.
    This method is a coroutine.
    """
    # Set config dir to directory holding config file
    config_dir = os.path.abspath(os.path.dirname(config_path))
    hass.config.config_dir = config_dir
    yield from hass.async_add_job(mount_local_lib_path, config_dir)

    async_enable_logging(hass, verbose, log_rotate_days)

    try:
        config_dict = yield from hass.async_add_job(
            conf_util.load_yaml_config_file, config_path)
    except HomeAssistantError as err:
        _LOGGER.error('Error loading %s: %s', config_path, err)
        return None
    finally:
        clear_secret_cache()

    hass = yield from async_from_config_dict(config_dict,
                                             hass,
                                             enable_log=False,
                                             skip_pip=skip_pip)
    return hass
Ejemplo n.º 10
0
 def test_bad_logger_value(self, mock_error):
     """Ensure logger: debug was removed."""
     yaml.clear_secret_cache()
     load_yaml(self._secret_path, 'logger: info\npw: abc')
     load_yaml(self._yaml_path, 'api_password: !secret pw')
     assert mock_error.call_count == 1, \
         "Expected an error about logger: value"
Ejemplo n.º 11
0
async def async_setup_hass(
    *,
    config_dir: str,
    verbose: bool,
    log_rotate_days: int,
    log_file: str,
    log_no_color: bool,
    skip_pip: bool,
    safe_mode: bool,
) -> Optional[core.HomeAssistant]:
    """Set up Home Assistant."""
    hass = core.HomeAssistant()
    hass.config.config_dir = config_dir

    async_enable_logging(hass, verbose, log_rotate_days, log_file, log_no_color)

    hass.config.skip_pip = skip_pip
    if skip_pip:
        _LOGGER.warning(
            "Skipping pip installation of required modules. This may cause issues"
        )

    if not await conf_util.async_ensure_config_exists(hass):
        _LOGGER.error("Error getting configuration path")
        return None

    _LOGGER.info("Config directory: %s", config_dir)

    config_dict = None

    if not safe_mode:
        await hass.async_add_executor_job(conf_util.process_ha_config_upgrade, hass)

        try:
            config_dict = await conf_util.async_hass_config_yaml(hass)
        except HomeAssistantError as err:
            _LOGGER.error(
                "Failed to parse configuration.yaml: %s. Falling back to safe mode",
                err,
            )
        else:
            if not is_virtual_env():
                await async_mount_local_lib_path(config_dir)

            await async_from_config_dict(config_dict, hass)
        finally:
            clear_secret_cache()

    if safe_mode or config_dict is None:
        _LOGGER.info("Starting in safe mode")

        http_conf = (await http.async_get_last_config(hass)) or {}

        await async_from_config_dict(
            {"safe_mode": {}, "http": http_conf}, hass,
        )

    return hass
Ejemplo n.º 12
0
async def async_from_config_file(
    config_path: str,
    hass: core.HomeAssistant,
    verbose: bool = False,
    skip_pip: bool = True,
    log_rotate_days: Any = None,
    log_file: Any = None,
    log_no_color: bool = False,
) -> Optional[core.HomeAssistant]:
    """Read the configuration file and try to start all the functionality.

    Will add functionality to 'hass' parameter.
    This method is a coroutine.
    """
    # Set config dir to directory holding config file
    config_dir = os.path.abspath(os.path.dirname(config_path))
    hass.config.config_dir = config_dir

    if not is_virtual_env():
        await async_mount_local_lib_path(config_dir)

    async_enable_logging(hass, verbose, log_rotate_days, log_file,
                         log_no_color)

    await hass.async_add_executor_job(conf_util.process_ha_config_upgrade,
                                      hass)

    # ais config
    ais_config = str(os.path.dirname(__file__))
    ais_config += "/ais-dom-config/configuration.yaml"

    try:
        config_dict = await hass.async_add_executor_job(
            conf_util.load_yaml_config_file, ais_config)
    except HomeAssistantError as err:
        _LOGGER.error("Error loading %s: %s", ais_config, err)
        return None
    try:
        user_config_dict = await hass.async_add_executor_job(
            conf_util.load_yaml_config_file, config_path)
    except HomeAssistantError as err:
        _LOGGER.error("Error loading %s: %s", config_path, err)
        # return None
    finally:
        clear_secret_cache()

    try:
        import homeassistant.components.ais_dom.ais_utils as ais_utils

        ais_utils.dict_merge(config_dict, user_config_dict)
    except:
        _LOGGER.error("Error loading user customize")

    return await async_from_config_dict(config_dict,
                                        hass,
                                        enable_log=False,
                                        skip_pip=skip_pip)
Ejemplo n.º 13
0
 def tearDown(self):  # pylint: disable=invalid-name
     """Clean up secrets."""
     yaml.clear_secret_cache()
     for path in [self._yaml_path, self._secret_path,
                  os.path.join(self._sub_folder_path, 'sub.yaml'),
                  os.path.join(self._sub_folder_path, yaml._SECRET_YAML),
                  os.path.join(self._unrelated_path, yaml._SECRET_YAML)]:
         if os.path.isfile(path):
             os.remove(path)
Ejemplo n.º 14
0
 def tearDown(self):  # pylint: disable=invalid-name
     """Clean up secrets."""
     yaml.clear_secret_cache()
     for path in [
             self._yaml_path, self._secret_path,
             os.path.join(self._sub_folder_path, 'sub.yaml'),
             os.path.join(self._sub_folder_path, yaml._SECRET_YAML),
             os.path.join(self._unrelated_path, yaml._SECRET_YAML)
     ]:
         if os.path.isfile(path):
             os.remove(path)
Ejemplo n.º 15
0
 def test_secrets_are_not_dict(self):
     """Did secrets handle non-dict file."""
     FILES[self._secret_path] = ('- http_pw: pwhttp\n'
                                 '  comp1_un: un1\n'
                                 '  comp1_pw: pw1\n')
     yaml.clear_secret_cache()
     with pytest.raises(HomeAssistantError):
         load_yaml(
             self._yaml_path, 'http:\n'
             '  api_password: !secret http_pw\n'
             'component:\n'
             '  username: !secret comp1_un\n'
             '  password: !secret comp1_pw\n'
             '')
Ejemplo n.º 16
0
 def test_secrets_are_not_dict(self):
     """Did secrets handle non-dict file."""
     FILES[self._secret_path] = (
               '- http_pw: pwhttp\n'
               '  comp1_un: un1\n'
               '  comp1_pw: pw1\n')
     yaml.clear_secret_cache()
     with pytest.raises(HomeAssistantError):
         load_yaml(self._yaml_path,
                   'http:\n'
                   '  api_password: !secret http_pw\n'
                   'component:\n'
                   '  username: !secret comp1_un\n'
                   '  password: !secret comp1_pw\n'
                   '')
Ejemplo n.º 17
0
    def setUp(self):
        """Create & load secrets file."""
        config_dir = get_test_config_dir()
        yaml.clear_secret_cache()
        self._yaml_path = os.path.join(config_dir, YAML_CONFIG_FILE)
        self._secret_path = os.path.join(config_dir, yaml.SECRET_YAML)
        self._sub_folder_path = os.path.join(config_dir, 'subFolder')
        self._unrelated_path = os.path.join(config_dir, 'unrelated')

        load_yaml(self._secret_path,
                  'http_pw: pwhttp\n'
                  'comp1_un: un1\n'
                  'comp1_pw: pw1\n'
                  'stale_pw: not_used\n'
                  'logger: debug\n')
        self._yaml = load_yaml(self._yaml_path,
                               'http:\n'
                               '  api_password: !secret http_pw\n'
                               'component:\n'
                               '  username: !secret comp1_un\n'
                               '  password: !secret comp1_pw\n'
                               '')
Ejemplo n.º 18
0
 def tearDown(self):  # pylint: disable=invalid-name
     """Clean up secrets."""
     yaml.clear_secret_cache()
     FILES.clear()
Ejemplo n.º 19
0
 def tearDown(self):  # pylint: disable=invalid-name
     """Clean up secrets."""
     yaml.clear_secret_cache()
     FILES.clear()
Ejemplo n.º 20
0
 def tearDown(self):
     """Clean up secrets."""
     yaml.clear_secret_cache()
     FILES.clear()
Ejemplo n.º 21
0
async def async_setup_hass(
    *,
    config_dir: str,
    verbose: bool,
    log_rotate_days: int,
    log_file: str,
    log_no_color: bool,
    skip_pip: bool,
    safe_mode: bool,
) -> Optional[core.HomeAssistant]:
    """Set up Home Assistant."""
    hass = core.HomeAssistant()
    hass.config.config_dir = config_dir

    async_enable_logging(hass, verbose, log_rotate_days, log_file, log_no_color)

    hass.config.skip_pip = skip_pip
    if skip_pip:
        _LOGGER.warning(
            "Skipping pip installation of required modules. This may cause issues"
        )

    if not await conf_util.async_ensure_config_exists(hass):
        _LOGGER.error("Error getting configuration path")
        return None

    _LOGGER.info("Config directory: %s", config_dir)

    config_dict = None
    basic_setup_success = False

    if not safe_mode:
        await hass.async_add_executor_job(conf_util.process_ha_config_upgrade, hass)

        try:
            config_dict = await conf_util.async_hass_config_yaml(hass)
        except HomeAssistantError as err:
            _LOGGER.error(
                "Failed to parse configuration.yaml: %s. Activating safe mode", err,
            )
        else:
            if not is_virtual_env():
                await async_mount_local_lib_path(config_dir)

            basic_setup_success = (
                await async_from_config_dict(config_dict, hass) is not None
            )
        finally:
            clear_secret_cache()

    if config_dict is None:
        safe_mode = True

    elif not basic_setup_success:
        _LOGGER.warning("Unable to set up core integrations. Activating safe mode")
        safe_mode = True

    elif (
        "frontend" in hass.data.get(DATA_SETUP, {})
        and "frontend" not in hass.config.components
    ):
        _LOGGER.warning("Detected that frontend did not load. Activating safe mode")
        # Ask integrations to shut down. It's messy but we can't
        # do a clean stop without knowing what is broken
        hass.async_track_tasks()
        hass.bus.async_fire(EVENT_HOMEASSISTANT_STOP, {})
        with contextlib.suppress(asyncio.TimeoutError):
            async with timeout(10):
                await hass.async_block_till_done()

        safe_mode = True
        hass = core.HomeAssistant()
        hass.config.config_dir = config_dir

    if safe_mode:
        _LOGGER.info("Starting in safe mode")
        hass.config.safe_mode = True

        http_conf = (await http.async_get_last_config(hass)) or {}

        await async_from_config_dict(
            {"safe_mode": {}, "http": http_conf}, hass,
        )

    return hass
Ejemplo n.º 22
0
 def tearDown(self):
     """Clean up secrets."""
     yaml.clear_secret_cache()
     FILES.clear()
Ejemplo n.º 23
0
async def check_ha_config_file(hass):
    """Check if Home Assistant configuration file is valid."""
    config_dir = hass.config.config_dir
    result = HomeAssistantConfig()

    def _pack_error(package, component, config, message):
        """Handle errors from packages: _log_pkg_error."""
        message = "Package {} setup failed. Component {} {}".format(
            package, component, message)
        domain = 'homeassistant.packages.{}.{}'.format(package, component)
        pack_config = core_config[CONF_PACKAGES].get(package, config)
        result.add_error(message, domain, pack_config)

    def _comp_error(ex, domain, config):
        """Handle errors from components: async_log_exception."""
        result.add_error(_format_config_error(ex, domain, config), domain,
                         config)

    # Load configuration.yaml
    try:
        config_path = await hass.async_add_executor_job(
            find_config_file, config_dir)
        if not config_path:
            return result.add_error("File configuration.yaml not found.")
        config = await hass.async_add_executor_job(load_yaml_config_file,
                                                   config_path)
    except HomeAssistantError as err:
        return result.add_error("Error loading {}: {}".format(
            config_path, err))
    finally:
        yaml.clear_secret_cache()

    # Extract and validate core [homeassistant] config
    try:
        core_config = config.pop(CONF_CORE, {})
        core_config = CORE_CONFIG_SCHEMA(core_config)
        result[CONF_CORE] = core_config
    except vol.Invalid as err:
        result.add_error(err, CONF_CORE, core_config)
        core_config = {}

    # Merge packages
    await merge_packages_config(hass, config,
                                core_config.get(CONF_PACKAGES,
                                                {}), _pack_error)
    core_config.pop(CONF_PACKAGES, None)

    # Filter out repeating config sections
    components = set(key.split(' ')[0] for key in config.keys())

    # Process and validate config
    for domain in components:
        try:
            integration = await loader.async_get_integration(hass, domain)
        except loader.IntegrationNotFound:
            result.add_error("Integration not found: {}".format(domain))
            continue

        try:
            component = integration.get_component()
        except ImportError:
            result.add_error("Component not found: {}".format(domain))
            continue

        if (not hass.config.skip_pip and integration.requirements
                and not await requirements.async_process_requirements(
                    hass, integration.domain, integration.requirements)):
            result.add_error("Unable to install all requirements: {}".format(
                ', '.join(integration.requirements)))
            continue

        if hasattr(component, 'CONFIG_SCHEMA'):
            try:
                config = component.CONFIG_SCHEMA(config)
                result[domain] = config[domain]
            except vol.Invalid as ex:
                _comp_error(ex, domain, config)
                continue

        component_platform_schema = getattr(
            component, 'PLATFORM_SCHEMA_BASE',
            getattr(component, 'PLATFORM_SCHEMA', None))

        if component_platform_schema is None:
            continue

        platforms = []
        for p_name, p_config in config_per_platform(config, domain):
            # Validate component specific platform schema
            try:
                p_validated = component_platform_schema(  # type: ignore
                    p_config)
            except vol.Invalid as ex:
                _comp_error(ex, domain, config)
                continue

            # Not all platform components follow same pattern for platforms
            # So if p_name is None we are not going to validate platform
            # (the automation component is one of them)
            if p_name is None:
                platforms.append(p_validated)
                continue

            try:
                p_integration = await loader.async_get_integration(
                    hass, p_name)
            except loader.IntegrationNotFound:
                result.add_error(
                    "Integration {} not found when trying to verify its {} "
                    "platform.".format(p_name, domain))
                continue

            try:
                platform = p_integration.get_platform(domain)
            except ImportError:
                result.add_error("Platform not found: {}.{}".format(
                    domain, p_name))
                continue

            # Validate platform specific schema
            if hasattr(platform, 'PLATFORM_SCHEMA'):
                try:
                    p_validated = platform.PLATFORM_SCHEMA(p_validated)
                except vol.Invalid as ex:
                    _comp_error(ex, '{}.{}'.format(domain, p_name),
                                p_validated)
                    continue

            platforms.append(p_validated)

        # Remove config for current component and add validated config back in.
        for filter_comp in extract_domain_configs(config, domain):
            del config[filter_comp]
        result[domain] = platforms

    return result
Ejemplo n.º 24
0
def check_ha_config_file(hass):
    """Check if Home Assistant configuration file is valid."""
    config_dir = hass.config.config_dir
    result = HomeAssistantConfig()

    def _pack_error(package, component, config, message):
        """Handle errors from packages: _log_pkg_error."""
        message = "Package {} setup failed. Component {} {}".format(
            package, component, message)
        domain = 'homeassistant.packages.{}.{}'.format(package, component)
        pack_config = core_config[CONF_PACKAGES].get(package, config)
        result.add_error(message, domain, pack_config)

    def _comp_error(ex, domain, config):
        """Handle errors from components: async_log_exception."""
        result.add_error(
            _format_config_error(ex, domain, config), domain, config)

    # Load configuration.yaml
    try:
        config_path = find_config_file(config_dir)
        if not config_path:
            return result.add_error("File configuration.yaml not found.")
        config = load_yaml_config_file(config_path)
    except HomeAssistantError as err:
        return result.add_error(
            "Error loading {}: {}".format(config_path, err))
    finally:
        yaml.clear_secret_cache()

    # Extract and validate core [homeassistant] config
    try:
        core_config = config.pop(CONF_CORE, {})
        core_config = CORE_CONFIG_SCHEMA(core_config)
        result[CONF_CORE] = core_config
    except vol.Invalid as err:
        result.add_error(err, CONF_CORE, core_config)
        core_config = {}

    # Merge packages
    merge_packages_config(
        hass, config, core_config.get(CONF_PACKAGES, {}), _pack_error)
    core_config.pop(CONF_PACKAGES, None)

    # Filter out repeating config sections
    components = set(key.split(' ')[0] for key in config.keys())

    # Process and validate config
    for domain in components:
        component = loader.get_component(hass, domain)
        if not component:
            result.add_error("Component not found: {}".format(domain))
            continue

        if hasattr(component, 'CONFIG_SCHEMA'):
            try:
                config = component.CONFIG_SCHEMA(config)
                result[domain] = config[domain]
            except vol.Invalid as ex:
                _comp_error(ex, domain, config)
                continue

        if (not hasattr(component, 'PLATFORM_SCHEMA') and
                not hasattr(component, 'PLATFORM_SCHEMA_BASE')):
            continue

        platforms = []
        for p_name, p_config in config_per_platform(config, domain):
            # Validate component specific platform schema
            try:
                if hasattr(component, 'PLATFORM_SCHEMA_BASE'):
                    p_validated = \
                        component.PLATFORM_SCHEMA_BASE(  # type: ignore
                            p_config)
                else:
                    p_validated = component.PLATFORM_SCHEMA(  # type: ignore
                        p_config)
            except vol.Invalid as ex:
                _comp_error(ex, domain, config)
                continue

            # Not all platform components follow same pattern for platforms
            # So if p_name is None we are not going to validate platform
            # (the automation component is one of them)
            if p_name is None:
                platforms.append(p_validated)
                continue

            platform = loader.get_platform(hass, domain, p_name)

            if platform is None:
                result.add_error(
                    "Platform not found: {}.{}".format(domain, p_name))
                continue

            # Validate platform specific schema
            if hasattr(platform, 'PLATFORM_SCHEMA'):
                try:
                    p_validated = platform.PLATFORM_SCHEMA(p_validated)
                except vol.Invalid as ex:
                    _comp_error(
                        ex, '{}.{}'.format(domain, p_name), p_validated)
                    continue

            platforms.append(p_validated)

        # Remove config for current component and add validated config back in.
        for filter_comp in extract_domain_configs(config, domain):
            del config[filter_comp]
        result[domain] = platforms

    return result
Ejemplo n.º 25
0
def check_ha_config_file(hass):
    """Check if Home Assistant configuration file is valid."""
    config_dir = hass.config.config_dir
    result = HomeAssistantConfig()

    def _pack_error(package, component, config, message):
        """Handle errors from packages: _log_pkg_error."""
        message = "Package {} setup failed. Component {} {}".format(
            package, component, message)
        domain = 'homeassistant.packages.{}.{}'.format(package, component)
        pack_config = core_config[CONF_PACKAGES].get(package, config)
        result.add_error(message, domain, pack_config)

    def _comp_error(ex, domain, config):
        """Handle errors from components: async_log_exception."""
        result.add_error(_format_config_error(ex, domain, config), domain,
                         config)

    # Load configuration.yaml
    try:
        config_path = find_config_file(config_dir)
        if not config_path:
            return result.add_error("File configuration.yaml not found.")
        config = load_yaml_config_file(config_path)
    except HomeAssistantError as err:
        return result.add_error("Error loading {}: {}".format(
            config_path, err))
    finally:
        yaml.clear_secret_cache()

    # Extract and validate core [homeassistant] config
    try:
        core_config = config.pop(CONF_CORE, {})
        core_config = CORE_CONFIG_SCHEMA(core_config)
        result[CONF_CORE] = core_config
    except vol.Invalid as err:
        result.add_error(err, CONF_CORE, core_config)
        core_config = {}

    # Merge packages
    merge_packages_config(hass, config, core_config.get(CONF_PACKAGES, {}),
                          _pack_error)
    del core_config[CONF_PACKAGES]

    # Ensure we have no None values after merge
    for key, value in config.items():
        if not value:
            config[key] = {}

    # Filter out repeating config sections
    components = set(key.split(' ')[0] for key in config.keys())

    # Process and validate config
    for domain in components:
        component = loader.get_component(hass, domain)
        if not component:
            result.add_error("Component not found: {}".format(domain))
            continue

        if hasattr(component, 'CONFIG_SCHEMA'):
            try:
                config = component.CONFIG_SCHEMA(config)
                result[domain] = config[domain]
            except vol.Invalid as ex:
                _comp_error(ex, domain, config)
                continue

        if not hasattr(component, 'PLATFORM_SCHEMA'):
            continue

        platforms = []
        for p_name, p_config in config_per_platform(config, domain):
            # Validate component specific platform schema
            try:
                p_validated = component.PLATFORM_SCHEMA(p_config)
            except vol.Invalid as ex:
                _comp_error(ex, domain, config)
                continue

            # Not all platform components follow same pattern for platforms
            # So if p_name is None we are not going to validate platform
            # (the automation component is one of them)
            if p_name is None:
                platforms.append(p_validated)
                continue

            platform = loader.get_platform(hass, domain, p_name)

            if platform is None:
                result.add_error("Platform not found: {}.{}".format(
                    domain, p_name))
                continue

            # Validate platform specific schema
            if hasattr(platform, 'PLATFORM_SCHEMA'):
                try:
                    p_validated = platform.PLATFORM_SCHEMA(p_validated)
                except vol.Invalid as ex:
                    _comp_error(ex, '{}.{}'.format(domain, p_name),
                                p_validated)
                    continue

            platforms.append(p_validated)

        # Remove config for current component and add validated config back in.
        for filter_comp in extract_domain_configs(config, domain):
            del config[filter_comp]
        result[domain] = platforms

    return result