diff --git a/API.md b/API.md index d5fb57bcd..2138ff022 100644 --- a/API.md +++ b/API.md @@ -428,11 +428,11 @@ Get all available addons. "name": "xy bla", "slug": "xy", "description": "description", - "arch": ["armhf", "aarch64", "i386", "amd64"], "repository": "core|local|REP_ID", "version": "LAST_VERSION", "installed": "none|INSTALL_VERSION", "detached": "bool", + "available": "bool", "build": "bool", "url": "null|url", "icon": "bool", @@ -463,6 +463,9 @@ Get all available addons. "auto_update": "bool", "url": "null|url of addon", "detached": "bool", + "available": "bool", + "arch": ["armhf", "aarch64", "i386", "amd64"], + "machine": "[raspberrypi2, tinker]", "repository": "12345678|null", "version": "null|VERSION_INSTALLED", "last_version": "LAST_VERSION", diff --git a/hassio/addons/addon.py b/hassio/addons/addon.py index 22299143a..e46a6db0d 100644 --- a/hassio/addons/addon.py +++ b/hassio/addons/addon.py @@ -13,7 +13,8 @@ import voluptuous as vol from voluptuous.humanize import humanize_error from .validate import ( - validate_options, SCHEMA_ADDON_SNAPSHOT, RE_VOLUME, RE_SERVICE) + validate_options, SCHEMA_ADDON_SNAPSHOT, RE_VOLUME, RE_SERVICE, + MACHINE_ALL) from .utils import check_installed, remove_data from ..const import ( ATTR_NAME, ATTR_VERSION, ATTR_SLUG, ATTR_DESCRIPTON, ATTR_BOOT, ATTR_MAP, @@ -27,6 +28,7 @@ from ..const import ( ATTR_HOST_DBUS, ATTR_AUTO_UART, ATTR_DISCOVERY, ATTR_SERVICES, ATTR_APPARMOR, ATTR_DEVICETREE, ATTR_DOCKER_API, ATTR_FULL_ACCESS, ATTR_PROTECTED, ATTR_ACCESS_TOKEN, ATTR_HOST_PID, ATTR_HASSIO_ROLE, + ATTR_MACHINE, SECURITY_PROFILE, SECURITY_DISABLE, SECURITY_DEFAULT) from ..coresys import CoreSysAttributes from ..docker.addon import DockerAddon @@ -82,6 +84,15 @@ class Addon(CoreSysAttributes): """Return True if add-on is detached.""" return self._id not in self._data.cache + @property + def available(self): + """Return True if this add-on is available on this platform.""" + if self.sys_arch not in self.supported_arch: + return False + if self.sys_machine not in self.supported_machine: + return False + return True + @property def version_installed(self): """Return installed version.""" @@ -468,6 +479,11 @@ class Addon(CoreSysAttributes): """Return list of supported arch.""" return self._mesh[ATTR_ARCH] + @property + def supported_machine(self): + """Return list of supported machine.""" + return self._mesh.get(ATTR_MACHINE) or MACHINE_ALL + @property def image(self): """Return image name of add-on.""" @@ -645,7 +661,7 @@ class Addon(CoreSysAttributes): async def install(self): """Install an add-on.""" - if self.sys_arch not in self.supported_arch: + if not self.available: _LOGGER.error( "Add-on %s not supported on %s", self._id, self.sys_arch) return False diff --git a/hassio/addons/validate.py b/hassio/addons/validate.py index 44695309f..8ef12eb26 100644 --- a/hassio/addons/validate.py +++ b/hassio/addons/validate.py @@ -20,6 +20,7 @@ from ..const import ( ATTR_HOST_DBUS, ATTR_AUTO_UART, ATTR_SERVICES, ATTR_DISCOVERY, ATTR_APPARMOR, ATTR_DEVICETREE, ATTR_DOCKER_API, ATTR_PROTECTED, ATTR_FULL_ACCESS, ATTR_ACCESS_TOKEN, ATTR_HOST_PID, ATTR_HASSIO_ROLE, + ATTR_MACHINE, PRIVILEGED_NET_ADMIN, PRIVILEGED_SYS_ADMIN, PRIVILEGED_SYS_RAWIO, PRIVILEGED_IPC_LOCK, PRIVILEGED_SYS_TIME, PRIVILEGED_SYS_NICE, PRIVILEGED_SYS_RESOURCE, PRIVILEGED_SYS_PTRACE, @@ -57,6 +58,12 @@ ARCH_ALL = [ ARCH_ARMHF, ARCH_AARCH64, ARCH_AMD64, ARCH_I386 ] +MACHINE_ALL = [ + 'intel-nuc', 'qemux86', 'qemux86-64', 'qemuarm', 'qemuarm-64', + 'raspberrypi', 'raspberrypi2', 'raspberrypi3', 'raspberrypi3-64', + 'odroid-cu2', 'odroid-xu', +] + STARTUP_ALL = [ STARTUP_ONCE, STARTUP_INITIALIZE, STARTUP_SYSTEM, STARTUP_SERVICES, STARTUP_APPLICATION @@ -105,6 +112,7 @@ SCHEMA_ADDON_CONFIG = vol.Schema({ vol.Required(ATTR_DESCRIPTON): vol.Coerce(str), vol.Optional(ATTR_URL): vol.Url(), vol.Optional(ATTR_ARCH, default=ARCH_ALL): [vol.In(ARCH_ALL)], + vol.Optional(ATTR_MACHINE): [vol.In(MACHINE_ALL)], vol.Required(ATTR_STARTUP): vol.All(_simple_startup, vol.In(STARTUP_ALL)), vol.Required(ATTR_BOOT): diff --git a/hassio/api/addons.py b/hassio/api/addons.py index 65028cd14..947751c26 100644 --- a/hassio/api/addons.py +++ b/hassio/api/addons.py @@ -20,7 +20,7 @@ from ..const import ( ATTR_NETWORK_RX, ATTR_BLK_READ, ATTR_BLK_WRITE, ATTR_ICON, ATTR_SERVICES, ATTR_DISCOVERY, ATTR_APPARMOR, ATTR_DEVICETREE, ATTR_DOCKER_API, ATTR_FULL_ACCESS, ATTR_PROTECTED, ATTR_RATING, ATTR_HOST_PID, - ATTR_HASSIO_ROLE, + ATTR_HASSIO_ROLE, ATTR_MACHINE, ATTR_AVAILABLE, CONTENT_TYPE_PNG, CONTENT_TYPE_BINARY, CONTENT_TYPE_TEXT, REQUEST_FROM) from ..coresys import CoreSysAttributes from ..validate import DOCKER_PORTS, ALSA_DEVICE @@ -85,7 +85,7 @@ class APIAddons(CoreSysAttributes): ATTR_DESCRIPTON: addon.description, ATTR_VERSION: addon.last_version, ATTR_INSTALLED: addon.version_installed, - ATTR_ARCH: addon.supported_arch, + ATTR_AVAILABLE: addon.available, ATTR_DETACHED: addon.is_detached, ATTR_REPOSITORY: addon.repository, ATTR_BUILD: addon.need_build, @@ -134,8 +134,11 @@ class APIAddons(CoreSysAttributes): ATTR_RATING: rating_security(addon), ATTR_BOOT: addon.boot, ATTR_OPTIONS: addon.options, + ATTR_ARCH: addon.supported_arch, + ATTR_MACHINE: addon.supported_machine, ATTR_URL: addon.url, ATTR_DETACHED: addon.is_detached, + ATTR_AVAILABLE: addon.available, ATTR_BUILD: addon.need_build, ATTR_NETWORK: addon.ports, ATTR_HOST_NETWORK: addon.host_network, diff --git a/hassio/api/security.py b/hassio/api/security.py index 90982acaf..1462fb0b5 100644 --- a/hassio/api/security.py +++ b/hassio/api/security.py @@ -33,7 +33,7 @@ NO_SECURITY_CHECK = re.compile( # Can called by every add-on ADDONS_API_BYPASS = re.compile( r"^(?:" - r"|/addons/self/(?!security)[^/]+)?" + r"|/addons/self/(?!security)[^/]+" r"|/version" r")$" ) @@ -58,13 +58,13 @@ ADDONS_ROLE_ACCESS = { r"|/hardware/.+" r"|/hassos/.+" r"|/supervisor/.+" - r"|/addons/.+/(?!security|options).+" - r"|/addons(?:/self/(?!security).+)" + r"|/addons/[^/]+/(?!security|options).+" + r"|/addons(?:/self/(?!security).+)?" r"|/snapshots.*" r")$" ), ROLE_ADMIN: re.compile( - r".+" + r".*" ), } @@ -130,5 +130,5 @@ class SecurityMiddleware(CoreSysAttributes): request[REQUEST_FROM] = request_from return await handler(request) - _LOGGER.warning("Invalid token for access %s", request.path) + _LOGGER.error("Invalid token for access %s", request.path) raise HTTPForbidden() diff --git a/hassio/api/version.py b/hassio/api/version.py index 4757f3119..7e5485dc5 100644 --- a/hassio/api/version.py +++ b/hassio/api/version.py @@ -22,5 +22,5 @@ class APIVersion(CoreSysAttributes): ATTR_HASSOS: self.sys_hassos.version, ATTR_MACHINE: self.sys_machine, ATTR_ARCH: self.sys_arch, - ATTR_CHANNEL: self.sys_channel, + ATTR_CHANNEL: self.sys_updater.channel, }