mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-07-18 14:46:30 +00:00
Merge pull request #94 from pvizeli/extend_hass
Add landingpage / cleanup homeassistant core handling
This commit is contained in:
commit
bcfd76d33c
8
API.md
8
API.md
@ -269,7 +269,9 @@ Optional:
|
||||
{
|
||||
"version": "INSTALL_VERSION",
|
||||
"last_version": "LAST_VERSION",
|
||||
"devices": []
|
||||
"devices": [""],
|
||||
"image": "str",
|
||||
"custom": "bool -> if custom image"
|
||||
}
|
||||
```
|
||||
|
||||
@ -291,9 +293,13 @@ Output the raw docker log
|
||||
```json
|
||||
{
|
||||
"devices": [],
|
||||
"image": "Optional|null",
|
||||
"last_version": "Optional for custom image|null"
|
||||
}
|
||||
```
|
||||
|
||||
Image with `null` and last_version with `null` reset this options.
|
||||
|
||||
### REST API addons
|
||||
|
||||
- POST `/addons/reload`
|
||||
|
@ -15,53 +15,22 @@ from .validate import (
|
||||
from ..const import (
|
||||
FILE_HASSIO_ADDONS, ATTR_VERSION, ATTR_SLUG, ATTR_REPOSITORY, ATTR_LOCATON,
|
||||
REPOSITORY_CORE, REPOSITORY_LOCAL, ATTR_USER, ATTR_SYSTEM)
|
||||
from ..tools import read_json_file, write_json_file
|
||||
from ..tools import JsonConfig, read_json_file
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
RE_VOLUME = re.compile(MAP_VOLUME)
|
||||
|
||||
|
||||
class Data(object):
|
||||
class Data(JsonConfig):
|
||||
"""Hold data for addons inside HassIO."""
|
||||
|
||||
def __init__(self, config):
|
||||
"""Initialize data holder."""
|
||||
self._file = FILE_HASSIO_ADDONS
|
||||
self._data = {}
|
||||
super().__init__(FILE_HASSIO_ADDONS, SCHEMA_ADDON_FILE)
|
||||
self.config = config
|
||||
self._cache = {}
|
||||
self._repositories = {}
|
||||
|
||||
# init or load data
|
||||
if self._file.is_file():
|
||||
try:
|
||||
self._data = read_json_file(self._file)
|
||||
except (OSError, json.JSONDecodeError):
|
||||
_LOGGER.warning("Can't read %s", self._file)
|
||||
self._data = {}
|
||||
|
||||
# validate
|
||||
try:
|
||||
self._data = SCHEMA_ADDON_FILE(self._data)
|
||||
except vol.Invalid as ex:
|
||||
_LOGGER.error("Can't parse addons.json -> %s",
|
||||
humanize_error(self._data, ex))
|
||||
|
||||
def save(self):
|
||||
"""Store data to config file."""
|
||||
# validate
|
||||
try:
|
||||
self._data = SCHEMA_ADDON_FILE(self._data)
|
||||
except vol.Invalid as ex:
|
||||
_LOGGER.error("Can't parse addons data -> %s",
|
||||
humanize_error(self._data, ex))
|
||||
return False
|
||||
|
||||
if not write_json_file(self._file, self._data):
|
||||
_LOGGER.error("Can't store config in %s", self._file)
|
||||
return False
|
||||
return True
|
||||
self._cache = {}
|
||||
|
||||
@property
|
||||
def user(self):
|
||||
|
@ -5,7 +5,8 @@ import logging
|
||||
import voluptuous as vol
|
||||
|
||||
from .util import api_process, api_process_raw, api_validate
|
||||
from ..const import ATTR_VERSION, ATTR_LAST_VERSION, ATTR_DEVICES
|
||||
from ..const import (
|
||||
ATTR_VERSION, ATTR_LAST_VERSION, ATTR_DEVICES, ATTR_IMAGE, ATTR_CUSTOM)
|
||||
from ..validate import HASS_DEVICES
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
@ -13,6 +14,9 @@ _LOGGER = logging.getLogger(__name__)
|
||||
|
||||
SCHEMA_OPTIONS = vol.Schema({
|
||||
vol.Optional(ATTR_DEVICES): HASS_DEVICES,
|
||||
vol.Inclusive(ATTR_IMAGE, 'custom_hass'): vol.Any(None, vol.Coerce(str)),
|
||||
vol.Inclusive(ATTR_LAST_VERSION, 'custom_hass'):
|
||||
vol.Any(None, vol.Coerce(str)),
|
||||
})
|
||||
|
||||
SCHEMA_VERSION = vol.Schema({
|
||||
@ -34,8 +38,10 @@ class APIHomeAssistant(object):
|
||||
"""Return host information."""
|
||||
return {
|
||||
ATTR_VERSION: self.homeassistant.version,
|
||||
ATTR_LAST_VERSION: self.config.last_homeassistant,
|
||||
ATTR_DEVICES: self.config.homeassistant_devices,
|
||||
ATTR_LAST_VERSION: self.homeassistant.last_version,
|
||||
ATTR_IMAGE: self.homeassistant.image,
|
||||
ATTR_DEVICES: self.homeassistant.devices,
|
||||
ATTR_CUSTOM: self.homeassistant.is_custom_image,
|
||||
}
|
||||
|
||||
@api_process
|
||||
@ -44,7 +50,11 @@ class APIHomeAssistant(object):
|
||||
body = await api_validate(SCHEMA_OPTIONS, request)
|
||||
|
||||
if ATTR_DEVICES in body:
|
||||
self.config.homeassistant_devices = body[ATTR_DEVICES]
|
||||
self.homeassistant.devices = body[ATTR_DEVICES]
|
||||
|
||||
if ATTR_IMAGE in body:
|
||||
self.homeassistant.set_custom(
|
||||
body[ATTR_IMAGE], body[ATTR_LAST_VERSION])
|
||||
|
||||
return True
|
||||
|
||||
@ -57,9 +67,6 @@ class APIHomeAssistant(object):
|
||||
if self.homeassistant.in_progress:
|
||||
raise RuntimeError("Other task is in progress")
|
||||
|
||||
if version == self.homeassistant.version:
|
||||
raise RuntimeError("Version is already in use")
|
||||
|
||||
return await asyncio.shield(
|
||||
self.homeassistant.update(version), loop=self.loop)
|
||||
|
||||
|
@ -1,17 +1,13 @@
|
||||
"""Bootstrap HassIO."""
|
||||
from datetime import datetime
|
||||
import logging
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path, PurePath
|
||||
|
||||
import voluptuous as vol
|
||||
from voluptuous.humanize import humanize_error
|
||||
|
||||
from .const import FILE_HASSIO_CONFIG, HASSIO_DATA
|
||||
from .tools import (
|
||||
fetch_last_versions, write_json_file, read_json_file, validate_timezone)
|
||||
from .validate import HASS_DEVICES
|
||||
from .tools import fetch_last_versions, JsonConfig, validate_timezone
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@ -19,7 +15,6 @@ DATETIME_FORMAT = "%Y%m%d %H:%M:%S"
|
||||
|
||||
HOMEASSISTANT_CONFIG = PurePath("homeassistant")
|
||||
HOMEASSISTANT_LAST = 'homeassistant_last'
|
||||
HOMEASSISTANT_DEVICES = 'homeassistant_devices'
|
||||
|
||||
HASSIO_SSL = PurePath("ssl")
|
||||
HASSIO_LAST = 'hassio_last'
|
||||
@ -50,7 +45,6 @@ SCHEMA_CONFIG = vol.Schema({
|
||||
vol.Optional(API_ENDPOINT): vol.Coerce(str),
|
||||
vol.Optional(TIMEZONE, default='UTC'): validate_timezone,
|
||||
vol.Optional(HOMEASSISTANT_LAST): vol.Coerce(str),
|
||||
vol.Optional(HOMEASSISTANT_DEVICES, default=[]): HASS_DEVICES,
|
||||
vol.Optional(HASSIO_LAST): vol.Coerce(str),
|
||||
vol.Optional(ADDONS_CUSTOM_LIST, default=[]): [vol.Url()],
|
||||
vol.Optional(SECURITY_INITIALIZE, default=False): vol.Boolean(),
|
||||
@ -61,48 +55,13 @@ SCHEMA_CONFIG = vol.Schema({
|
||||
}, extra=vol.REMOVE_EXTRA)
|
||||
|
||||
|
||||
class CoreConfig(object):
|
||||
class CoreConfig(JsonConfig):
|
||||
"""Hold all core config data."""
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize config object."""
|
||||
super().__init__(FILE_HASSIO_CONFIG, SCHEMA_CONFIG)
|
||||
self.arch = None
|
||||
self._file = FILE_HASSIO_CONFIG
|
||||
self._data = {}
|
||||
|
||||
# init or load data
|
||||
if self._file.is_file():
|
||||
try:
|
||||
self._data = read_json_file(self._file)
|
||||
except (OSError, json.JSONDecodeError):
|
||||
_LOGGER.warning("Can't read %s", self._file)
|
||||
self._data = {}
|
||||
|
||||
# validate data
|
||||
if not self._validate_config():
|
||||
self._data = SCHEMA_CONFIG({})
|
||||
|
||||
def _validate_config(self):
|
||||
"""Validate config and return True or False."""
|
||||
# validate data
|
||||
try:
|
||||
self._data = SCHEMA_CONFIG(self._data)
|
||||
except vol.Invalid as ex:
|
||||
_LOGGER.warning(
|
||||
"Invalid config %s", humanize_error(self._data, ex))
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def save(self):
|
||||
"""Store data to config file."""
|
||||
if not self._validate_config():
|
||||
return False
|
||||
|
||||
if not write_json_file(self._file, self._data):
|
||||
_LOGGER.error("Can't store config in %s", self._file)
|
||||
return False
|
||||
return True
|
||||
|
||||
async def fetch_update_infos(self, websession):
|
||||
"""Read current versions from web."""
|
||||
@ -150,22 +109,6 @@ class CoreConfig(object):
|
||||
self._data[TIMEZONE] = value
|
||||
self.save()
|
||||
|
||||
@property
|
||||
def homeassistant_devices(self):
|
||||
"""Return list of special device to map into homeassistant."""
|
||||
return self._data[HOMEASSISTANT_DEVICES]
|
||||
|
||||
@homeassistant_devices.setter
|
||||
def homeassistant_devices(self, value):
|
||||
"""Set list of special device."""
|
||||
self._data[HOMEASSISTANT_DEVICES] = value
|
||||
self.save()
|
||||
|
||||
@property
|
||||
def homeassistant_image(self):
|
||||
"""Return docker homeassistant repository."""
|
||||
return os.environ['HOMEASSISTANT_REPOSITORY']
|
||||
|
||||
@property
|
||||
def last_homeassistant(self):
|
||||
"""Actual version of homeassistant."""
|
||||
|
@ -24,6 +24,7 @@ RESTART_EXIT_CODE = 100
|
||||
|
||||
FILE_HASSIO_ADDONS = Path(HASSIO_DATA, "addons.json")
|
||||
FILE_HASSIO_CONFIG = Path(HASSIO_DATA, "config.json")
|
||||
FILE_HASSIO_HOMEASSISTANT = Path(HASSIO_DATA, "homeassistant.json")
|
||||
|
||||
SOCKET_DOCKER = Path("/var/run/docker.sock")
|
||||
SOCKET_HC = Path("/var/run/hassio-hc.sock")
|
||||
@ -94,6 +95,7 @@ ATTR_SIZE = 'size'
|
||||
ATTR_TYPE = 'type'
|
||||
ATTR_TIMEOUT = 'timeout'
|
||||
ATTR_AUTO_UPDATE = 'auto_update'
|
||||
ATTR_CUSTOM = 'custom'
|
||||
|
||||
STARTUP_INITIALIZE = 'initialize'
|
||||
STARTUP_BEFORE = 'before'
|
||||
|
@ -13,13 +13,12 @@ from .const import (
|
||||
RUN_UPDATE_SUPERVISOR_TASKS, RUN_WATCHDOG_HOMEASSISTANT,
|
||||
RUN_CLEANUP_API_SESSIONS, STARTUP_AFTER, STARTUP_BEFORE,
|
||||
STARTUP_INITIALIZE, RUN_RELOAD_SNAPSHOTS_TASKS, RUN_UPDATE_ADDONS_TASKS)
|
||||
from .homeassistant import HomeAssistant
|
||||
from .scheduler import Scheduler
|
||||
from .dock.homeassistant import DockerHomeAssistant
|
||||
from .dock.supervisor import DockerSupervisor
|
||||
from .snapshots import SnapshotsManager
|
||||
from .tasks import (
|
||||
hassio_update, homeassistant_watchdog, homeassistant_setup,
|
||||
api_sessions_cleanup, addons_update)
|
||||
hassio_update, homeassistant_watchdog, api_sessions_cleanup, addons_update)
|
||||
from .tools import get_local_ip, fetch_timezone
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
@ -41,7 +40,10 @@ class HassIO(object):
|
||||
|
||||
# init basic docker container
|
||||
self.supervisor = DockerSupervisor(config, loop, self.dock, self.stop)
|
||||
self.homeassistant = DockerHomeAssistant(config, loop, self.dock)
|
||||
|
||||
# init homeassistant
|
||||
self.homeassistant = HomeAssistant(
|
||||
config, loop, self.dock, self.websession)
|
||||
|
||||
# init HostControl
|
||||
self.host_control = HostControl(loop)
|
||||
@ -94,13 +96,8 @@ class HassIO(object):
|
||||
api_sessions_cleanup(self.config), RUN_CLEANUP_API_SESSIONS,
|
||||
now=True)
|
||||
|
||||
# first start of supervisor?
|
||||
if not await self.homeassistant.exists():
|
||||
_LOGGER.info("No HomeAssistant docker found.")
|
||||
await homeassistant_setup(
|
||||
self.config, self.loop, self.homeassistant, self.websession)
|
||||
else:
|
||||
await self.homeassistant.attach()
|
||||
# Load homeassistant
|
||||
await self.homeassistant.prepare()
|
||||
|
||||
# Load addons
|
||||
await self.addons.prepare()
|
||||
@ -157,6 +154,10 @@ class HassIO(object):
|
||||
homeassistant_watchdog(self.loop, self.homeassistant),
|
||||
RUN_WATCHDOG_HOMEASSISTANT)
|
||||
|
||||
# If landingpage / run upgrade in background
|
||||
if self.homeassistant.version == 'landingpage':
|
||||
self.loop.create_task(self.homeassistant.install())
|
||||
|
||||
async def stop(self, exit_code=0):
|
||||
"""Stop a running orchestration."""
|
||||
# don't process scheduler anymore
|
||||
|
@ -260,9 +260,13 @@ class DockerBase(object):
|
||||
if not self._install(tag):
|
||||
return False
|
||||
|
||||
# cleanup old stuff
|
||||
# run or cleanup container
|
||||
if was_running:
|
||||
self._run()
|
||||
else:
|
||||
self._stop()
|
||||
|
||||
# cleanup images
|
||||
self._cleanup()
|
||||
|
||||
return True
|
||||
|
@ -13,9 +13,10 @@ HASS_DOCKER_NAME = 'homeassistant'
|
||||
class DockerHomeAssistant(DockerBase):
|
||||
"""Docker hassio wrapper for HomeAssistant."""
|
||||
|
||||
def __init__(self, config, loop, dock):
|
||||
def __init__(self, config, loop, dock, data):
|
||||
"""Initialize docker homeassistant wrapper."""
|
||||
super().__init__(config, loop, dock, image=config.homeassistant_image)
|
||||
super().__init__(config, loop, dock, image=data.image)
|
||||
self.data = data
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
@ -25,11 +26,11 @@ class DockerHomeAssistant(DockerBase):
|
||||
@property
|
||||
def devices(self):
|
||||
"""Create list of special device to map into docker."""
|
||||
if not self.config.homeassistant_devices:
|
||||
if not self.data.devices:
|
||||
return
|
||||
|
||||
devices = []
|
||||
for device in self.config.homeassistant_devices:
|
||||
for device in self.data.devices:
|
||||
devices.append("/dev/{0}:/dev/{0}:rwm".format(device))
|
||||
|
||||
return devices
|
||||
|
162
hassio/homeassistant.py
Normal file
162
hassio/homeassistant.py
Normal file
@ -0,0 +1,162 @@
|
||||
"""HomeAssistant control object."""
|
||||
import asyncio
|
||||
import logging
|
||||
import os
|
||||
|
||||
from .const import (
|
||||
FILE_HASSIO_HOMEASSISTANT, ATTR_DEVICES, ATTR_IMAGE, ATTR_LAST_VERSION,
|
||||
ATTR_VERSION)
|
||||
from .dock.homeassistant import DockerHomeAssistant
|
||||
from .tools import JsonConfig
|
||||
from .validate import SCHEMA_HASS_CONFIG
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class HomeAssistant(JsonConfig):
|
||||
"""Hass core object for handle it."""
|
||||
|
||||
def __init__(self, config, loop, dock, websession):
|
||||
"""Initialize hass object."""
|
||||
super().__init__(FILE_HASSIO_HOMEASSISTANT, SCHEMA_HASS_CONFIG)
|
||||
self.config = config
|
||||
self.loop = loop
|
||||
self.websession = websession
|
||||
self.docker = DockerHomeAssistant(config, loop, dock, self)
|
||||
|
||||
async def prepare(self):
|
||||
"""Prepare HomeAssistant object."""
|
||||
if not await self.docker.exists():
|
||||
_LOGGER.info("No HomeAssistant docker %s found.", self.image)
|
||||
if self.is_custom_image:
|
||||
await self.install()
|
||||
else:
|
||||
await self.install_landingpage()
|
||||
else:
|
||||
await self.docker.attach()
|
||||
|
||||
@property
|
||||
def version(self):
|
||||
"""Return version of running homeassistant."""
|
||||
return self.docker.version
|
||||
|
||||
@property
|
||||
def last_version(self):
|
||||
"""Return last available version of homeassistant."""
|
||||
if self.is_custom_image:
|
||||
return self._data.get(ATTR_LAST_VERSION)
|
||||
return self.config.last_homeassistant
|
||||
|
||||
@property
|
||||
def image(self):
|
||||
"""Return image name of hass containter."""
|
||||
if ATTR_IMAGE in self._data:
|
||||
return self._data[ATTR_IMAGE]
|
||||
return os.environ['HOMEASSISTANT_REPOSITORY']
|
||||
|
||||
@property
|
||||
def is_custom_image(self):
|
||||
"""Return True if a custom image is used."""
|
||||
return ATTR_IMAGE in self._data
|
||||
|
||||
@property
|
||||
def devices(self):
|
||||
"""Return extend device mapping."""
|
||||
return self._data[ATTR_DEVICES]
|
||||
|
||||
@devices.setter
|
||||
def devices(self, value):
|
||||
"""Set extend device mapping."""
|
||||
self._data[ATTR_DEVICES] = value
|
||||
self.save()
|
||||
|
||||
def set_custom(self, image, version):
|
||||
"""Set a custom image for homeassistant."""
|
||||
# reset
|
||||
if image is None and version is None:
|
||||
self._data.pop(ATTR_IMAGE, None)
|
||||
self._data.pop(ATTR_VERSION, None)
|
||||
|
||||
self.docker.image = self.image
|
||||
else:
|
||||
if image:
|
||||
self._data[ATTR_IMAGE] = image
|
||||
self.docker.image = image
|
||||
if version:
|
||||
self._data[ATTR_VERSION] = version
|
||||
self.save()
|
||||
|
||||
async def install_landingpage(self):
|
||||
"""Install a landingpage."""
|
||||
_LOGGER.info("Setup HomeAssistant landingpage")
|
||||
while True:
|
||||
if await self.docker.install('landingpage'):
|
||||
break
|
||||
_LOGGER.warning("Fails install landingpage, retry after 60sec")
|
||||
await asyncio.sleep(60, loop=self.loop)
|
||||
|
||||
async def install(self):
|
||||
"""Install a landingpage."""
|
||||
_LOGGER.info("Setup HomeAssistant")
|
||||
while True:
|
||||
# read homeassistant tag and install it
|
||||
if not self.last_version:
|
||||
await self.config.fetch_update_infos(self.websession)
|
||||
|
||||
tag = self.last_version
|
||||
if tag and await self.docker.install(tag):
|
||||
break
|
||||
_LOGGER.warning("Error on install HomeAssistant. Retry in 60sec")
|
||||
await asyncio.sleep(60, loop=self.loop)
|
||||
|
||||
# store version
|
||||
_LOGGER.info("HomeAssistant docker now installed")
|
||||
await self.docker.cleanup()
|
||||
|
||||
def update(self, version=None):
|
||||
"""Update HomeAssistant version.
|
||||
|
||||
Return a coroutine.
|
||||
"""
|
||||
version = version or self.last_version
|
||||
return self.docker.update(version)
|
||||
|
||||
def run(self):
|
||||
"""Run HomeAssistant docker.
|
||||
|
||||
Return a coroutine.
|
||||
"""
|
||||
return self.docker.run()
|
||||
|
||||
def stop(self):
|
||||
"""Stop HomeAssistant docker.
|
||||
|
||||
Return a coroutine.
|
||||
"""
|
||||
return self.docker.stop()
|
||||
|
||||
def restart(self):
|
||||
"""Restart HomeAssistant docker.
|
||||
|
||||
Return a coroutine.
|
||||
"""
|
||||
return self.docker.restart()
|
||||
|
||||
def logs(self):
|
||||
"""Get HomeAssistant docker logs.
|
||||
|
||||
Return a coroutine.
|
||||
"""
|
||||
return self.docker.logs()
|
||||
|
||||
def is_running(self):
|
||||
"""Return True if docker container is running.
|
||||
|
||||
Return a coroutine.
|
||||
"""
|
||||
return self.docker.is_running()
|
||||
|
||||
@property
|
||||
def in_progress(self):
|
||||
"""Return True if a task is in progress."""
|
||||
return self.docker.in_progress
|
@ -46,8 +46,7 @@ class SnapshotsManager(object):
|
||||
snapshot.create(slug, name, date_str, sys_type)
|
||||
|
||||
# set general data
|
||||
snapshot.homeassistant_version = self.homeassistant.version
|
||||
snapshot.homeassistant_devices = self.config.homeassistant_devices
|
||||
snapshot.snapshot_homeassistant(self.homeassistant)
|
||||
snapshot.repositories = self.config.addons_repositories
|
||||
|
||||
return snapshot
|
||||
@ -198,8 +197,7 @@ class SnapshotsManager(object):
|
||||
await snapshot.restore_folders()
|
||||
|
||||
# start homeassistant restore
|
||||
self.config.homeassistant_devices = \
|
||||
snapshot.homeassistant_devices
|
||||
snapshot.restore_homeassistant(self.homeassistant)
|
||||
task_hass = self.loop.create_task(
|
||||
self.homeassistant.update(snapshot.homeassistant_version))
|
||||
|
||||
@ -281,8 +279,7 @@ class SnapshotsManager(object):
|
||||
await snapshot.restore_folders(folders)
|
||||
|
||||
if homeassistant:
|
||||
self.config.homeassistant_devices = \
|
||||
snapshot.homeassistant_devices
|
||||
snapshot.restore_homeassistant(self.homeassistant)
|
||||
tasks.append(self.homeassistant.update(
|
||||
snapshot.homeassistant_version))
|
||||
|
||||
|
@ -13,7 +13,8 @@ from .validate import SCHEMA_SNAPSHOT, ALL_FOLDERS
|
||||
from .util import remove_folder
|
||||
from ..const import (
|
||||
ATTR_SLUG, ATTR_NAME, ATTR_DATE, ATTR_ADDONS, ATTR_REPOSITORIES,
|
||||
ATTR_HOMEASSISTANT, ATTR_FOLDERS, ATTR_VERSION, ATTR_TYPE, ATTR_DEVICES)
|
||||
ATTR_HOMEASSISTANT, ATTR_FOLDERS, ATTR_VERSION, ATTR_TYPE, ATTR_DEVICES,
|
||||
ATTR_IMAGE)
|
||||
from ..tools import write_json_file
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
@ -90,6 +91,16 @@ class Snapshot(object):
|
||||
"""Set snapshot homeassistant devices."""
|
||||
self._data[ATTR_HOMEASSISTANT][ATTR_DEVICES] = value
|
||||
|
||||
@property
|
||||
def homeassistant_image(self):
|
||||
"""Return snapshot homeassistant custom image."""
|
||||
return self._data[ATTR_HOMEASSISTANT].get(ATTR_IMAGE)
|
||||
|
||||
@homeassistant_image.setter
|
||||
def homeassistant_image(self, value):
|
||||
"""Set snapshot homeassistant custom image."""
|
||||
self._data[ATTR_HOMEASSISTANT][ATTR_IMAGE] = value
|
||||
|
||||
@property
|
||||
def size(self):
|
||||
"""Return snapshot size."""
|
||||
@ -111,6 +122,24 @@ class Snapshot(object):
|
||||
self._data[ATTR_REPOSITORIES] = []
|
||||
self._data[ATTR_FOLDERS] = []
|
||||
|
||||
def snapshot_homeassistant(self, homeassistant):
|
||||
"""Read all data from homeassistant object."""
|
||||
self.homeassistant_version = homeassistant.version
|
||||
self.homeassistant_devices = homeassistant.devices
|
||||
|
||||
# custom image
|
||||
if homeassistant.is_custom_image:
|
||||
self.homeassistant_image = homeassistant.image
|
||||
|
||||
def restore_homeassistant(self, homeassistant):
|
||||
"""Write all data to homeassistant object."""
|
||||
homeassistant.devices = self.homeassistant_devices
|
||||
|
||||
# custom image
|
||||
if self.homeassistant_image:
|
||||
homeassistant.set_custom(
|
||||
self.homeassistant_image, self.homeassistant_version)
|
||||
|
||||
async def load(self):
|
||||
"""Read snapshot.json from tar file."""
|
||||
if not self.tar_file.is_file():
|
||||
|
@ -5,7 +5,7 @@ import voluptuous as vol
|
||||
from ..const import (
|
||||
ATTR_REPOSITORIES, ATTR_ADDONS, ATTR_NAME, ATTR_SLUG, ATTR_DATE,
|
||||
ATTR_VERSION, ATTR_HOMEASSISTANT, ATTR_FOLDERS, ATTR_TYPE, ATTR_DEVICES,
|
||||
FOLDER_SHARE, FOLDER_HOMEASSISTANT, FOLDER_ADDONS, FOLDER_SSL,
|
||||
ATTR_IMAGE, FOLDER_SHARE, FOLDER_HOMEASSISTANT, FOLDER_ADDONS, FOLDER_SSL,
|
||||
SNAPSHOT_FULL, SNAPSHOT_PARTIAL)
|
||||
from ..validate import HASS_DEVICES
|
||||
|
||||
@ -20,6 +20,7 @@ SCHEMA_SNAPSHOT = vol.Schema({
|
||||
vol.Required(ATTR_HOMEASSISTANT): vol.Schema({
|
||||
vol.Required(ATTR_VERSION): vol.Coerce(str),
|
||||
vol.Optional(ATTR_DEVICES, default=[]): HASS_DEVICES,
|
||||
vol.Optional(ATTR_IMAGE): vol.Coerce(str),
|
||||
}),
|
||||
vol.Optional(ATTR_FOLDERS, default=[]): [vol.In(ALL_FOLDERS)],
|
||||
vol.Optional(ATTR_ADDONS, default=[]): [vol.Schema({
|
||||
|
@ -66,20 +66,3 @@ def homeassistant_watchdog(loop, homeassistant):
|
||||
loop.create_task(homeassistant.run())
|
||||
|
||||
return _homeassistant_watchdog
|
||||
|
||||
|
||||
async def homeassistant_setup(config, loop, homeassistant, websession):
|
||||
"""Install a homeassistant docker container."""
|
||||
while True:
|
||||
# read homeassistant tag and install it
|
||||
if not config.last_homeassistant:
|
||||
await config.fetch_update_infos(websession)
|
||||
|
||||
tag = config.last_homeassistant
|
||||
if tag and await homeassistant.install(tag):
|
||||
break
|
||||
_LOGGER.warning("Error on setup HomeAssistant. Retry in 60.")
|
||||
await asyncio.sleep(60, loop=loop)
|
||||
|
||||
# store version
|
||||
_LOGGER.info("HomeAssistant docker now installed.")
|
||||
|
@ -9,6 +9,7 @@ import aiohttp
|
||||
import async_timeout
|
||||
import pytz
|
||||
import voluptuous as vol
|
||||
from voluptuous.humanize import humanize_error
|
||||
|
||||
from .const import URL_HASSIO_VERSION, URL_HASSIO_VERSION_BETA
|
||||
|
||||
@ -98,3 +99,44 @@ async def fetch_timezone(websession):
|
||||
data = await request.json()
|
||||
|
||||
return data.get('time_zone', 'UTC')
|
||||
|
||||
|
||||
class JsonConfig(object):
|
||||
"""Hass core object for handle it."""
|
||||
|
||||
def __init__(self, json_file, schema):
|
||||
"""Initialize hass object."""
|
||||
self._file = json_file
|
||||
self._schema = schema
|
||||
self._data = {}
|
||||
|
||||
# init or load data
|
||||
if self._file.is_file():
|
||||
try:
|
||||
self._data = read_json_file(self._file)
|
||||
except (OSError, json.JSONDecodeError):
|
||||
_LOGGER.warning("Can't read %s", self._file)
|
||||
self._data = {}
|
||||
|
||||
# validate
|
||||
try:
|
||||
self._data = self._schema(self._data)
|
||||
except vol.Invalid as ex:
|
||||
_LOGGER.error("Can't parse %s -> %s",
|
||||
self._file, humanize_error(self._data, ex))
|
||||
|
||||
def save(self):
|
||||
"""Store data to config file."""
|
||||
# validate
|
||||
try:
|
||||
self._data = self._schema(self._data)
|
||||
except vol.Invalid as ex:
|
||||
_LOGGER.error("Can't parse data -> %s",
|
||||
humanize_error(self._data, ex))
|
||||
return False
|
||||
|
||||
# write
|
||||
if not write_json_file(self._file, self._data):
|
||||
_LOGGER.error("Can't store config in %s", self._file)
|
||||
return False
|
||||
return True
|
||||
|
@ -1,6 +1,9 @@
|
||||
"""Validate functions."""
|
||||
import voluptuous as vol
|
||||
|
||||
from .const import ATTR_DEVICES, ATTR_IMAGE, ATTR_LAST_VERSION
|
||||
|
||||
|
||||
NETWORK_PORT = vol.All(vol.Coerce(int), vol.Range(min=1, max=65535))
|
||||
HASS_DEVICES = [vol.Match(r"^[^/]*$")]
|
||||
|
||||
@ -30,3 +33,10 @@ DOCKER_PORTS = vol.Schema({
|
||||
vol.All(vol.Coerce(str), vol.Match(r"^\d+(?:/tcp|/udp)?$")):
|
||||
convert_to_docker_ports,
|
||||
})
|
||||
|
||||
|
||||
SCHEMA_HASS_CONFIG = vol.Schema({
|
||||
vol.Optional(ATTR_DEVICES, default=[]): HASS_DEVICES,
|
||||
vol.Inclusive(ATTR_IMAGE, 'custom_hass'): vol.Coerce(str),
|
||||
vol.Inclusive(ATTR_LAST_VERSION, 'custom_hass'): vol.Coerce(str),
|
||||
})
|
||||
|
Loading…
x
Reference in New Issue
Block a user