From a860a3c122e92d773e9c70b16efb1bdb67289c10 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Tue, 27 Mar 2018 09:24:38 +0200 Subject: [PATCH 01/19] Update Home-Assistant to version 0.66.0.b2 --- version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.json b/version.json index d3be94492..cc096cc11 100644 --- a/version.json +++ b/version.json @@ -1,6 +1,6 @@ { "hassio": "0.99", - "homeassistant": "0.66.0.beta0", + "homeassistant": "0.66.0.b2", "resinos": "1.3", "resinhup": "0.3", "generic": "0.3", From ae7808eb2aa7514d6647ecd34ae678cd2d407b32 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Fri, 30 Mar 2018 10:22:41 +0200 Subject: [PATCH 02/19] Update Home-Assistant to version 0.66.0.b3 --- version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.json b/version.json index cc096cc11..1d0a949a4 100644 --- a/version.json +++ b/version.json @@ -1,6 +1,6 @@ { "hassio": "0.99", - "homeassistant": "0.66.0.b2", + "homeassistant": "0.66.0.b3", "resinos": "1.3", "resinhup": "0.3", "generic": "0.3", From 716389e0c1820f329e66b6f9420a0f59b3c04c1e Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Fri, 30 Mar 2018 15:10:02 +0200 Subject: [PATCH 03/19] Fix tag format --- version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.json b/version.json index 1d0a949a4..49bb8449f 100644 --- a/version.json +++ b/version.json @@ -1,6 +1,6 @@ { "hassio": "0.99", - "homeassistant": "0.66.0.b3", + "homeassistant": "0.66.0b3", "resinos": "1.3", "resinhup": "0.3", "generic": "0.3", From c650f8d1e1c996e7ee21c6bb4c9978f43056e9c2 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Sat, 31 Mar 2018 09:45:15 +0200 Subject: [PATCH 04/19] Update Home-Assistant to version 0.66.0 --- version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.json b/version.json index 49bb8449f..efb1b41d8 100644 --- a/version.json +++ b/version.json @@ -1,6 +1,6 @@ { "hassio": "0.99", - "homeassistant": "0.66.0b3", + "homeassistant": "0.66.0", "resinos": "1.3", "resinhup": "0.3", "generic": "0.3", From db8540d4ab825a20045d1b476ded7b55b6dd294c Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Sun, 1 Apr 2018 11:07:55 +0200 Subject: [PATCH 05/19] Update Home-Assistant to version 0.66.1b0 --- version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.json b/version.json index efb1b41d8..6488d329e 100644 --- a/version.json +++ b/version.json @@ -1,6 +1,6 @@ { "hassio": "0.99", - "homeassistant": "0.66.0", + "homeassistant": "0.66.1b0", "resinos": "1.3", "resinhup": "0.3", "generic": "0.3", From a4e453bf833940e48438aa6544a2db50d8c888a9 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Mon, 2 Apr 2018 09:47:05 +0200 Subject: [PATCH 06/19] Update Home-Assistant to version 0.66.1 --- version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.json b/version.json index 6488d329e..883e377db 100644 --- a/version.json +++ b/version.json @@ -1,6 +1,6 @@ { "hassio": "0.99", - "homeassistant": "0.66.1b0", + "homeassistant": "0.66.1", "resinos": "1.3", "resinhup": "0.3", "generic": "0.3", From 4eb24fcbc51cc51a559d8995a54f2ac341ef7aea Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Fri, 6 Apr 2018 23:19:31 +0200 Subject: [PATCH 07/19] Update Home-Assistant 0.67.0b0 --- version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.json b/version.json index 883e377db..1a6c1f74d 100644 --- a/version.json +++ b/version.json @@ -1,6 +1,6 @@ { "hassio": "0.99", - "homeassistant": "0.66.1", + "homeassistant": "0.67.0b0", "resinos": "1.3", "resinhup": "0.3", "generic": "0.3", From 72279072acbc6d36b5bac383fd5f3e5677abb4ab Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Sat, 7 Apr 2018 00:24:23 +0200 Subject: [PATCH 08/19] Add support for Seccomp/AppArmor profiles --- API.md | 2 ++ hassio/addons/addon.py | 37 ++++++++++++++++++++++++++++++++++++- hassio/addons/validate.py | 5 ++++- hassio/api/addons.py | 4 +++- hassio/const.py | 6 ++++++ hassio/docker/addon.py | 23 +++++++++++++++-------- 6 files changed, 66 insertions(+), 11 deletions(-) diff --git a/API.md b/API.md index 86689a9b4..9a5a38962 100644 --- a/API.md +++ b/API.md @@ -427,6 +427,8 @@ Get all available addons. "host_ipc": "bool", "host_dbus": "bool", "privileged": ["NET_ADMIN", "SYS_ADMIN"], + "seccomp": "disable|default|custom", + "apparmor": "disable|default|custom", "devices": ["/dev/xy"], "auto_uart": "bool", "icon": "bool", diff --git a/hassio/addons/addon.py b/hassio/addons/addon.py index 83cd86d84..f8283f3af 100644 --- a/hassio/addons/addon.py +++ b/hassio/addons/addon.py @@ -23,7 +23,9 @@ from ..const import ( ATTR_STATE, ATTR_TIMEOUT, ATTR_AUTO_UPDATE, ATTR_NETWORK, ATTR_WEBUI, ATTR_HASSIO_API, ATTR_AUDIO, ATTR_AUDIO_OUTPUT, ATTR_AUDIO_INPUT, ATTR_GPIO, ATTR_HOMEASSISTANT_API, ATTR_STDIN, ATTR_LEGACY, ATTR_HOST_IPC, - ATTR_HOST_DBUS, ATTR_AUTO_UART, ATTR_DISCOVERY, ATTR_SERVICES) + ATTR_HOST_DBUS, ATTR_AUTO_UART, ATTR_DISCOVERY, ATTR_SERVICES, + ATTR_SECCOMP, ATTR_APPARMOR, SECURITY_CUSTOM, SECURITY_DISABLE, + SECURITY_DEFAULT) from ..coresys import CoreSysAttributes from ..docker.addon import DockerAddon from ..utils.json import write_json_file, read_json_file @@ -316,6 +318,29 @@ class Addon(CoreSysAttributes): """Return list of privilege.""" return self._mesh.get(ATTR_PRIVILEGED) + @property + def seccomp(self): + """Return True if seccomp is enabled.""" + if not self._mesh.get(ATTR_SECCOMP): + return SECURITY_DISABLE + elif self.path_seccomp.exists(): + return SECURITY_CUSTOM + return SECURITY_DEFAULT + + @property + def apparmor(self): + """Return True if seccomp is enabled.""" + if not self._mesh.get(ATTR_SECCOMP): + return SECURITY_DISABLE + elif self.path_apparmor.exists(): + return SECURITY_CUSTOM + return SECURITY_DEFAULT + + @property + def seccomp_profile(self): + """Return True if it not use the default profile.""" + return Path(self.path_location, f"{ATTR_SECCOMP}.json").exists() + @property def legacy(self): """Return if the add-on don't support hass labels.""" @@ -474,6 +499,16 @@ class Addon(CoreSysAttributes): """Return path to addon changelog.""" return Path(self.path_location, 'CHANGELOG.md') + @property + def path_seccomp(self): + """Return path to custom seccomp profile.""" + return Path(self.path_location, 'seccomp.json') + + @property + def path_apparmor(self): + """Return path to custom AppArmor profile.""" + return Path(self.path_location, 'apparmor') + def save_data(self): """Save data of addon.""" self._addons.data.save_data() diff --git a/hassio/addons/validate.py b/hassio/addons/validate.py index 0094b826f..c5ed81d28 100644 --- a/hassio/addons/validate.py +++ b/hassio/addons/validate.py @@ -17,7 +17,8 @@ from ..const import ( ATTR_AUTO_UPDATE, ATTR_WEBUI, ATTR_AUDIO, ATTR_AUDIO_INPUT, ATTR_HOST_IPC, ATTR_AUDIO_OUTPUT, ATTR_HASSIO_API, ATTR_BUILD_FROM, ATTR_SQUASH, ATTR_ARGS, ATTR_GPIO, ATTR_HOMEASSISTANT_API, ATTR_STDIN, ATTR_LEGACY, - ATTR_HOST_DBUS, ATTR_AUTO_UART, ATTR_SERVICES, ATTR_DISCOVERY) + ATTR_HOST_DBUS, ATTR_AUTO_UART, ATTR_SERVICES, ATTR_DISCOVERY, + ATTR_SECCOMP, ATTR_APPARMOR) from ..validate import NETWORK_PORT, DOCKER_PORTS, ALSA_CHANNEL _LOGGER = logging.getLogger(__name__) @@ -107,6 +108,8 @@ SCHEMA_ADDON_CONFIG = vol.Schema({ vol.Optional(ATTR_MAP, default=list): [vol.Match(RE_VOLUME)], vol.Optional(ATTR_ENVIRONMENT): {vol.Match(r"\w*"): vol.Coerce(str)}, vol.Optional(ATTR_PRIVILEGED): [vol.In(PRIVILEGED_ALL)], + vol.Optional(ATTR_SECCOMP, default=True): vol.Boolean(), + vol.Optional(ATTR_APPARMOR, default=True): vol.Boolean(), vol.Optional(ATTR_AUDIO, default=False): vol.Boolean(), vol.Optional(ATTR_GPIO, default=False): vol.Boolean(), vol.Optional(ATTR_HASSIO_API, default=False): vol.Boolean(), diff --git a/hassio/api/addons.py b/hassio/api/addons.py index b1909cbd3..bb00750e2 100644 --- a/hassio/api/addons.py +++ b/hassio/api/addons.py @@ -17,7 +17,7 @@ from ..const import ( ATTR_CHANGELOG, ATTR_HOST_IPC, ATTR_HOST_DBUS, ATTR_LONG_DESCRIPTION, ATTR_CPU_PERCENT, ATTR_MEMORY_LIMIT, ATTR_MEMORY_USAGE, ATTR_NETWORK_TX, ATTR_NETWORK_RX, ATTR_BLK_READ, ATTR_BLK_WRITE, ATTR_ICON, ATTR_SERVICES, - ATTR_DISCOVERY, + ATTR_DISCOVERY, ATTR_SECCOMP, ATTR_APPARMOR, CONTENT_TYPE_PNG, CONTENT_TYPE_BINARY, CONTENT_TYPE_TEXT) from ..coresys import CoreSysAttributes from ..validate import DOCKER_PORTS @@ -123,6 +123,8 @@ class APIAddons(CoreSysAttributes): ATTR_HOST_IPC: addon.host_ipc, ATTR_HOST_DBUS: addon.host_dbus, ATTR_PRIVILEGED: addon.privileged, + ATTR_SECCOMP: addon.seccomp, + ATTR_APPARMOR: addon.apparmor, ATTR_DEVICES: self._pretty_devices(addon), ATTR_ICON: addon.with_icon, ATTR_LOGO: addon.with_logo, diff --git a/hassio/const.py b/hassio/const.py index b0935e4cf..c7f2b8d5a 100644 --- a/hassio/const.py +++ b/hassio/const.py @@ -159,6 +159,8 @@ ATTR_DISCOVERY = 'discovery' ATTR_PROTECTED = 'protected' ATTR_CRYPTO = 'crypto' ATTR_BRANCH = 'branch' +ATTR_SECCOMP = 'seccomp' +ATTR_APPARMOR = 'apparmor' SERVICE_MQTT = 'mqtt' @@ -202,3 +204,7 @@ SNAPSHOT_FULL = 'full' SNAPSHOT_PARTIAL = 'partial' CRYPTO_AES128 = 'aes128' + +SECURITY_CUSTOM = 'custom' +SECURITY_DEFAULT = 'default' +SECURITY_DISABLE = 'disable' diff --git a/hassio/docker/addon.py b/hassio/docker/addon.py index e60a99202..76a6586de 100644 --- a/hassio/docker/addon.py +++ b/hassio/docker/addon.py @@ -9,7 +9,7 @@ from .interface import DockerInterface from ..addons.build import AddonBuild from ..const import ( MAP_CONFIG, MAP_SSL, MAP_ADDONS, MAP_BACKUP, MAP_SHARE, ENV_TOKEN, - ENV_TIME) + ENV_TIME, SECURITY_CUSTOM, SECURITY_DISABLE) from ..utils import process_lock _LOGGER = logging.getLogger(__name__) @@ -121,14 +121,21 @@ class DockerAddon(DockerInterface): @property def security_opt(self): """Controlling security opt.""" - privileged = self.addon.privileged or [] + security = [] - # Disable AppArmor sinse it make troubles wit SYS_ADMIN - if 'SYS_ADMIN' in privileged: - return [ - "apparmor:unconfined", - ] - return None + # AppArmor + if self.addon.apparmor == SECURITY_DISABLE: + security.append("apparmor:unconfined") + elif self.addon.apparmor == SECURITY_DEFAULT: + security.append(f"apparmor={self.addon.slug}") + + # Seccomp + if self.addon.seccomp == SECURITY_DISABLE: + security.append("seccomp=unconfined") + elif self.addon.seccomp == SECURITY_CUSTOM: + security.append(f"seccomp={self.addon.path_seccomp}") + + return security or None @property def tmpfs(self): From fddd5b8860547a17dce8ff6d19dfd996a832040b Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Sat, 7 Apr 2018 00:32:54 +0200 Subject: [PATCH 09/19] Fix lint --- hassio/docker/addon.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hassio/docker/addon.py b/hassio/docker/addon.py index 76a6586de..a74aa411b 100644 --- a/hassio/docker/addon.py +++ b/hassio/docker/addon.py @@ -126,7 +126,7 @@ class DockerAddon(DockerInterface): # AppArmor if self.addon.apparmor == SECURITY_DISABLE: security.append("apparmor:unconfined") - elif self.addon.apparmor == SECURITY_DEFAULT: + elif self.addon.apparmor == SECURITY_CUSTOM: security.append(f"apparmor={self.addon.slug}") # Seccomp From ee4b28a490f4aefec45f8de926d251b8ad459ad8 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Sun, 8 Apr 2018 22:27:58 +0200 Subject: [PATCH 10/19] Fix's & cleanup --- API.md | 4 ++-- hassio/addons/addon.py | 13 ++++--------- hassio/const.py | 2 +- hassio/docker/addon.py | 6 +++--- 4 files changed, 10 insertions(+), 15 deletions(-) diff --git a/API.md b/API.md index 9a5a38962..aac11806b 100644 --- a/API.md +++ b/API.md @@ -427,8 +427,8 @@ Get all available addons. "host_ipc": "bool", "host_dbus": "bool", "privileged": ["NET_ADMIN", "SYS_ADMIN"], - "seccomp": "disable|default|custom", - "apparmor": "disable|default|custom", + "seccomp": "disable|default|profile", + "apparmor": "disable|default|profile", "devices": ["/dev/xy"], "auto_uart": "bool", "icon": "bool", diff --git a/hassio/addons/addon.py b/hassio/addons/addon.py index f8283f3af..b3d6660d8 100644 --- a/hassio/addons/addon.py +++ b/hassio/addons/addon.py @@ -24,7 +24,7 @@ from ..const import ( ATTR_HASSIO_API, ATTR_AUDIO, ATTR_AUDIO_OUTPUT, ATTR_AUDIO_INPUT, ATTR_GPIO, ATTR_HOMEASSISTANT_API, ATTR_STDIN, ATTR_LEGACY, ATTR_HOST_IPC, ATTR_HOST_DBUS, ATTR_AUTO_UART, ATTR_DISCOVERY, ATTR_SERVICES, - ATTR_SECCOMP, ATTR_APPARMOR, SECURITY_CUSTOM, SECURITY_DISABLE, + ATTR_SECCOMP, ATTR_APPARMOR, SECURITY_PROFILE, SECURITY_DISABLE, SECURITY_DEFAULT) from ..coresys import CoreSysAttributes from ..docker.addon import DockerAddon @@ -324,23 +324,18 @@ class Addon(CoreSysAttributes): if not self._mesh.get(ATTR_SECCOMP): return SECURITY_DISABLE elif self.path_seccomp.exists(): - return SECURITY_CUSTOM + return SECURITY_PROFILE return SECURITY_DEFAULT @property def apparmor(self): """Return True if seccomp is enabled.""" - if not self._mesh.get(ATTR_SECCOMP): + if not self._mesh.get(ATTR_APPARMOR): return SECURITY_DISABLE elif self.path_apparmor.exists(): - return SECURITY_CUSTOM + return SECURITY_PROFILE return SECURITY_DEFAULT - @property - def seccomp_profile(self): - """Return True if it not use the default profile.""" - return Path(self.path_location, f"{ATTR_SECCOMP}.json").exists() - @property def legacy(self): """Return if the add-on don't support hass labels.""" diff --git a/hassio/const.py b/hassio/const.py index c7f2b8d5a..5a953fd9c 100644 --- a/hassio/const.py +++ b/hassio/const.py @@ -205,6 +205,6 @@ SNAPSHOT_PARTIAL = 'partial' CRYPTO_AES128 = 'aes128' -SECURITY_CUSTOM = 'custom' +SECURITY_PROFILE = 'profile' SECURITY_DEFAULT = 'default' SECURITY_DISABLE = 'disable' diff --git a/hassio/docker/addon.py b/hassio/docker/addon.py index a74aa411b..e766be5e0 100644 --- a/hassio/docker/addon.py +++ b/hassio/docker/addon.py @@ -9,7 +9,7 @@ from .interface import DockerInterface from ..addons.build import AddonBuild from ..const import ( MAP_CONFIG, MAP_SSL, MAP_ADDONS, MAP_BACKUP, MAP_SHARE, ENV_TOKEN, - ENV_TIME, SECURITY_CUSTOM, SECURITY_DISABLE) + ENV_TIME, SECURITY_PROFILE, SECURITY_DISABLE) from ..utils import process_lock _LOGGER = logging.getLogger(__name__) @@ -126,13 +126,13 @@ class DockerAddon(DockerInterface): # AppArmor if self.addon.apparmor == SECURITY_DISABLE: security.append("apparmor:unconfined") - elif self.addon.apparmor == SECURITY_CUSTOM: + elif self.addon.apparmor == SECURITY_PROFILE: security.append(f"apparmor={self.addon.slug}") # Seccomp if self.addon.seccomp == SECURITY_DISABLE: security.append("seccomp=unconfined") - elif self.addon.seccomp == SECURITY_CUSTOM: + elif self.addon.seccomp == SECURITY_PROFILE: security.append(f"seccomp={self.addon.path_seccomp}") return security or None From 068442737342027a17ac2aacd6c8f746358c50a6 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Sun, 8 Apr 2018 23:30:42 +0200 Subject: [PATCH 11/19] Bugfix, remove unsupported characters --- hassio/addons/build.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/hassio/addons/build.py b/hassio/addons/build.py index a3dcfb5b3..d98c9597a 100644 --- a/hassio/addons/build.py +++ b/hassio/addons/build.py @@ -55,8 +55,8 @@ class AddonBuild(JsonConfig, CoreSysAttributes): 'io.hass.version': version, 'io.hass.arch': self._arch, 'io.hass.type': META_ADDON, - 'io.hass.name': self.addon.name, - 'io.hass.description': self.addon.description, + 'io.hass.name': self._fix_label('name'), + 'io.hass.description': self._fix_label('description'), }, 'buildargs': { 'BUILD_FROM': self.base_image, @@ -70,3 +70,8 @@ class AddonBuild(JsonConfig, CoreSysAttributes): args['labels']['io.hass.url'] = self.addon.url return args + + def _fix_label(self, label_name): + """Remove characters they are not supported.""" + label = getattr(self.addon, label_name, "") + return label.replace("'", "") From d36c3919d7676d11ce03e4be6f3af6815f4d9ee9 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Mon, 9 Apr 2018 20:01:48 +0200 Subject: [PATCH 12/19] Update docker --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 839793112..359baad77 100644 --- a/setup.py +++ b/setup.py @@ -42,7 +42,7 @@ setup( install_requires=[ 'async_timeout==2.0.0', 'aiohttp==3.0.9', - 'docker==3.1.1', + 'docker==3.2.0', 'colorlog==3.1.2', 'voluptuous==0.11.1', 'gitpython==2.1.8', From 19b5059972638f69254938b54d80bb36cd028c6d Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Mon, 9 Apr 2018 20:23:04 +0200 Subject: [PATCH 13/19] Pump version 1.0 --- hassio/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hassio/const.py b/hassio/const.py index 5a953fd9c..f79af5a17 100644 --- a/hassio/const.py +++ b/hassio/const.py @@ -2,7 +2,7 @@ from pathlib import Path from ipaddress import ip_network -HASSIO_VERSION = '0.99' +HASSIO_VERSION = '1.00' URL_HASSIO_VERSION = ('https://raw.githubusercontent.com/home-assistant/' 'hassio/{}/version.json') From 7036ecbd0afda6da1c1c7c12e200d577f5562e8c Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Mon, 9 Apr 2018 21:01:06 +0200 Subject: [PATCH 14/19] Update aioHttp 3.1.2 & Handling --- hassio/api/__init__.py | 211 +++++++++++++++++++---------------------- setup.py | 4 +- 2 files changed, 100 insertions(+), 115 deletions(-) diff --git a/hassio/api/__init__.py b/hassio/api/__init__.py index 18f742bb1..8493b0154 100644 --- a/hassio/api/__init__.py +++ b/hassio/api/__init__.py @@ -51,178 +51,163 @@ class RestAPI(CoreSysAttributes): api_host = APIHost() api_host.coresys = self.coresys - self.webapp.router.add_get('/host/info', api_host.info) - self.webapp.router.add_get('/host/hardware', api_host.hardware) - self.webapp.router.add_post('/host/reboot', api_host.reboot) - self.webapp.router.add_post('/host/shutdown', api_host.shutdown) - self.webapp.router.add_post('/host/update', api_host.update) - self.webapp.router.add_post('/host/options', api_host.options) - self.webapp.router.add_post('/host/reload', api_host.reload) + self.webapp.add_routes([ + web.get('/host/info', api_host.info), + web.get('/host/hardware', api_host.hardware), + web.post('/host/reboot', api_host.reboot), + web.post('/host/shutdown', api_host.shutdown), + web.post('/host/update', api_host.update), + web.post('/host/options', api_host.options), + web.post('/host/reload', api_host.reload), + ]) def _register_network(self): """Register network function.""" api_net = APINetwork() api_net.coresys = self.coresys - self.webapp.router.add_get('/network/info', api_net.info) - self.webapp.router.add_post('/network/options', api_net.options) + self.webapp.add_routes([ + web.get('/network/info', api_net.info), + web.post('/network/options', api_net.options), + ]) def _register_supervisor(self): """Register supervisor function.""" api_supervisor = APISupervisor() api_supervisor.coresys = self.coresys - self.webapp.router.add_get('/supervisor/ping', api_supervisor.ping) - self.webapp.router.add_get('/supervisor/info', api_supervisor.info) - self.webapp.router.add_get('/supervisor/stats', api_supervisor.stats) - self.webapp.router.add_post( - '/supervisor/update', api_supervisor.update) - self.webapp.router.add_post( - '/supervisor/reload', api_supervisor.reload) - self.webapp.router.add_post( - '/supervisor/options', api_supervisor.options) - self.webapp.router.add_get('/supervisor/logs', api_supervisor.logs) + self.webapp.add_routes([ + web.get('/supervisor/ping', api_supervisor.ping), + web.get('/supervisor/info', api_supervisor.info), + web.get('/supervisor/stats', api_supervisor.stats), + web.post('/supervisor/update', api_supervisor.update), + web.post('/supervisor/reload', api_supervisor.reload), + web.post('/supervisor/options', api_supervisor.options), + + ]) def _register_homeassistant(self): """Register homeassistant function.""" api_hass = APIHomeAssistant() api_hass.coresys = self.coresys - self.webapp.router.add_get('/homeassistant/info', api_hass.info) - self.webapp.router.add_get('/homeassistant/logs', api_hass.logs) - self.webapp.router.add_get('/homeassistant/stats', api_hass.stats) - self.webapp.router.add_post('/homeassistant/options', api_hass.options) - self.webapp.router.add_post('/homeassistant/update', api_hass.update) - self.webapp.router.add_post('/homeassistant/restart', api_hass.restart) - self.webapp.router.add_post('/homeassistant/stop', api_hass.stop) - self.webapp.router.add_post('/homeassistant/start', api_hass.start) - self.webapp.router.add_post('/homeassistant/check', api_hass.check) + self.webapp.add_routes([ + web.get('/homeassistant/info', api_hass.info), + web.get('/homeassistant/logs', api_hass.logs), + web.get('/homeassistant/stats', api_hass.stats), + web.post('/homeassistant/options', api_hass.options), + web.post('/homeassistant/update', api_hass.update), + web.post('/homeassistant/restart', api_hass.restart), + web.post('/homeassistant/stop', api_hass.stop), + web.post('/homeassistant/start', api_hass.start), + web.post('/homeassistant/check', api_hass.check), + ]) def _register_proxy(self): """Register HomeAssistant API Proxy.""" api_proxy = APIProxy() api_proxy.coresys = self.coresys - self.webapp.router.add_get( - '/homeassistant/api/websocket', api_proxy.websocket) - self.webapp.router.add_get( - '/homeassistant/websocket', api_proxy.websocket) - self.webapp.router.add_get( - '/homeassistant/api/stream', api_proxy.stream) - self.webapp.router.add_post( - '/homeassistant/api/{path:.+}', api_proxy.api) - self.webapp.router.add_get( - '/homeassistant/api/{path:.+}', api_proxy.api) - self.webapp.router.add_get( - '/homeassistant/api/', api_proxy.api) + self.webapp.add_routes([ + web.get('/homeassistant/api/websocket', api_proxy.websocket), + web.get('/homeassistant/websocket', api_proxy.websocket), + web.get('/homeassistant/api/stream', api_proxy.stream), + web.post('/homeassistant/api/{path:.+}', api_proxy.api), + web.get('/homeassistant/api/{path:.+}', api_proxy.api), + web.get('/homeassistant/api/', api_proxy.api), + ]) def _register_addons(self): """Register homeassistant function.""" api_addons = APIAddons() api_addons.coresys = self.coresys - self.webapp.router.add_get('/addons', api_addons.list) - self.webapp.router.add_post('/addons/reload', api_addons.reload) - self.webapp.router.add_get('/addons/{addon}/info', api_addons.info) - self.webapp.router.add_post( - '/addons/{addon}/install', api_addons.install) - self.webapp.router.add_post( - '/addons/{addon}/uninstall', api_addons.uninstall) - self.webapp.router.add_post('/addons/{addon}/start', api_addons.start) - self.webapp.router.add_post('/addons/{addon}/stop', api_addons.stop) - self.webapp.router.add_post( - '/addons/{addon}/restart', api_addons.restart) - self.webapp.router.add_post( - '/addons/{addon}/update', api_addons.update) - self.webapp.router.add_post( - '/addons/{addon}/options', api_addons.options) - self.webapp.router.add_post( - '/addons/{addon}/rebuild', api_addons.rebuild) - self.webapp.router.add_get('/addons/{addon}/logs', api_addons.logs) - self.webapp.router.add_get('/addons/{addon}/icon', api_addons.icon) - self.webapp.router.add_get('/addons/{addon}/logo', api_addons.logo) - self.webapp.router.add_get( - '/addons/{addon}/changelog', api_addons.changelog) - self.webapp.router.add_post('/addons/{addon}/stdin', api_addons.stdin) - self.webapp.router.add_get('/addons/{addon}/stats', api_addons.stats) + self.webapp.add_routes([ + web.get('/addons', api_addons.list), + web.post('/addons/reload', api_addons.reload), + web.get('/addons/{addon}/info', api_addons.info), + web.post('/addons/{addon}/install', api_addons.install), + web.post('/addons/{addon}/uninstall', api_addons.uninstall), + web.post('/addons/{addon}/start', api_addons.start), + web.post('/addons/{addon}/stop', api_addons.stop), + web.post('/addons/{addon}/restart', api_addons.restart), + web.post('/addons/{addon}/update', api_addons.update), + web.post('/addons/{addon}/options', api_addons.options), + web.post('/addons/{addon}/rebuild', api_addons.rebuild), + web.get('/addons/{addon}/logs', api_addons.logs), + web.get('/addons/{addon}/icon', api_addons.icon), + web.get('/addons/{addon}/logo', api_addons.logo), + web.get('/addons/{addon}/changelog', api_addons.changelog), + web.post('/addons/{addon}/stdin', api_addons.stdin), + web.get('/addons/{addon}/stats', api_addons.stats), + ]) def _register_snapshots(self): """Register snapshots function.""" api_snapshots = APISnapshots() api_snapshots.coresys = self.coresys - self.webapp.router.add_get('/snapshots', api_snapshots.list) - self.webapp.router.add_post('/snapshots/reload', api_snapshots.reload) - - self.webapp.router.add_post( - '/snapshots/new/full', api_snapshots.snapshot_full) - self.webapp.router.add_post( - '/snapshots/new/partial', api_snapshots.snapshot_partial) - self.webapp.router.add_post( - '/snapshots/new/upload', api_snapshots.upload) - - self.webapp.router.add_get( - '/snapshots/{snapshot}/info', api_snapshots.info) - self.webapp.router.add_post( - '/snapshots/{snapshot}/remove', api_snapshots.remove) - self.webapp.router.add_post( - '/snapshots/{snapshot}/restore/full', api_snapshots.restore_full) - self.webapp.router.add_post( - '/snapshots/{snapshot}/restore/partial', - api_snapshots.restore_partial) - self.webapp.router.add_get( - '/snapshots/{snapshot}/download', - api_snapshots.download) + self.webapp.add_routes([ + web.get('/snapshots', api_snapshots.list), + web.post('/snapshots/reload', api_snapshots.reload), + web.post('/snapshots/new/full', api_snapshots.snapshot_full), + web.post('/snapshots/new/partial', api_snapshots.snapshot_partial), + web.post('/snapshots/new/upload', api_snapshots.upload), + web.get('/snapshots/{snapshot}/info', api_snapshots.info), + web.post('/snapshots/{snapshot}/remove', api_snapshots.remove), + web.post('/snapshots/{snapshot}/restore/full', + api_snapshots.restore_full), + web.post('/snapshots/{snapshot}/restore/partial', + api_snapshots.restore_partial), + web.get('/snapshots/{snapshot}/download', api_snapshots.download), + ]) def _register_services(self): api_services = APIServices() api_services.coresys = self.coresys - self.webapp.router.add_get('/services', api_services.list) - - self.webapp.router.add_get( - '/services/{service}', api_services.get_service) - self.webapp.router.add_post( - '/services/{service}', api_services.set_service) - self.webapp.router.add_delete( - '/services/{service}', api_services.del_service) + self.webapp.add_routes([ + web.get('/services', api_services.list), + web.get('/services/{service}', api_services.get_service), + web.post('/services/{service}', api_services.set_service), + web.delete('/services/{service}', api_services.del_service), + ]) def _register_discovery(self): api_discovery = APIDiscovery() api_discovery.coresys = self.coresys - self.webapp.router.add_get( - '/services/discovery', api_discovery.list) - self.webapp.router.add_get( - '/services/discovery/{uuid}', api_discovery.get_discovery) - self.webapp.router.add_delete( - '/services/discovery/{uuid}', api_discovery.del_discovery) - self.webapp.router.add_post( - '/services/discovery', api_discovery.set_discovery) + self.webapp.add_routes([ + web.get('/services/discovery', api_discovery.list), + web.get('/services/discovery/{uuid}', api_discovery.get_discovery), + web.delete('/services/discovery/{uuid}', + api_discovery.del_discovery), + web.post('/services/discovery', api_discovery.set_discovery), + ]) def _register_panel(self): """Register panel for homeassistant.""" - def create_panel_response(build_type): + def create_response(build_type): """Create a function to generate a response.""" path = Path(__file__).parent.joinpath( f"panel/{build_type}.html") return lambda request: web.FileResponse(path) # This route is for backwards compatibility with HA < 0.58 - self.webapp.router.add_get( - '/panel', create_panel_response('hassio-main-es5')) + self.webapp.add_routes([ + web.get('/panel', create_response('hassio-main-es5'))]) # This route is for backwards compatibility with HA 0.58 - 0.61 - self.webapp.router.add_get( - '/panel_es5', create_panel_response('hassio-main-es5')) - self.webapp.router.add_get( - '/panel_latest', create_panel_response('hassio-main-latest')) + self.webapp.add_routes([ + web.get('/panel_es5', create_response('hassio-main-es5')), + web.get('/panel_latest', create_response('hassio-main-latest')), + ]) # This route is for HA > 0.61 - self.webapp.router.add_get( - '/app-es5/index.html', create_panel_response('index')) - self.webapp.router.add_get( - '/app-es5/hassio-app.html', create_panel_response('hassio-app')) + self.webapp.add_routes([ + web.get('/app-es5/index.html', create_response('index')), + web.get('/app-es5/hassio-app.html', create_response('hassio-app')), + ]) async def start(self): """Run rest api webserver.""" diff --git a/setup.py b/setup.py index 359baad77..3380d639e 100644 --- a/setup.py +++ b/setup.py @@ -40,8 +40,8 @@ setup( ], include_package_data=True, install_requires=[ - 'async_timeout==2.0.0', - 'aiohttp==3.0.9', + 'async_timeout==2.0.1', + 'aiohttp==3.1.2', 'docker==3.2.0', 'colorlog==3.1.2', 'voluptuous==0.11.1', From 92d5b14cf59322ac692463b83cbc83ed02bb904a Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Mon, 9 Apr 2018 22:13:16 +0200 Subject: [PATCH 15/19] Abstract restart logic --- hassio/docker/interface.py | 25 ------------------------- hassio/homeassistant.py | 18 +++++++++--------- 2 files changed, 9 insertions(+), 34 deletions(-) diff --git a/hassio/docker/interface.py b/hassio/docker/interface.py index 69e69052b..f14ddae46 100644 --- a/hassio/docker/interface.py +++ b/hassio/docker/interface.py @@ -264,31 +264,6 @@ class DockerInterface(CoreSysAttributes): except docker.errors.DockerException as err: _LOGGER.warning("Can't grap logs from %s: %s", self.image, err) - @process_lock - def restart(self): - """Restart docker container.""" - return self._loop.run_in_executor(None, self._restart) - - def _restart(self): - """Restart docker container. - - Need run inside executor. - """ - try: - container = self._docker.containers.get(self.name) - except docker.errors.DockerException: - return False - - _LOGGER.info("Restart %s", self.image) - - try: - container.restart(timeout=self.timeout) - except docker.errors.DockerException as err: - _LOGGER.warning("Can't restart %s: %s", self.image, err) - return False - - return True - @process_lock def cleanup(self): """Check if old version exists and cleanup.""" diff --git a/hassio/homeassistant.py b/hassio/homeassistant.py index 57c6af89d..cbbff13f0 100644 --- a/hassio/homeassistant.py +++ b/hassio/homeassistant.py @@ -218,15 +218,17 @@ class HomeAssistant(JsonConfig, CoreSysAttributes): """Start HomeAssistant docker & wait.""" if await self.instance.run(): await self._block_till_run() + return False @process_lock - async def start(self): - """Run HomeAssistant docker.""" - if not await self.instance.run(): - return False + def start(self): + """Run HomeAssistant docker. - return await self._block_till_run() + Return a coroutine. + """ + return self._start() + @process_lock def stop(self): """Stop HomeAssistant docker. @@ -237,10 +239,8 @@ class HomeAssistant(JsonConfig, CoreSysAttributes): @process_lock async def restart(self): """Restart HomeAssistant docker.""" - if not await self.instance.restart(): - return False - - return await self._block_till_run() + await self.instance.stop() + return await self._start() def logs(self): """Get HomeAssistant docker logs. From b692b19a4de5a8a040247fd0894562e4fda8d744 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Mon, 9 Apr 2018 22:50:21 +0200 Subject: [PATCH 16/19] Fix log bug --- hassio/api/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hassio/api/__init__.py b/hassio/api/__init__.py index 8493b0154..c3d878751 100644 --- a/hassio/api/__init__.py +++ b/hassio/api/__init__.py @@ -80,10 +80,10 @@ class RestAPI(CoreSysAttributes): web.get('/supervisor/ping', api_supervisor.ping), web.get('/supervisor/info', api_supervisor.info), web.get('/supervisor/stats', api_supervisor.stats), + web.get('/supervisor/logs', api_supervisor.logs), web.post('/supervisor/update', api_supervisor.update), web.post('/supervisor/reload', api_supervisor.reload), web.post('/supervisor/options', api_supervisor.options), - ]) def _register_homeassistant(self): From 1374f904334bd61789e3e75667593d6a02314afa Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Mon, 9 Apr 2018 22:52:16 +0200 Subject: [PATCH 17/19] cleanup version --- hassio/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hassio/const.py b/hassio/const.py index f79af5a17..f91aa2538 100644 --- a/hassio/const.py +++ b/hassio/const.py @@ -2,7 +2,7 @@ from pathlib import Path from ipaddress import ip_network -HASSIO_VERSION = '1.00' +HASSIO_VERSION = '1.0' URL_HASSIO_VERSION = ('https://raw.githubusercontent.com/home-assistant/' 'hassio/{}/version.json') From f062f31ca2520b67542c8635ac55dca943b3a98f Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Mon, 9 Apr 2018 23:10:12 +0200 Subject: [PATCH 18/19] Fix logic --- hassio/homeassistant.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hassio/homeassistant.py b/hassio/homeassistant.py index cbbff13f0..21916cfdc 100644 --- a/hassio/homeassistant.py +++ b/hassio/homeassistant.py @@ -216,9 +216,9 @@ class HomeAssistant(JsonConfig, CoreSysAttributes): async def _start(self): """Start HomeAssistant docker & wait.""" - if await self.instance.run(): - await self._block_till_run() - return False + if not await self.instance.run(): + return False + return await self._block_till_run() @process_lock def start(self): From dac90d29ddf5e153dc01bc510db324da4cbdb36d Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Mon, 9 Apr 2018 23:39:19 +0200 Subject: [PATCH 19/19] Update Hass.io to version 1.0 --- version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.json b/version.json index 1a6c1f74d..c5d68761b 100644 --- a/version.json +++ b/version.json @@ -1,5 +1,5 @@ { - "hassio": "0.99", + "hassio": "1.0", "homeassistant": "0.67.0b0", "resinos": "1.3", "resinhup": "0.3",