diff --git a/API.md b/API.md index 65ffd3400..7ed976be2 100644 --- a/API.md +++ b/API.md @@ -69,7 +69,15 @@ On success "version": "INSTALL_VERSION", "current": "CURRENT_VERSION", "beta": "true|false", - "addons": {} + "addons": [ + { + "name": "xy bla", + "slug": "xy", + "version": "CURRENT_VERSION", + "installed": "none|INSTALL_VERSION", + "description": "description" + } + ] } ``` diff --git a/hassio/addons/__init__.py b/hassio/addons/__init__.py index 26b58fdb5..b42a39858 100644 --- a/hassio/addons/__init__.py +++ b/hassio/addons/__init__.py @@ -10,10 +10,11 @@ _LOGGER = logging.getLogger(__name__) class AddonsManager(object): """Manage addons inside HassIO.""" - def __init__(self, config, loop): + def __init__(self, config, loop, dock): """Initialize docker base wrapper.""" self.config = config self.loop = loop + self.dock = dock self.repo = AddonsRepo(config, loop) self.addons = AddonsConfig(config) self.dockers = {} diff --git a/hassio/addons/config.py b/hassio/addons/config.py index c4cd1c74f..b48c5864d 100644 --- a/hassio/addons/config.py +++ b/hassio/addons/config.py @@ -9,8 +9,8 @@ from voluptuous.humanize import humanize_error from ..const import ( FILE_HASSIO_ADDONS, ATTR_NAME, ATTR_VERSION, ATTR_SLUG, ATTR_DESCRIPTON, ATTR_STARTUP, ATTR_BOOT, ATTR_MAP_SSL, ATTR_MAP_CONFIG, ATTR_MAP_DATA, - ATTR_OPTIONS, STARTUP_ONCE, STARTUP_AFTER, STARTUP_BEFORE, BOOT_START, - BOOT_STOP, BOOT_MANUAL) + ATTR_OPTIONS, ATTR_PORTS, STARTUP_ONCE, STARTUP_AFTER, STARTUP_BEFORE, + BOOT_AUTO, BOOT_MANUAL) _LOGGER = logging.getLogger(__name__) @@ -25,7 +25,8 @@ SCHEMA_ADDON_CONFIG = vol.Schema({ vol.Required(ATTR_STARTUP): vol.In([STARTUP_BEFORE, STARTUP_AFTER, STARTUP_ONCE]), vol.Required(ATTR_BOOT): - vol.IN([BOOT_START, BOOT_STOP, BOOT_MANUAL]), + vol.IN([BOOT_AUTO, BOOT_MANUAL]), + vol.Optional(ATTR_PORTS): dict, vol.Required(ATTR_MAP_CONFIG): vol.Boolean(), vol.Required(ATTR_MAP_SSL): vol.Boolean(), vol.Required(ATTR_MAP_DATA): vol.Boolean(), diff --git a/hassio/const.py b/hassio/const.py index 99fc13fbb..4d561d958 100644 --- a/hassio/const.py +++ b/hassio/const.py @@ -39,10 +39,10 @@ ATTR_MAP_SSL = 'map_ssl' ATTR_MAP_DATA = 'map_data' ATTR_OPTIONS = 'options' ATTR_INSTALLED = 'installed' +ATTR_STATE = 'state' STARTUP_BEFORE = 'before' STARTUP_AFTER = 'after' STARTUP_ONCE = 'once' -BOOT_START = 'start' -BOOT_STOP = 'stop' +BOOT_STOP = 'auto' BOOT_MANUAL = 'manual' diff --git a/hassio/dock/__init__.py b/hassio/dock/__init__.py index 633a17870..88e2f1c02 100644 --- a/hassio/dock/__init__.py +++ b/hassio/dock/__init__.py @@ -177,6 +177,30 @@ class DockerBase(object): self.container = None + async def remove(self): + """Remove docker container.""" + if self._lock.locked(): + _LOGGER.error("Can't excute remove while a task is in progress") + return False + + async with self._lock: + await self.loop.run_in_executor(None, self._remove) + return True + + def _stop(self): + """Stop/remove and remove docker container. + + Need run inside executor. + """ + if self.container: + self._stop() + + image = "{}:latest".format(self.image) + try: + self.dock.images.remove(image=image, force=True) + except docker.errors.DockerException as err: + _LOGGER.warning("Can't remove image %s -> %s.", image, err) + async def update(self, tag): """Update a docker image. diff --git a/hassio/dock/addon.py b/hassio/dock/addon.py new file mode 100644 index 000000000..97665573b --- /dev/null +++ b/hassio/dock/addon.py @@ -0,0 +1,63 @@ +"""Init file for HassIO addon docker object.""" +import logging + +import docker + +from . import DockerBase +from ..const import ATTR_SLUG, ATTR_PORTS +from ..tools import get_version_from_env + +_LOGGER = logging.getLogger(__name__) + +HASS_DOCKER_NAME = 'homeassistant' + + +class DockerHomeAssistant(DockerBase): + """Docker hassio wrapper for HomeAssistant.""" + + def __init__(self, config, loop, dock, addon_config, image): + """Initialize docker homeassistant wrapper.""" + super().__init__(config, loop, dock, image=image) + self.addon_config + + @property + def docker_name(self): + """Return name of docker container.""" + return "addon_{}".format(self.addon_config[ATTR_SLUG]) + + def _run(self): + """Run docker image. + + Need run inside executor. + """ + if self._is_running(): + return + + # cleanup old container + self._stop() + + try: + self.container = self.dock.containers.run( + self.image, + name=self.docker_name, + detach=True, + network_mode='bridge', + ports=self.addon_config[ATTR_PORTS], + restart_policy={ + "Name": "on-failure", + "MaximumRetryCount": 10, + }, + volumes={ + self.config.path_config_docker: + {'bind': '/config', 'mode': 'rw'}, + self.config.path_ssl_docker: + {'bind': '/ssl', 'mode': 'rw'}, + }) + + self.version = get_version_from_env( + self.container.attrs['Config']['Env']) + except docker.errors.DockerException as err: + _LOGGER.error("Can't run %s -> %s.", self.image, err) + return False + + return True diff --git a/hassio/dock/supervisor.py b/hassio/dock/supervisor.py index c932e9d04..1f61ecbde 100644 --- a/hassio/dock/supervisor.py +++ b/hassio/dock/supervisor.py @@ -27,3 +27,7 @@ class DockerSupervisor(DockerBase): async def update(self, tag): """Update docker image.""" raise RuntimeError("Not support on supervisor docker container!") + + async def remove(self, tag): + """Remove docker image.""" + raise RuntimeError("Not support on supervisor docker container!")