diff --git a/hassio/addons/__init__.py b/hassio/addons/__init__.py index cf4361260..1d25d8dc9 100644 --- a/hassio/addons/__init__.py +++ b/hassio/addons/__init__.py @@ -1,5 +1,7 @@ """Init file for HassIO addons.""" import logging +import os +import shutil from .config import AddonsConfig from .git import AddonsRepo @@ -26,8 +28,63 @@ class AddonsManager(object): if await self.repo.load(): self.addons.read_addons_repo() + # load installed addons + for addon in self.addons.list_installed: + self.dockers[addon] = DockerAddon( + self.config, self.loop, self.dock, self.addons, addon) + async def relaod_addons(self): """Update addons from repo and reload list.""" if not await self.repo.pull(): return self.addons.read_addons_repo() + + async def install_addon(self, addon, version=None): + """Install a addon.""" + if not self.addons.exists_addon(addon): + _LOGGER.error("Addon %s not exists for install.", addon) + return False + + if self.addons.is_installed(addon): + _LOGGER.error("Addon %s is allready installed.", addon) + return False + + if not os.path.isdir(self.addons.path_data(addon)): + _LOGGER.info("Create Home-Assistant addon data folder %s", + self.addon.path_data(addon)) + os.mkdir(self.addons.path_data(addon)) + + addon_docker = DockerAddon( + self.config, self.loop, self.dock, self.addons, addon) + + version = version or self.addons.get_version(addon) + if not await addon_docker.install(version): + _LOGGER.error("Can't install addon %s version %s.", addon, version) + return False + + self.dockers[addon] = addon_docker + self.addons.set_install_addon(addon, version) + return True + + async def uninstall_addon(self, addon): + """Remove a addon.""" + if self.addons.is_installed(addon): + _LOGGER.error("Addon %s is allready installed.", addon) + return False + + if addon not in self.dockers: + _LOGGER.error("No docker found for addon %s.", addon) + return False + + if not await self.dockers[addon].remove(version): + _LOGGER.error("Can't install addon %s.", addon) + return False + + if os.path.isdir(self.addons.path_data(addon)): + _LOGGER.info("Remove Home-Assistant addon data folder %s", + self.addon.path_data(addon)) + shutil.rmtree(self.addons.path_data(addon)) + + self.dockers.pop(addon) + self.addons.set_uninstall_addon(addon) + return True diff --git a/hassio/addons/config.py b/hassio/addons/config.py index d16102bfd..c90bc9f74 100644 --- a/hassio/addons/config.py +++ b/hassio/addons/config.py @@ -61,12 +61,39 @@ class AddonsConfig(Config): _LOGGER.warnign("Can't read %s -> %s.", addon, humanize_error(addon_config, ex)) + @property + def list_installed(self): + """Return a list of installed addons.""" + return self._data.keys() + + def exists_addon(self, addon): + """Return True if a addon exists.""" + return addon in self._addons_data + + def is_installed(self, addon): + """Return True if a addon is installed.""" + return addon in self._data + + def set_install_addon(self, addon, version): + """Set addon as installed.""" + self._data[addon] = {ATTR_VERSION: version} + self.save() + + def set_uninstall_addon(self, addon, version): + """Set addon as uninstalled.""" + self._data.pop(addon, None) + self.save() + def get_image(self, addon): """Return name of addon docker image.""" return "{}/{}-addon-{}".format( DOCKER_REPO, self.config.hassio_arch, self._addons_data[addon][ATTR_SLUG]) + def get_version(self, addon): + """Return version of addon.""" + return self._addons_data[addon][ATTR_VERSION] + def get_slug(self, addon): """Return slug of addon.""" return self._addons_data[addon][ATTR_SLUG] diff --git a/hassio/bootstrap.py b/hassio/bootstrap.py index d4ce6844e..779b91b0d 100644 --- a/hassio/bootstrap.py +++ b/hassio/bootstrap.py @@ -26,6 +26,12 @@ def initialize_system_data(websession): _LOGGER.info("Create Home-Assistant ssl folder %s", config.path_ssl) os.mkdir(config.path_ssl) + # homeassistant addon data folder + if not os.path.isdir(config.path_addons_data): + _LOGGER.info("Create Home-Assistant addon data folder %s", + config.path_addons_data) + os.mkdir(config.path_addons_data) + return config diff --git a/hassio/dock/__init__.py b/hassio/dock/__init__.py index 88e2f1c02..bfb53df21 100644 --- a/hassio/dock/__init__.py +++ b/hassio/dock/__init__.py @@ -184,11 +184,10 @@ class DockerBase(object): return False async with self._lock: - await self.loop.run_in_executor(None, self._remove) - return True + return await self.loop.run_in_executor(None, self._remove) - def _stop(self): - """Stop/remove and remove docker container. + def _remove(self): + """remove docker container. Need run inside executor. """ @@ -200,6 +199,9 @@ class DockerBase(object): self.dock.images.remove(image=image, force=True) except docker.errors.DockerException as err: _LOGGER.warning("Can't remove image %s -> %s.", image, err) + return False + + return True async def update(self, tag): """Update a docker image.