Add support for addon config.

This commit is contained in:
pvizeli 2017-04-10 11:32:19 +02:00 committed by Pascal Vizeli
parent f127de8059
commit 530f17d502
6 changed files with 131 additions and 15 deletions

View File

@ -1,13 +1,31 @@
"""Init file for HassIO addons."""
import logging
from .config import AddonsConfig
from .git import AddonsRepo
_LOGGER = logging.getLogger(__name__)
class AddonManager(object):
class AddonsManager(object):
"""Manage addons inside HassIO."""
def __init__(self, config, loop):
"""Initialize docker base wrapper."""
self.config = config
self.loop = loop
self.repo = AddonsRepo(config, loop)
self.addons = AddonsConfig(config)
self.dockers = {}
async def prepare(self):
"""Startup addon management."""
# load addon repository
if await self.repo.load():
self.addons.read_addons_repo()
async def relaod_addons(self):
"""Update addons from repo and reload list."""
if not await self.repo.pull():
return
self.addons.read_addons_repo()

62
hassio/addons/config.py Normal file
View File

@ -0,0 +1,62 @@
"""Init file for HassIO addons."""
import logging
import glob
import json
import voluptuous as vol
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)
_LOGGER = logging.getLogger(__name__)
ADDONS_REPO_PATTERN = "{}/*/config.json"
# pylint: disable=no-value-for-parameter
SCHEMA_ADDON_CONFIG = vol.Schema({
vol.Required(ATTR_NAME): vol.Coerce(str),
vol.Required(ATTR_VERSION): vol.Coerce(str),
vol.Required(ATTR_SLUG): vol.Coerce(str),
vol.Required(ATTR_DESCRIPTON): vol.Coerce(str),
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.Required(ATTR_MAP_CONFIG): vol.Boolean(),
vol.Required(ATTR_MAP_SSL): vol.Boolean(),
vol.Required(ATTR_MAP_DATA): vol.Boolean(),
vol.Required(ATTR_OPTIONS): dict,
})
class AddonsConfig(Config):
"""Config for addons inside HassIO."""
def __init__(self, config):
"""Initialize docker base wrapper."""
super().__init__(FILE_HASSIO_ADDONS)
self.config
self._addons_data = {}
def read_addons_repo(self):
"""Read data from addons repository."""
pattern = ADDONS_REPO_PATTERN.format(self.config.path_addons_repo)
for addon in glob.iglob(pattern):
try:
with open(addon, 'r') as cfile:
addon_config = json.loads(cfile.read())
addon_config = SCHEMA_ADDON_CONFIG(addon_config)
self._addons_data[addon_config[ATTR_SLUG]] = addon_config
except (OSError, KeyError):
_LOGGER.warning("Can't read %s", addon)
except vol.Invalid as ex:
_LOGGER.warnign("Can't read %s -> %s.", addon,
humanize_error(addon_config, ex))

View File

@ -20,7 +20,7 @@ class AddonsRepo(object):
self.repo = None
self._lock = asyncio.Lock(loop=loop)
async def init(self):
async def load(self):
"""Init git addon repo."""
if not os.path.isdir(self.config.path_addons_repo):
return await self.clone()
@ -32,6 +32,9 @@ class AddonsRepo(object):
except (git.InvalidGitRepositoryError, git.NoSuchPathError) as err:
_LOGGER.error("Can't load addons repo: %s.", err)
return False
return True
async def clone(self):
"""Clone git addon repo."""
@ -43,12 +46,15 @@ class AddonsRepo(object):
except (git.InvalidGitRepositoryError, git.NoSuchPathError) as err:
_LOGGER.error("Can't clone addons repo: %s.", err)
return False
return True
async def pull(self):
"""Pull git addon repo."""
if self._lock.locked():
_LOGGER.warning("It is already a task in progress.")
return
return False
await with self._lock:
try:
@ -57,3 +63,6 @@ class AddonsRepo(object):
except (git.InvalidGitRepositoryError, git.NoSuchPathError) as err:
_LOGGER.error("Can't pull addons repo: %s.", err)
return False
return True

View File

@ -82,7 +82,7 @@ async def api_validate(schema, request):
"""Validate request data with schema."""
data = await request.json(loads=json_loads)
try:
schema(data)
data = schema(data)
except vol.Invalid as ex:
raise RuntimeError(humanize_error(data, ex)) from None

View File

@ -21,12 +21,11 @@ ADDONS_DATA = "{}/addons_data"
UPSTREAM_BETA = 'upstream_beta'
class CoreConfig(object):
class Config(object):
"""Hold all config data."""
def __init__(self, websession, config_file=FILE_HASSIO_CONFIG):
def __init__(self, config_file):
"""Initialize config object."""
self.websession = websession
self._filename = config_file
self._data = {}
@ -38,14 +37,6 @@ class CoreConfig(object):
except OSError:
_LOGGER.warning("Can't read %s", self._filename)
# init data
if not self._data:
self._data.update({
HOMEASSISTANT_IMAGE: os.environ['HOMEASSISTANT_REPOSITORY'],
UPSTREAM_BETA: False,
})
self.save()
def save(self):
"""Store data to config file."""
try:
@ -57,6 +48,24 @@ class CoreConfig(object):
return True
class CoreConfig(Config):
"""Hold all core config data."""
def __init__(self, websession):
"""Initialize config object."""
self.websession = websession
super().__ini__(FILE_HASSIO_CONFIG)
# init data
if not self._data:
self._data.update({
HOMEASSISTANT_IMAGE: os.environ['HOMEASSISTANT_REPOSITORY'],
UPSTREAM_BETA: False,
})
self.save()
async def fetch_update_infos(self):
"""Read current versions from web."""
current = await fetch_current_versions(

View File

@ -28,3 +28,21 @@ RESULT_OK = 'ok'
ATTR_VERSION = 'version'
ATTR_CURRENT = 'current'
ATTR_BETA = 'beta'
ATTR_NAME = 'name'
ATTR_SLUG = 'slug'
ATTR_DESCRIPTON = 'description'
ATTR_STARTUP = 'startup'
ATTR_BOOT = 'boot'
ATTR_PORTS = 'ports'
ATTR_MAP_CONFIG = 'map_config'
ATTR_MAP_SSL = 'map_ssl'
ATTR_MAP_DATA = 'map_data'
ATTR_OPTIONS = 'options'
ATTR_INSTALLED = 'installed'
STARTUP_BEFORE = 'before'
STARTUP_AFTER = 'after'
STARTUP_ONCE = 'once'
BOOT_START = 'start'
BOOT_STOP = 'stop'
BOOT_MANUAL = 'manual'