diff --git a/hassio/addons/data.py b/hassio/addons/data.py index e4eae0a95..4228c053a 100644 --- a/hassio/addons/data.py +++ b/hassio/addons/data.py @@ -3,18 +3,20 @@ import copy import logging import json from pathlib import Path, PurePath +import re import voluptuous as vol from voluptuous.humanize import humanize_error from .util import extract_hash_from_path from .validate import ( - validate_options, SCHEMA_ADDON_CONFIG, SCHEMA_REPOSITORY_CONFIG) + validate_options, SCHEMA_ADDON_CONFIG, SCHEMA_REPOSITORY_CONFIG, + MAP_VOLUME) from ..const import ( FILE_HASSIO_ADDONS, ATTR_NAME, ATTR_VERSION, ATTR_SLUG, ATTR_DESCRIPTON, ATTR_STARTUP, ATTR_BOOT, ATTR_MAP, ATTR_OPTIONS, ATTR_PORTS, BOOT_AUTO, - ATTR_SCHEMA, ATTR_IMAGE, MAP_CONFIG, MAP_SSL, MAP_ADDONS, MAP_BACKUP, - ATTR_REPOSITORY, ATTR_URL, ATTR_ARCH, ATTR_LOCATON) + ATTR_SCHEMA, ATTR_IMAGE, ATTR_REPOSITORY, ATTR_URL, ATTR_ARCH, + ATTR_LOCATON, ATTR_DEVICES) from ..config import Config from ..tools import read_json_file, write_json_file @@ -26,6 +28,8 @@ USER = 'user' REPOSITORY_CORE = 'core' REPOSITORY_LOCAL = 'local' +RE_VOLUME = re.compile(MAP_VOLUME) + class AddonsData(Config): """Hold data for addons inside HassIO.""" @@ -290,6 +294,10 @@ class AddonsData(Config): """Return ports of addon.""" return self._system_data[addon].get(ATTR_PORTS) + def get_devices(self, addon): + """Return devices of addon.""" + return self._system_data[addon].get(ATTR_DEVICES) + def get_url(self, addon): """Return url of addon.""" if addon in self._addons_cache: @@ -323,21 +331,14 @@ class AddonsData(Config): ) return ATTR_IMAGE not in addon_data - def map_config(self, addon): - """Return True if config map is needed.""" - return MAP_CONFIG in self._system_data[addon][ATTR_MAP] + def map_volumes(self, addon): + """Return a dict of {volume: policy} from addon.""" + volumes = {} + for volume in self._system_data[addon][ATTR_MAP]: + result = RE_VOLUME.match(volume) + volumes[result.group(1)] = result.group(2) or 'ro' - def map_ssl(self, addon): - """Return True if ssl map is needed.""" - return MAP_SSL in self._system_data[addon][ATTR_MAP] - - def map_addons(self, addon): - """Return True if addons map is needed.""" - return MAP_ADDONS in self._system_data[addon][ATTR_MAP] - - def map_backup(self, addon): - """Return True if backup map is needed.""" - return MAP_BACKUP in self._system_data[addon][ATTR_MAP] + return volumes def path_data(self, addon): """Return addon data path inside supervisor.""" diff --git a/hassio/addons/validate.py b/hassio/addons/validate.py index e3dcb40b4..39d8f3c1a 100644 --- a/hassio/addons/validate.py +++ b/hassio/addons/validate.py @@ -4,9 +4,12 @@ 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, BOOT_AUTO, BOOT_MANUAL, ATTR_SCHEMA, ATTR_IMAGE, MAP_SSL, - MAP_CONFIG, MAP_ADDONS, MAP_BACKUP, ATTR_URL, ATTR_MAINTAINER, ATTR_ARCH, - ARCH_ARMHF, ARCH_AARCH64, ARCH_AMD64, ARCH_I386) + STARTUP_BEFORE, BOOT_AUTO, BOOT_MANUAL, ATTR_SCHEMA, ATTR_IMAGE, + ATTR_URL, ATTR_MAINTAINER, ATTR_ARCH, ATTR_DEVICES, ARCH_ARMHF, + ARCH_AARCH64, ARCH_AMD64, ARCH_I386) + + +MAP_VOLUME = r"^(config|ssl|addons|backup)(?::(rw|:ro))?$" V_STR = 'str' V_INT = 'int' @@ -34,9 +37,8 @@ SCHEMA_ADDON_CONFIG = vol.Schema({ vol.Required(ATTR_BOOT): vol.In([BOOT_AUTO, BOOT_MANUAL]), vol.Optional(ATTR_PORTS): dict, - vol.Optional(ATTR_MAP, default=[]): [ - vol.In([MAP_CONFIG, MAP_SSL, MAP_ADDONS, MAP_BACKUP]) - ], + vol.Optional(ATTR_DEVICES): [vol.Match(r"^(.*):(.*):([rwm]{1,3})$")], + vol.Optional(ATTR_MAP, default=[]): [vol.Match(MAP_VOLUME)], vol.Required(ATTR_OPTIONS): dict, vol.Required(ATTR_SCHEMA): { vol.Coerce(str): vol.Any(ADDON_ELEMENT, [ diff --git a/hassio/const.py b/hassio/const.py index d81e5360e..bac023dc2 100644 --- a/hassio/const.py +++ b/hassio/const.py @@ -1,7 +1,7 @@ """Const file for HassIO.""" from pathlib import Path -HASSIO_VERSION = '0.27' +HASSIO_VERSION = '0.28' URL_HASSIO_VERSION = ('https://raw.githubusercontent.com/home-assistant/' 'hassio/master/version.json') @@ -75,6 +75,7 @@ ATTR_INITIALIZE = 'initialize' ATTR_SESSION = 'session' ATTR_LOCATON = 'location' ATTR_BUILD = 'build' +ATTR_DEVICES = 'devices' STARTUP_BEFORE = 'before' STARTUP_AFTER = 'after' diff --git a/hassio/dock/addon.py b/hassio/dock/addon.py index 679b594bf..813890119 100644 --- a/hassio/dock/addon.py +++ b/hassio/dock/addon.py @@ -7,7 +7,7 @@ import docker from . import DockerBase from .util import dockerfile_template -from ..const import META_ADDON +from ..const import META_ADDON, MAP_CONFIG, MAP_SSL, MAP_ADDONS, MAP_BACKUP _LOGGER = logging.getLogger(__name__) @@ -35,28 +35,30 @@ class DockerAddon(DockerBase): 'bind': '/data', 'mode': 'rw' }} - if self.addons_data.map_config(self.addon): + addon_mapping = self.addons_data.map_volumes(self.addon) + + if MAP_CONFIG in addon_mapping: volumes.update({ str(self.config.path_extern_config): { - 'bind': '/config', 'mode': 'rw' + 'bind': '/config', 'mode': addon_mapping[MAP_CONFIG] }}) - if self.addons_data.map_ssl(self.addon): + if MAP_SSL in addon_mapping: volumes.update({ str(self.config.path_extern_ssl): { - 'bind': '/ssl', 'mode': 'rw' + 'bind': '/ssl', 'mode': addon_mapping[MAP_SSL] }}) - if self.addons_data.map_addons(self.addon): + if MAP_ADDONS in addon_mapping: volumes.update({ str(self.config.path_extern_addons_local): { - 'bind': '/addons', 'mode': 'rw' + 'bind': '/addons', 'mode': addon_mapping[MAP_ADDONS] }}) - if self.addons_data.map_backup(self.addon): + if MAP_BACKUP in addon_mapping: volumes.update({ str(self.config.path_extern_backup): { - 'bind': '/backup', 'mode': 'rw' + 'bind': '/backup', 'mode': addon_mapping[MAP_BACKUP] }}) return volumes @@ -79,6 +81,7 @@ class DockerAddon(DockerBase): detach=True, network_mode='bridge', ports=self.addons_data.get_ports(self.addon), + devices=self.addons_data.get_devices(self.addon), volumes=self.volumes, ) diff --git a/version.json b/version.json index 27be93826..45026aae7 100644 --- a/version.json +++ b/version.json @@ -1,5 +1,5 @@ { - "hassio": "0.27", + "hassio": "0.28", "homeassistant": "0.44.2", "resinos": "0.7", "resinhup": "0.1",