mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-10-17 23:59:42 +00:00

* Enable Security API * Update addons.py * Update proxy.py * Update __init__.py * Update security.py * Fix lint
159 lines
5.0 KiB
Python
159 lines
5.0 KiB
Python
"""Init file for Hass.io add-ons."""
|
|
import asyncio
|
|
import logging
|
|
|
|
from .addon import Addon
|
|
from .repository import Repository
|
|
from .data import AddonsData
|
|
from ..const import REPOSITORY_CORE, REPOSITORY_LOCAL, BOOT_AUTO, STATE_STARTED
|
|
from ..coresys import CoreSysAttributes
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
BUILTIN_REPOSITORIES = set((REPOSITORY_CORE, REPOSITORY_LOCAL))
|
|
|
|
|
|
class AddonManager(CoreSysAttributes):
|
|
"""Manage add-ons inside Hass.io."""
|
|
|
|
def __init__(self, coresys):
|
|
"""Initialize Docker base wrapper."""
|
|
self.coresys = coresys
|
|
self.data = AddonsData(coresys)
|
|
self.addons_obj = {}
|
|
self.repositories_obj = {}
|
|
|
|
@property
|
|
def list_addons(self):
|
|
"""Return a list of all add-ons."""
|
|
return list(self.addons_obj.values())
|
|
|
|
@property
|
|
def list_installed(self):
|
|
"""Return a list of installed add-ons."""
|
|
return [addon for addon in self.addons_obj.values()
|
|
if addon.is_installed]
|
|
|
|
@property
|
|
def list_repositories(self):
|
|
"""Return list of add-on repositories."""
|
|
return list(self.repositories_obj.values())
|
|
|
|
def get(self, addon_slug):
|
|
"""Return an add-on from slug."""
|
|
return self.addons_obj.get(addon_slug)
|
|
|
|
def from_token(self, token):
|
|
"""Return an add-on from Hass.io token."""
|
|
for addon in self.list_addons:
|
|
if addon.is_installed and token == addon.hassio_token:
|
|
return addon
|
|
return None
|
|
|
|
async def load(self):
|
|
"""Start up add-on management."""
|
|
self.data.reload()
|
|
|
|
# Init Hass.io built-in repositories
|
|
repositories = \
|
|
set(self.sys_config.addons_repositories) | BUILTIN_REPOSITORIES
|
|
|
|
# Init custom repositories and load add-ons
|
|
await self.load_repositories(repositories)
|
|
|
|
async def reload(self):
|
|
"""Update add-ons from repository and reload list."""
|
|
tasks = [repository.update() for repository in
|
|
self.repositories_obj.values()]
|
|
if tasks:
|
|
await asyncio.wait(tasks)
|
|
|
|
# read data from repositories
|
|
self.data.reload()
|
|
|
|
# update addons
|
|
await self.load_addons()
|
|
|
|
async def load_repositories(self, list_repositories):
|
|
"""Add a new custom repository."""
|
|
new_rep = set(list_repositories)
|
|
old_rep = set(self.repositories_obj)
|
|
|
|
# add new repository
|
|
async def _add_repository(url):
|
|
"""Helper function to async add repository."""
|
|
repository = Repository(self.coresys, url)
|
|
if not await repository.load():
|
|
_LOGGER.error("Can't load from repository %s", url)
|
|
return
|
|
self.repositories_obj[url] = repository
|
|
|
|
# don't add built-in repository to config
|
|
if url not in BUILTIN_REPOSITORIES:
|
|
self.sys_config.add_addon_repository(url)
|
|
|
|
tasks = [_add_repository(url) for url in new_rep - old_rep]
|
|
if tasks:
|
|
await asyncio.wait(tasks)
|
|
|
|
# del new repository
|
|
for url in old_rep - new_rep - BUILTIN_REPOSITORIES:
|
|
self.repositories_obj.pop(url).remove()
|
|
self.sys_config.drop_addon_repository(url)
|
|
|
|
# update data
|
|
self.data.reload()
|
|
await self.load_addons()
|
|
|
|
async def load_addons(self):
|
|
"""Update/add internal add-on store."""
|
|
all_addons = set(self.data.system) | set(self.data.cache)
|
|
|
|
# calc diff
|
|
add_addons = all_addons - set(self.addons_obj)
|
|
del_addons = set(self.addons_obj) - all_addons
|
|
|
|
_LOGGER.info("Load add-ons: %d all - %d new - %d remove",
|
|
len(all_addons), len(add_addons), len(del_addons))
|
|
|
|
# new addons
|
|
tasks = []
|
|
for addon_slug in add_addons:
|
|
addon = Addon(self.coresys, addon_slug)
|
|
|
|
tasks.append(addon.load())
|
|
self.addons_obj[addon_slug] = addon
|
|
|
|
if tasks:
|
|
await asyncio.wait(tasks)
|
|
|
|
# remove
|
|
for addon_slug in del_addons:
|
|
self.addons_obj.pop(addon_slug)
|
|
|
|
async def boot(self, stage):
|
|
"""Boot add-ons with mode auto."""
|
|
tasks = []
|
|
for addon in self.addons_obj.values():
|
|
if addon.is_installed and addon.boot == BOOT_AUTO and \
|
|
addon.startup == stage:
|
|
tasks.append(addon.start())
|
|
|
|
_LOGGER.info("Startup %s run %d add-ons", stage, len(tasks))
|
|
if tasks:
|
|
await asyncio.wait(tasks)
|
|
await asyncio.sleep(self.sys_config.wait_boot)
|
|
|
|
async def shutdown(self, stage):
|
|
"""Shutdown addons."""
|
|
tasks = []
|
|
for addon in self.addons_obj.values():
|
|
if addon.is_installed and \
|
|
await addon.state() == STATE_STARTED and \
|
|
addon.startup == stage:
|
|
tasks.append(addon.stop())
|
|
|
|
_LOGGER.info("Shutdown %s stop %d add-ons", stage, len(tasks))
|
|
if tasks:
|
|
await asyncio.wait(tasks)
|