mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-07-13 20:26:29 +00:00
Use tmp folder / fix log bug / add executor (#83)
* Use tmp folder / fix log bug / add executor * Update __main__.py * Update .travis.yml * Add autoupdate on startup. * Fix bug * Move selfupdate code part into start
This commit is contained in:
parent
40343089b5
commit
d5eb66bc0d
@ -2,7 +2,7 @@ sudo: false
|
||||
matrix:
|
||||
fast_finish: true
|
||||
include:
|
||||
- python: "3.5"
|
||||
- python: "3.6"
|
||||
|
||||
cache:
|
||||
directories:
|
||||
|
@ -1,5 +1,6 @@
|
||||
"""Main file for HassIO."""
|
||||
import asyncio
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
import logging
|
||||
import sys
|
||||
|
||||
@ -17,7 +18,14 @@ if __name__ == "__main__":
|
||||
exit(1)
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
hassio = core.HassIO(loop)
|
||||
executor = ThreadPoolExecutor(thread_name_prefix="SyncWorker")
|
||||
loop.set_default_executor(executor)
|
||||
|
||||
_LOGGER.info("Initialize Hassio setup")
|
||||
config = bootstrap.initialize_system_data()
|
||||
hassio = core.HassIO(loop, config)
|
||||
|
||||
bootstrap.migrate_system_env(config)
|
||||
|
||||
_LOGGER.info("Run Hassio setup")
|
||||
loop.run_until_complete(hassio.setup())
|
||||
@ -26,7 +34,11 @@ if __name__ == "__main__":
|
||||
loop.call_soon_threadsafe(loop.create_task, hassio.start())
|
||||
loop.call_soon_threadsafe(bootstrap.reg_signal, loop, hassio)
|
||||
|
||||
_LOGGER.info("Run Hassio loop")
|
||||
loop.run_forever()
|
||||
|
||||
_LOGGER.info("Cleanup system")
|
||||
executor.shutdown(wait=False)
|
||||
loop.close()
|
||||
|
||||
_LOGGER.info("Close Hassio")
|
||||
|
@ -96,6 +96,7 @@ class Addon(object):
|
||||
**self.data.system[self._id][ATTR_OPTIONS],
|
||||
**self.data.user[self._id][ATTR_OPTIONS],
|
||||
}
|
||||
return self.data.cache[self._id][ATTR_OPTIONS]
|
||||
|
||||
@options.setter
|
||||
def options(self, value):
|
||||
|
@ -79,10 +79,10 @@ class APIAddons(object):
|
||||
return True
|
||||
|
||||
@api_process
|
||||
async def install(self, request, check_installed=False):
|
||||
async def install(self, request):
|
||||
"""Install addon."""
|
||||
body = await api_validate(SCHEMA_VERSION, request)
|
||||
addon = self._extract_addon(request)
|
||||
addon = self._extract_addon(request, check_installed=False)
|
||||
version = body.get(ATTR_VERSION)
|
||||
|
||||
return await asyncio.shield(
|
||||
|
@ -2,6 +2,7 @@
|
||||
import logging
|
||||
import os
|
||||
import signal
|
||||
from pathlib import Path
|
||||
|
||||
from colorlog import ColoredFormatter
|
||||
|
||||
@ -11,9 +12,9 @@ from .config import CoreConfig
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def initialize_system_data(websession):
|
||||
def initialize_system_data():
|
||||
"""Setup default config and create folders."""
|
||||
config = CoreConfig(websession)
|
||||
config = CoreConfig()
|
||||
|
||||
# homeassistant config folder
|
||||
if not config.path_config.is_dir():
|
||||
@ -42,10 +43,10 @@ def initialize_system_data(websession):
|
||||
config.path_addons_git)
|
||||
config.path_addons_git.mkdir(parents=True)
|
||||
|
||||
if not config.path_addons_build.is_dir():
|
||||
_LOGGER.info("Create Home-Assistant addon build folder %s",
|
||||
config.path_addons_build)
|
||||
config.path_addons_build.mkdir(parents=True)
|
||||
# hassio tmp folder
|
||||
if not config.path_tmp.is_dir():
|
||||
_LOGGER.info("Create hassio temp folder %s", config.path_tmp)
|
||||
config.path_tmp.mkdir(parents=True)
|
||||
|
||||
# hassio backup folder
|
||||
if not config.path_backup.is_dir():
|
||||
@ -60,6 +61,18 @@ def initialize_system_data(websession):
|
||||
return config
|
||||
|
||||
|
||||
def migrate_system_env(config):
|
||||
"""Cleanup some stuff after update."""
|
||||
|
||||
# hass.io 0.37 -> 0.38
|
||||
old_build = Path(config.path_hassio, "addons/build")
|
||||
if old_build.is_dir():
|
||||
try:
|
||||
old_build.rmdir()
|
||||
except OSError:
|
||||
_LOGGER.warning("Can't cleanup old addons build dir.")
|
||||
|
||||
|
||||
def initialize_logging():
|
||||
"""Setup the logging."""
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
@ -8,7 +8,7 @@ from pathlib import Path, PurePath
|
||||
import voluptuous as vol
|
||||
from voluptuous.humanize import humanize_error
|
||||
|
||||
from .const import FILE_HASSIO_CONFIG, HASSIO_SHARE
|
||||
from .const import FILE_HASSIO_CONFIG, HASSIO_DATA
|
||||
from .tools import (
|
||||
fetch_last_versions, write_json_file, read_json_file, validate_timezone)
|
||||
|
||||
@ -27,12 +27,11 @@ ADDONS_CORE = PurePath("addons/core")
|
||||
ADDONS_LOCAL = PurePath("addons/local")
|
||||
ADDONS_GIT = PurePath("addons/git")
|
||||
ADDONS_DATA = PurePath("addons/data")
|
||||
ADDONS_BUILD = PurePath("addons/build")
|
||||
ADDONS_CUSTOM_LIST = 'addons_custom_list'
|
||||
|
||||
BACKUP_DATA = PurePath("backup")
|
||||
|
||||
SHARE_DATA = PurePath("share")
|
||||
TMP_DATA = PurePath("tmp")
|
||||
|
||||
UPSTREAM_BETA = 'upstream_beta'
|
||||
API_ENDPOINT = 'api_endpoint'
|
||||
@ -88,9 +87,8 @@ class Config(object):
|
||||
class CoreConfig(Config):
|
||||
"""Hold all core config data."""
|
||||
|
||||
def __init__(self, websession):
|
||||
def __init__(self):
|
||||
"""Initialize config object."""
|
||||
self.websession = websession
|
||||
self.arch = None
|
||||
|
||||
super().__init__(FILE_HASSIO_CONFIG)
|
||||
@ -103,10 +101,9 @@ class CoreConfig(Config):
|
||||
_LOGGER.warning(
|
||||
"Invalid config %s", humanize_error(self._data, ex))
|
||||
|
||||
async def fetch_update_infos(self):
|
||||
async def fetch_update_infos(self, websession):
|
||||
"""Read current versions from web."""
|
||||
last = await fetch_last_versions(
|
||||
self.websession, beta=self.upstream_beta)
|
||||
last = await fetch_last_versions(websession, beta=self.upstream_beta)
|
||||
|
||||
if last:
|
||||
self._data.update({
|
||||
@ -176,6 +173,11 @@ class CoreConfig(Config):
|
||||
"""Actual version of hassio."""
|
||||
return self._data.get(HASSIO_LAST)
|
||||
|
||||
@property
|
||||
def path_hassio(self):
|
||||
"""Return hassio data path."""
|
||||
return HASSIO_DATA
|
||||
|
||||
@property
|
||||
def path_extern_hassio(self):
|
||||
"""Return hassio data path extern for docker."""
|
||||
@ -189,7 +191,7 @@ class CoreConfig(Config):
|
||||
@property
|
||||
def path_config(self):
|
||||
"""Return config path inside supervisor."""
|
||||
return Path(HASSIO_SHARE, HOMEASSISTANT_CONFIG)
|
||||
return Path(HASSIO_DATA, HOMEASSISTANT_CONFIG)
|
||||
|
||||
@property
|
||||
def path_extern_ssl(self):
|
||||
@ -199,22 +201,22 @@ class CoreConfig(Config):
|
||||
@property
|
||||
def path_ssl(self):
|
||||
"""Return SSL path inside supervisor."""
|
||||
return Path(HASSIO_SHARE, HASSIO_SSL)
|
||||
return Path(HASSIO_DATA, HASSIO_SSL)
|
||||
|
||||
@property
|
||||
def path_addons_core(self):
|
||||
"""Return git path for core addons."""
|
||||
return Path(HASSIO_SHARE, ADDONS_CORE)
|
||||
return Path(HASSIO_DATA, ADDONS_CORE)
|
||||
|
||||
@property
|
||||
def path_addons_git(self):
|
||||
"""Return path for git addons."""
|
||||
return Path(HASSIO_SHARE, ADDONS_GIT)
|
||||
return Path(HASSIO_DATA, ADDONS_GIT)
|
||||
|
||||
@property
|
||||
def path_addons_local(self):
|
||||
"""Return path for customs addons."""
|
||||
return Path(HASSIO_SHARE, ADDONS_LOCAL)
|
||||
return Path(HASSIO_DATA, ADDONS_LOCAL)
|
||||
|
||||
@property
|
||||
def path_extern_addons_local(self):
|
||||
@ -224,7 +226,7 @@ class CoreConfig(Config):
|
||||
@property
|
||||
def path_addons_data(self):
|
||||
"""Return root addon data folder."""
|
||||
return Path(HASSIO_SHARE, ADDONS_DATA)
|
||||
return Path(HASSIO_DATA, ADDONS_DATA)
|
||||
|
||||
@property
|
||||
def path_extern_addons_data(self):
|
||||
@ -232,14 +234,14 @@ class CoreConfig(Config):
|
||||
return PurePath(self.path_extern_hassio, ADDONS_DATA)
|
||||
|
||||
@property
|
||||
def path_addons_build(self):
|
||||
"""Return root addon build folder."""
|
||||
return Path(HASSIO_SHARE, ADDONS_BUILD)
|
||||
def path_tmp(self):
|
||||
"""Return hass.io temp folder."""
|
||||
return Path(HASSIO_DATA, TMP_DATA)
|
||||
|
||||
@property
|
||||
def path_backup(self):
|
||||
"""Return root backup data folder."""
|
||||
return Path(HASSIO_SHARE, BACKUP_DATA)
|
||||
return Path(HASSIO_DATA, BACKUP_DATA)
|
||||
|
||||
@property
|
||||
def path_extern_backup(self):
|
||||
@ -249,7 +251,7 @@ class CoreConfig(Config):
|
||||
@property
|
||||
def path_share(self):
|
||||
"""Return root share data folder."""
|
||||
return Path(HASSIO_SHARE, SHARE_DATA)
|
||||
return Path(HASSIO_DATA, SHARE_DATA)
|
||||
|
||||
@property
|
||||
def path_extern_share(self):
|
||||
|
@ -10,7 +10,7 @@ URL_HASSIO_VERSION_BETA = ('https://raw.githubusercontent.com/home-assistant/'
|
||||
|
||||
URL_HASSIO_ADDONS = 'https://github.com/home-assistant/hassio-addons'
|
||||
|
||||
HASSIO_SHARE = Path("/data")
|
||||
HASSIO_DATA = Path("/data")
|
||||
|
||||
RUN_UPDATE_INFO_TASKS = 28800
|
||||
RUN_UPDATE_SUPERVISOR_TASKS = 29100
|
||||
@ -20,8 +20,8 @@ RUN_CLEANUP_API_SESSIONS = 900
|
||||
|
||||
RESTART_EXIT_CODE = 100
|
||||
|
||||
FILE_HASSIO_ADDONS = Path(HASSIO_SHARE, "addons.json")
|
||||
FILE_HASSIO_CONFIG = Path(HASSIO_SHARE, "config.json")
|
||||
FILE_HASSIO_ADDONS = Path(HASSIO_DATA, "addons.json")
|
||||
FILE_HASSIO_CONFIG = Path(HASSIO_DATA, "config.json")
|
||||
|
||||
SOCKET_DOCKER = Path("/var/run/docker.sock")
|
||||
SOCKET_HC = Path("/var/run/hassio-hc.sock")
|
||||
|
@ -4,7 +4,6 @@ import logging
|
||||
import aiohttp
|
||||
import docker
|
||||
|
||||
from . import bootstrap
|
||||
from .addons import AddonManager
|
||||
from .api import RestAPI
|
||||
from .host_control import HostControl
|
||||
@ -27,28 +26,26 @@ _LOGGER = logging.getLogger(__name__)
|
||||
class HassIO(object):
|
||||
"""Main object of hassio."""
|
||||
|
||||
def __init__(self, loop):
|
||||
def __init__(self, loop, config):
|
||||
"""Initialize hassio object."""
|
||||
self.exit_code = 0
|
||||
self.loop = loop
|
||||
self.websession = aiohttp.ClientSession(loop=self.loop)
|
||||
self.config = bootstrap.initialize_system_data(self.websession)
|
||||
self.scheduler = Scheduler(self.loop)
|
||||
self.api = RestAPI(self.config, self.loop)
|
||||
self.config = config
|
||||
self.websession = aiohttp.ClientSession(loop=loop)
|
||||
self.scheduler = Scheduler(loop)
|
||||
self.api = RestAPI(config, loop)
|
||||
self.dock = docker.DockerClient(
|
||||
base_url="unix:/{}".format(str(SOCKET_DOCKER)), version='auto')
|
||||
|
||||
# init basic docker container
|
||||
self.supervisor = DockerSupervisor(
|
||||
self.config, self.loop, self.dock, self.stop)
|
||||
self.homeassistant = DockerHomeAssistant(
|
||||
self.config, self.loop, self.dock)
|
||||
self.supervisor = DockerSupervisor(config, loop, self.dock, self.stop)
|
||||
self.homeassistant = DockerHomeAssistant(config, loop, self.dock)
|
||||
|
||||
# init HostControl
|
||||
self.host_control = HostControl(self.loop)
|
||||
self.host_control = HostControl(loop)
|
||||
|
||||
# init addon system
|
||||
self.addons = AddonManager(self.config, self.loop, self.dock)
|
||||
self.addons = AddonManager(config, loop, self.dock)
|
||||
|
||||
async def setup(self):
|
||||
"""Setup HassIO orchestration."""
|
||||
@ -72,8 +69,8 @@ class HassIO(object):
|
||||
|
||||
# schedule update info tasks
|
||||
self.scheduler.register_task(
|
||||
|
||||
self.host_control.load, RUN_UPDATE_INFO_TASKS)
|
||||
|
||||
# rest api views
|
||||
self.api.register_host(self.host_control)
|
||||
self.api.register_network(self.host_control)
|
||||
@ -89,16 +86,11 @@ class HassIO(object):
|
||||
api_sessions_cleanup(self.config), RUN_CLEANUP_API_SESSIONS,
|
||||
now=True)
|
||||
|
||||
# schedule update info tasks
|
||||
self.scheduler.register_task(
|
||||
self.config.fetch_update_infos, RUN_UPDATE_INFO_TASKS,
|
||||
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.config, self.loop, self.homeassistant, self.websession)
|
||||
else:
|
||||
await self.homeassistant.attach()
|
||||
|
||||
@ -111,7 +103,7 @@ class HassIO(object):
|
||||
|
||||
# schedule self update task
|
||||
self.scheduler.register_task(
|
||||
hassio_update(self.config, self.supervisor),
|
||||
hassio_update(self.config, self.supervisor, self.websession),
|
||||
RUN_UPDATE_SUPERVISOR_TASKS)
|
||||
|
||||
# start addon mark as initialize
|
||||
@ -119,6 +111,14 @@ class HassIO(object):
|
||||
|
||||
async def start(self):
|
||||
"""Start HassIO orchestration."""
|
||||
# on release channel, try update itself
|
||||
# on beta channel, only read new versions
|
||||
if not self.config.upstream_beta:
|
||||
await self.loop.create_task(
|
||||
hassio_update(self.config, self.supervisor, self.websession)())
|
||||
else:
|
||||
await self.config.fetch_update_infos(self.websession)
|
||||
|
||||
# start api
|
||||
await self.api.start()
|
||||
_LOGGER.info("Start hassio api on %s", self.config.api_endpoint)
|
||||
|
@ -267,7 +267,7 @@ class DockerBase(object):
|
||||
"""Return docker logs of container."""
|
||||
if self._lock.locked():
|
||||
_LOGGER.error("Can't excute logs while a task is in progress")
|
||||
return False
|
||||
return b""
|
||||
|
||||
async with self._lock:
|
||||
return await self.loop.run_in_executor(None, self._logs)
|
||||
|
@ -145,7 +145,7 @@ class DockerAddon(DockerBase):
|
||||
|
||||
Need run inside executor.
|
||||
"""
|
||||
build_dir = Path(self.config.path_addons_build, self.addon.slug)
|
||||
build_dir = Path(self.config.path_tmp, self.addon.slug)
|
||||
try:
|
||||
# prepare temporary addon build folder
|
||||
try:
|
||||
|
@ -18,10 +18,11 @@ def api_sessions_cleanup(config):
|
||||
return _api_sessions_cleanup
|
||||
|
||||
|
||||
def hassio_update(config, supervisor):
|
||||
def hassio_update(config, supervisor, websession):
|
||||
"""Create scheduler task for update of supervisor hassio."""
|
||||
async def _hassio_update():
|
||||
"""Check and run update of supervisor hassio."""
|
||||
await config.fetch_update_infos(websession)
|
||||
if config.last_hassio == supervisor.version:
|
||||
return
|
||||
|
||||
@ -43,12 +44,12 @@ def homeassistant_watchdog(loop, homeassistant):
|
||||
return _homeassistant_watchdog
|
||||
|
||||
|
||||
async def homeassistant_setup(config, loop, homeassistant):
|
||||
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()
|
||||
await config.fetch_update_infos(websession)
|
||||
|
||||
tag = config.last_homeassistant
|
||||
if tag and await homeassistant.install(tag):
|
||||
|
Loading…
x
Reference in New Issue
Block a user