Update secrets handling (#1289)

* Update secrets handling

* Remove start pre_check

* fix lint

* remove tasker
This commit is contained in:
Pascal Vizeli 2019-09-12 23:16:56 +02:00 committed by GitHub
parent 64fe190119
commit a12567d0a8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 27 additions and 33 deletions

View File

@ -345,11 +345,14 @@ class Addon(AddonModel):
"""Save data of add-on.""" """Save data of add-on."""
self.sys_addons.data.save_data() self.sys_addons.data.save_data()
def write_options(self): async def write_options(self):
"""Return True if add-on options is written to data.""" """Return True if add-on options is written to data."""
schema = self.schema schema = self.schema
options = self.options options = self.options
# Update secrets for validation
await self.sys_secrets.reload()
try: try:
options = schema(options) options = schema(options)
write_json_file(self.path_options, options) write_json_file(self.path_options, options)
@ -467,7 +470,7 @@ class Addon(AddonModel):
self.save_persist() self.save_persist()
# Options # Options
self.write_options() await self.write_options()
# Sound # Sound
if self.with_audio: if self.with_audio:

View File

@ -5,7 +5,6 @@ from typing import Any, Awaitable, Dict, List
from aiohttp import web from aiohttp import web
import voluptuous as vol import voluptuous as vol
from voluptuous.humanize import humanize_error
from ..addons import AnyAddon from ..addons import AnyAddon
from ..docker.stats import DockerStats from ..docker.stats import DockerStats
@ -266,13 +265,16 @@ class APIAddons(CoreSysAttributes):
"""Store user options for add-on.""" """Store user options for add-on."""
addon: AnyAddon = self._extract_addon(request) addon: AnyAddon = self._extract_addon(request)
# Update secrets for validation
await self.sys_secrets.reload()
# Extend schema with add-on specific validation
addon_schema = SCHEMA_OPTIONS.extend( addon_schema = SCHEMA_OPTIONS.extend(
{vol.Optional(ATTR_OPTIONS): vol.Any(None, addon.schema)} {vol.Optional(ATTR_OPTIONS): vol.Any(None, addon.schema)}
) )
body: Dict[str, Any] = await api_validate(
addon_schema, request, origin=[ATTR_OPTIONS]
)
# Validate/Process Body
body = await api_validate(addon_schema, request, origin=[ATTR_OPTIONS])
if ATTR_OPTIONS in body: if ATTR_OPTIONS in body:
addon.options = body[ATTR_OPTIONS] addon.options = body[ATTR_OPTIONS]
if ATTR_BOOT in body: if ATTR_BOOT in body:
@ -336,14 +338,6 @@ class APIAddons(CoreSysAttributes):
def start(self, request: web.Request) -> Awaitable[None]: def start(self, request: web.Request) -> Awaitable[None]:
"""Start add-on.""" """Start add-on."""
addon: AnyAddon = self._extract_addon(request) addon: AnyAddon = self._extract_addon(request)
# check options
options = addon.options
try:
addon.schema(options)
except vol.Invalid as ex:
raise APIError(humanize_error(options, ex)) from None
return asyncio.shield(addon.start()) return asyncio.shield(addon.start())
@api_process @api_process

View File

@ -1,26 +1,26 @@
"""Init file for Hass.io util for RESTful API.""" """Init file for Hass.io util for RESTful API."""
import json import json
import logging import logging
from typing import Optional, List from typing import Any, Dict, List, Optional
from aiohttp import web from aiohttp import web
import voluptuous as vol import voluptuous as vol
from voluptuous.humanize import humanize_error from voluptuous.humanize import humanize_error
from ..const import ( from ..const import (
JSON_RESULT, CONTENT_TYPE_BINARY,
JSON_DATA, JSON_DATA,
JSON_MESSAGE, JSON_MESSAGE,
RESULT_OK, JSON_RESULT,
RESULT_ERROR, RESULT_ERROR,
CONTENT_TYPE_BINARY, RESULT_OK,
) )
from ..exceptions import HassioError, APIError, APIForbidden from ..exceptions import APIError, APIForbidden, HassioError
_LOGGER: logging.Logger = logging.getLogger(__name__) _LOGGER: logging.Logger = logging.getLogger(__name__)
def json_loads(data): def json_loads(data: Any) -> Dict[str, Any]:
"""Extract json from string with support for '' and None.""" """Extract json from string with support for '' and None."""
if not data: if not data:
return {} return {}
@ -78,23 +78,23 @@ def api_process_raw(content):
return wrap_method return wrap_method
def api_return_error(message=None): def api_return_error(message: Optional[str] = None) -> web.Response:
"""Return an API error message.""" """Return an API error message."""
return web.json_response( return web.json_response(
{JSON_RESULT: RESULT_ERROR, JSON_MESSAGE: message}, status=400 {JSON_RESULT: RESULT_ERROR, JSON_MESSAGE: message}, status=400
) )
def api_return_ok(data=None): def api_return_ok(data: Optional[Dict[str, Any]] = None) -> web.Response:
"""Return an API ok answer.""" """Return an API ok answer."""
return web.json_response({JSON_RESULT: RESULT_OK, JSON_DATA: data or {}}) return web.json_response({JSON_RESULT: RESULT_OK, JSON_DATA: data or {}})
async def api_validate( async def api_validate(
schema: vol.Schema, request: web.Request, origin: Optional[List[str]] = None schema: vol.Schema, request: web.Request, origin: Optional[List[str]] = None
): ) -> Dict[str, Any]:
"""Validate request data with schema.""" """Validate request data with schema."""
data = await request.json(loads=json_loads) data: Dict[str, Any] = await request.json(loads=json_loads)
try: try:
data_validated = schema(data) data_validated = schema(data)
except vol.Invalid as ex: except vol.Invalid as ex:

View File

@ -1,11 +1,13 @@
"""Handle Home Assistant secrets to add-ons.""" """Handle Home Assistant secrets to add-ons."""
from typing import Dict from datetime import timedelta
from pathlib import Path
import logging import logging
from pathlib import Path
from typing import Dict
from ruamel.yaml import YAML, YAMLError from ruamel.yaml import YAML, YAMLError
from .coresys import CoreSys, CoreSysAttributes from .coresys import CoreSys, CoreSysAttributes
from .utils import AsyncThrottle
_LOGGER: logging.Logger = logging.getLogger(__name__) _LOGGER: logging.Logger = logging.getLogger(__name__)
@ -38,6 +40,7 @@ class SecretsManager(CoreSysAttributes):
"""Reload secrets.""" """Reload secrets."""
await self._read_secrets() await self._read_secrets()
@AsyncThrottle(timedelta(seconds=60))
async def _read_secrets(self): async def _read_secrets(self):
"""Read secrets.yaml into memory.""" """Read secrets.yaml into memory."""
if not self.path_secrets.exists(): if not self.path_secrets.exists():

View File

@ -16,10 +16,9 @@ RUN_UPDATE_DNS = 30100
RUN_RELOAD_ADDONS = 10800 RUN_RELOAD_ADDONS = 10800
RUN_RELOAD_SNAPSHOTS = 72000 RUN_RELOAD_SNAPSHOTS = 72000
RUN_RELOAD_HOST = 72000 RUN_RELOAD_HOST = 7600
RUN_RELOAD_UPDATER = 7200 RUN_RELOAD_UPDATER = 7200
RUN_RELOAD_INGRESS = 930 RUN_RELOAD_INGRESS = 930
RUN_RELOAD_SECRETS = 940
RUN_WATCHDOG_HOMEASSISTANT_DOCKER = 15 RUN_WATCHDOG_HOMEASSISTANT_DOCKER = 15
RUN_WATCHDOG_HOMEASSISTANT_API = 300 RUN_WATCHDOG_HOMEASSISTANT_API = 300
@ -78,11 +77,6 @@ class Tasks(CoreSysAttributes):
self.sys_ingress.reload, RUN_RELOAD_INGRESS self.sys_ingress.reload, RUN_RELOAD_INGRESS
) )
) )
self.jobs.add(
self.sys_scheduler.register_task(
self.sys_secrets.reload, RUN_RELOAD_SECRETS
)
)
# Watchdog # Watchdog
self.jobs.add( self.jobs.add(