From 143a358b0c008e749ddb910eda43e383bd1940e2 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Fri, 14 Jul 2017 23:51:24 +0200 Subject: [PATCH] Change startup system / Allow nested dict (#99) * Change startup system / Allow nested dict * fix schema * fix lint --- hassio/addons/validate.py | 67 +++++++++++++++++++++++++++++---------- hassio/const.py | 5 +-- hassio/core.py | 16 ++++++---- 3 files changed, 63 insertions(+), 25 deletions(-) diff --git a/hassio/addons/validate.py b/hassio/addons/validate.py index d71511bec..fac2a5a14 100644 --- a/hassio/addons/validate.py +++ b/hassio/addons/validate.py @@ -3,13 +3,14 @@ import voluptuous as vol from ..const import ( ATTR_NAME, ATTR_VERSION, ATTR_SLUG, ATTR_DESCRIPTON, ATTR_STARTUP, - ATTR_BOOT, ATTR_MAP, ATTR_OPTIONS, ATTR_PORTS, STARTUP_ONCE, STARTUP_AFTER, - STARTUP_BEFORE, STARTUP_INITIALIZE, BOOT_AUTO, BOOT_MANUAL, ATTR_SCHEMA, - ATTR_IMAGE, ATTR_URL, ATTR_MAINTAINER, ATTR_ARCH, ATTR_DEVICES, - ATTR_ENVIRONMENT, ATTR_HOST_NETWORK, ARCH_ARMHF, ARCH_AARCH64, ARCH_AMD64, - ARCH_I386, ATTR_TMPFS, ATTR_PRIVILEGED, ATTR_USER, ATTR_STATE, ATTR_SYSTEM, - STATE_STARTED, STATE_STOPPED, ATTR_LOCATON, ATTR_REPOSITORY, ATTR_TIMEOUT, - ATTR_NETWORK, ATTR_AUTO_UPDATE) + ATTR_BOOT, ATTR_MAP, ATTR_OPTIONS, ATTR_PORTS, STARTUP_ONCE, + STARTUP_SYSTEM, STARTUP_SERVICES, STARTUP_APPLICATION, STARTUP_INITIALIZE, + BOOT_AUTO, BOOT_MANUAL, ATTR_SCHEMA, ATTR_IMAGE, ATTR_URL, ATTR_MAINTAINER, + ATTR_ARCH, ATTR_DEVICES, ATTR_ENVIRONMENT, ATTR_HOST_NETWORK, ARCH_ARMHF, + ARCH_AARCH64, ARCH_AMD64, ARCH_I386, ATTR_TMPFS, ATTR_PRIVILEGED, + ATTR_USER, ATTR_STATE, ATTR_SYSTEM, STATE_STARTED, STATE_STOPPED, + ATTR_LOCATON, ATTR_REPOSITORY, ATTR_TIMEOUT, ATTR_NETWORK, + ATTR_AUTO_UPDATE) from ..validate import NETWORK_PORT, DOCKER_PORTS @@ -29,11 +30,28 @@ ARCH_ALL = [ ARCH_ARMHF, ARCH_AARCH64, ARCH_AMD64, ARCH_I386 ] +STARTUP_ALL = [ + STARTUP_ONCE, STARTUP_INITIALIZE, STARTUP_SYSTEM, STARTUP_SERVICES, + STARTUP_APPLICATION +] + PRIVILEGE_ALL = [ "NET_ADMIN" ] +def _migrate_startup(value): + """Migrate startup schema. + + REMOVE after 0.50- + """ + if value == "before": + return STARTUP_SERVICES + if value == "after": + return STARTUP_APPLICATION + return value + + # pylint: disable=no-value-for-parameter SCHEMA_ADDON_CONFIG = vol.Schema({ vol.Required(ATTR_NAME): vol.Coerce(str), @@ -43,8 +61,7 @@ SCHEMA_ADDON_CONFIG = vol.Schema({ vol.Optional(ATTR_URL): vol.Url(), vol.Optional(ATTR_ARCH, default=ARCH_ALL): [vol.In(ARCH_ALL)], vol.Required(ATTR_STARTUP): - vol.In([STARTUP_BEFORE, STARTUP_AFTER, STARTUP_ONCE, - STARTUP_INITIALIZE]), + vol.All(_migrate_startup, vol.In([STARTUP_ALL])), vol.Required(ATTR_BOOT): vol.In([BOOT_AUTO, BOOT_MANUAL]), vol.Optional(ATTR_PORTS): DOCKER_PORTS, @@ -56,11 +73,11 @@ SCHEMA_ADDON_CONFIG = vol.Schema({ vol.Optional(ATTR_ENVIRONMENT): {vol.Match(r"\w*"): vol.Coerce(str)}, vol.Optional(ATTR_PRIVILEGED): [vol.In(PRIVILEGE_ALL)], vol.Required(ATTR_OPTIONS): dict, - vol.Required(ATTR_SCHEMA): vol.Any({ + vol.Required(ATTR_SCHEMA): vol.Any(vol.Schema({ vol.Coerce(str): vol.Any(ADDON_ELEMENT, [ vol.Any(ADDON_ELEMENT, {vol.Coerce(str): ADDON_ELEMENT}) - ]) - }, False), + ], vol.Schema({vol.Coerce(str): ADDON_ELEMENT})) + }), False), vol.Optional(ATTR_IMAGE): vol.Match(r"\w*/\w*"), vol.Optional(ATTR_TIMEOUT, default=10): vol.All(vol.Coerce(int), vol.Range(min=10, max=120)) @@ -124,8 +141,11 @@ def validate_options(raw_schema): typ = raw_schema[key] try: if isinstance(typ, list): - # nested value - options[key] = _nested_validate(typ[0], value, key) + # nested value list + options[key] = _nested_validate_list(typ[0], value, key) + elif isinstance(typ, dict): + # nested value dict + options[key] = _nested_validate_dict(typ, value, key) else: # normal value options[key] = _single_validate(typ, value, key) @@ -161,13 +181,13 @@ def _single_validate(typ, value, key): elif typ == V_PORT: return NETWORK_PORT(value) - raise vol.Invalid("Fatal error for {} type {}.".format(key, typ)) + raise vol.Invalid("Fatal error for {} type {}".format(key, typ)) except ValueError: raise vol.Invalid( "Type {} error for '{}' on {}.".format(typ, value, key)) from None -def _nested_validate(typ, data_list, key): +def _nested_validate_list(typ, data_list, key): """Validate nested items.""" options = [] @@ -178,7 +198,7 @@ def _nested_validate(typ, data_list, key): for c_key, c_value in element.items(): if c_key not in typ: raise vol.Invalid( - "Unknown nested options {}.".format(c_key)) + "Unknown nested options {}".format(c_key)) c_options[c_key] = _single_validate(typ[c_key], c_value, c_key) options.append(c_options) @@ -187,3 +207,16 @@ def _nested_validate(typ, data_list, key): options.append(_single_validate(typ, element, key)) return options + + +def _nested_validate_dict(typ, data_dict, key): + """Validate nested items.""" + options = {} + + for c_key, c_value in data_dict.items(): + if c_key not in typ: + raise vol.Invalid("Unknow nested dict options {}".format(c_key)) + + options[c_key] = _single_validate(typ[c_key], c_value, c_key) + + return options diff --git a/hassio/const.py b/hassio/const.py index ef3353301..4e401fb84 100644 --- a/hassio/const.py +++ b/hassio/const.py @@ -98,8 +98,9 @@ ATTR_AUTO_UPDATE = 'auto_update' ATTR_CUSTOM = 'custom' STARTUP_INITIALIZE = 'initialize' -STARTUP_BEFORE = 'before' -STARTUP_AFTER = 'after' +STARTUP_SYSTEM = 'system' +STARTUP_SERVICES = 'services' +STARTUP_APPLICATION = 'application' STARTUP_ONCE = 'once' BOOT_AUTO = 'auto' diff --git a/hassio/core.py b/hassio/core.py index 0544b7d76..71f48afb6 100644 --- a/hassio/core.py +++ b/hassio/core.py @@ -11,8 +11,9 @@ from .host_control import HostControl from .const import ( SOCKET_DOCKER, RUN_UPDATE_INFO_TASKS, RUN_RELOAD_ADDONS_TASKS, RUN_UPDATE_SUPERVISOR_TASKS, RUN_WATCHDOG_HOMEASSISTANT, - RUN_CLEANUP_API_SESSIONS, STARTUP_AFTER, STARTUP_BEFORE, - STARTUP_INITIALIZE, RUN_RELOAD_SNAPSHOTS_TASKS, RUN_UPDATE_ADDONS_TASKS) + RUN_CLEANUP_API_SESSIONS, STARTUP_SYSTEM, STARTUP_SERVICES, + STARTUP_APPLICATION, STARTUP_INITIALIZE, RUN_RELOAD_SNAPSHOTS_TASKS, + RUN_UPDATE_ADDONS_TASKS) from .homeassistant import HomeAssistant from .scheduler import Scheduler from .dock.supervisor import DockerSupervisor @@ -133,20 +134,23 @@ class HassIO(object): await self.api.start() _LOGGER.info("Start hassio api on %s", self.config.api_endpoint) + # start addon mark as system + await self.addons.auto_boot(STARTUP_SYSTEM) + try: # HomeAssistant is already running / supervisor have only reboot if await self.homeassistant.is_running(): _LOGGER.info("HassIO reboot detected") return - # start addon mark as before - await self.addons.auto_boot(STARTUP_BEFORE) + # start addon mark as services + await self.addons.auto_boot(STARTUP_SERVICES) # run HomeAssistant await self.homeassistant.run() - # start addon mark as after - await self.addons.auto_boot(STARTUP_AFTER) + # start addon mark as application + await self.addons.auto_boot(STARTUP_APPLICATION) finally: # schedule homeassistant watchdog