mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-07-14 12:46:32 +00:00
Add support for home-assistant bootup (#349)
* Add support for home-assistant bootup * fix bug * fix * fix ip bug * bugfix
This commit is contained in:
parent
b50756785e
commit
dec04386bf
6
API.md
6
API.md
@ -268,7 +268,8 @@ Optional:
|
||||
"boot": "bool",
|
||||
"port": 8123,
|
||||
"ssl": "bool",
|
||||
"watchdog": "bool"
|
||||
"watchdog": "bool",
|
||||
"startup_time": 600
|
||||
}
|
||||
```
|
||||
|
||||
@ -300,7 +301,8 @@ Output is the raw Docker log.
|
||||
"port": "port for access hass",
|
||||
"ssl": "bool",
|
||||
"password": "",
|
||||
"watchdog": "bool"
|
||||
"watchdog": "bool",
|
||||
"startup_time": 600
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -581,12 +581,12 @@ class Addon(CoreSysAttributes):
|
||||
return STATE_STOPPED
|
||||
|
||||
@check_installed
|
||||
def start(self):
|
||||
"""Set options and start addon.
|
||||
async def start(self):
|
||||
"""Set options and start addon."""
|
||||
if not self.write_options():
|
||||
return False
|
||||
|
||||
Return a coroutine.
|
||||
"""
|
||||
return self.instance.run()
|
||||
return await self.instance.run()
|
||||
|
||||
@check_installed
|
||||
def stop(self):
|
||||
@ -611,16 +611,14 @@ class Addon(CoreSysAttributes):
|
||||
|
||||
# restore state
|
||||
if last_state == STATE_STARTED:
|
||||
await self.instance.run()
|
||||
await self.start()
|
||||
return True
|
||||
|
||||
@check_installed
|
||||
def restart(self):
|
||||
"""Restart addon.
|
||||
|
||||
Return a coroutine.
|
||||
"""
|
||||
return self.instance.restart()
|
||||
async def restart(self):
|
||||
"""Restart addon."""
|
||||
await self.stop()
|
||||
return await self.start()
|
||||
|
||||
@check_installed
|
||||
def logs(self):
|
||||
@ -656,7 +654,7 @@ class Addon(CoreSysAttributes):
|
||||
|
||||
# restore state
|
||||
if last_state == STATE_STARTED:
|
||||
await self.instance.run()
|
||||
await self.start()
|
||||
return True
|
||||
|
||||
@check_installed
|
||||
|
@ -9,7 +9,7 @@ from ..const import (
|
||||
ATTR_VERSION, ATTR_LAST_VERSION, ATTR_IMAGE, ATTR_CUSTOM, ATTR_BOOT,
|
||||
ATTR_PORT, ATTR_PASSWORD, ATTR_SSL, ATTR_WATCHDOG, ATTR_CPU_PERCENT,
|
||||
ATTR_MEMORY_USAGE, ATTR_MEMORY_LIMIT, ATTR_NETWORK_RX, ATTR_NETWORK_TX,
|
||||
ATTR_BLK_READ, ATTR_BLK_WRITE, CONTENT_TYPE_BINARY)
|
||||
ATTR_BLK_READ, ATTR_BLK_WRITE, ATTR_STARTUP_TIME, CONTENT_TYPE_BINARY)
|
||||
from ..coresys import CoreSysAttributes
|
||||
from ..validate import NETWORK_PORT, DOCKER_IMAGE
|
||||
|
||||
@ -27,6 +27,8 @@ SCHEMA_OPTIONS = vol.Schema({
|
||||
vol.Optional(ATTR_PASSWORD): vol.Any(None, vol.Coerce(str)),
|
||||
vol.Optional(ATTR_SSL): vol.Boolean(),
|
||||
vol.Optional(ATTR_WATCHDOG): vol.Boolean(),
|
||||
vol.Optional(ATTR_STARTUP_TIME):
|
||||
vol.All(vol.Coerce(int), vol.Range(min=60)),
|
||||
})
|
||||
|
||||
SCHEMA_VERSION = vol.Schema({
|
||||
@ -49,6 +51,7 @@ class APIHomeAssistant(CoreSysAttributes):
|
||||
ATTR_PORT: self._homeassistant.api_port,
|
||||
ATTR_SSL: self._homeassistant.api_ssl,
|
||||
ATTR_WATCHDOG: self._homeassistant.watchdog,
|
||||
ATTR_STARTUP_TIME: self._homeassistant.startup_time,
|
||||
}
|
||||
|
||||
@api_process
|
||||
@ -75,6 +78,9 @@ class APIHomeAssistant(CoreSysAttributes):
|
||||
if ATTR_WATCHDOG in body:
|
||||
self._homeassistant.watchdog = body[ATTR_WATCHDOG]
|
||||
|
||||
if ATTR_STARTUP_TIME in body:
|
||||
self._homeassistant.startup_time = body[ATTR_STARTUP_TIME]
|
||||
|
||||
self._homeassistant.save_data()
|
||||
return True
|
||||
|
||||
@ -115,7 +121,7 @@ class APIHomeAssistant(CoreSysAttributes):
|
||||
@api_process
|
||||
def start(self, request):
|
||||
"""Start homeassistant."""
|
||||
return asyncio.shield(self._homeassistant.run(), loop=self._loop)
|
||||
return asyncio.shield(self._homeassistant.start(), loop=self._loop)
|
||||
|
||||
@api_process
|
||||
def restart(self, request):
|
||||
|
@ -155,6 +155,7 @@ ATTR_CONFIG = 'config'
|
||||
ATTR_DISCOVERY_ID = 'discovery_id'
|
||||
ATTR_SERVICES = 'services'
|
||||
ATTR_DISCOVERY = 'discovery'
|
||||
ATTR_STARTUP_TIME = 'startup_time'
|
||||
|
||||
SERVICE_MQTT = 'mqtt'
|
||||
|
||||
|
@ -84,7 +84,7 @@ class HassIO(CoreSysAttributes):
|
||||
|
||||
# run HomeAssistant
|
||||
if self._homeassistant.boot:
|
||||
await self._homeassistant.run()
|
||||
await self._homeassistant.start()
|
||||
|
||||
# start addon mark as application
|
||||
await self._addons.auto_boot(STARTUP_APPLICATION)
|
||||
|
@ -225,10 +225,6 @@ class DockerAddon(DockerInterface):
|
||||
# cleanup
|
||||
self._stop()
|
||||
|
||||
# write config
|
||||
if not self.addon.write_options():
|
||||
return False
|
||||
|
||||
ret = self._docker.run(
|
||||
self.image,
|
||||
name=self.name,
|
||||
@ -337,15 +333,6 @@ class DockerAddon(DockerInterface):
|
||||
self._cleanup()
|
||||
return True
|
||||
|
||||
def _restart(self):
|
||||
"""Restart docker container.
|
||||
|
||||
Addons prepare some thing on start and that is normaly not repeatable.
|
||||
Need run inside executor.
|
||||
"""
|
||||
self._stop()
|
||||
return self._run()
|
||||
|
||||
@docker_process
|
||||
def write_stdin(self, data):
|
||||
"""Write to add-on stdin."""
|
||||
|
@ -3,6 +3,8 @@ import asyncio
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import socket
|
||||
import time
|
||||
|
||||
import aiohttp
|
||||
from aiohttp.hdrs import CONTENT_TYPE
|
||||
@ -10,7 +12,7 @@ from aiohttp.hdrs import CONTENT_TYPE
|
||||
from .const import (
|
||||
FILE_HASSIO_HOMEASSISTANT, ATTR_IMAGE, ATTR_LAST_VERSION, ATTR_UUID,
|
||||
ATTR_BOOT, ATTR_PASSWORD, ATTR_PORT, ATTR_SSL, ATTR_WATCHDOG,
|
||||
HEADER_HA_ACCESS, CONTENT_TYPE_JSON)
|
||||
ATTR_STARTUP_TIME, HEADER_HA_ACCESS, CONTENT_TYPE_JSON)
|
||||
from .coresys import CoreSysAttributes
|
||||
from .docker.homeassistant import DockerHomeAssistant
|
||||
from .utils import convert_to_ascii
|
||||
@ -91,6 +93,16 @@ class HomeAssistant(JsonConfig, CoreSysAttributes):
|
||||
"""Return True if the watchdog should protect Home-Assistant."""
|
||||
self._data[ATTR_WATCHDOG] = value
|
||||
|
||||
@property
|
||||
def startup_time(self):
|
||||
"""Return time to wait for Home-Assistant startup."""
|
||||
return self._data[ATTR_STARTUP_TIME]
|
||||
|
||||
@startup_time.setter
|
||||
def startup_time(self, value):
|
||||
"""Set time to wait for Home-Assistant startup."""
|
||||
self._data[ATTR_STARTUP_TIME] = value
|
||||
|
||||
@property
|
||||
def version(self):
|
||||
"""Return version of running homeassistant."""
|
||||
@ -156,8 +168,8 @@ class HomeAssistant(JsonConfig, CoreSysAttributes):
|
||||
_LOGGER.warning("Fails install landingpage, retry after 60sec")
|
||||
await asyncio.sleep(60, loop=self._loop)
|
||||
|
||||
# run landingpage after installation
|
||||
await self.instance.run()
|
||||
# Run landingpage after installation
|
||||
await self.start()
|
||||
|
||||
async def install(self):
|
||||
"""Install a landingpage."""
|
||||
@ -176,7 +188,7 @@ class HomeAssistant(JsonConfig, CoreSysAttributes):
|
||||
# finishing
|
||||
_LOGGER.info("HomeAssistant docker now installed")
|
||||
if self.boot:
|
||||
await self.instance.run()
|
||||
await self.start()
|
||||
await self.instance.cleanup()
|
||||
|
||||
async def update(self, version=None):
|
||||
@ -193,14 +205,14 @@ class HomeAssistant(JsonConfig, CoreSysAttributes):
|
||||
return await self.instance.update(version)
|
||||
finally:
|
||||
if running:
|
||||
await self.instance.run()
|
||||
await self.start()
|
||||
|
||||
def run(self):
|
||||
"""Run HomeAssistant docker.
|
||||
async def start(self):
|
||||
"""Run HomeAssistant docker."""
|
||||
if not await self.instance.run():
|
||||
return False
|
||||
|
||||
Return a coroutine.
|
||||
"""
|
||||
return self.instance.run()
|
||||
return await self._block_till_run()
|
||||
|
||||
def stop(self):
|
||||
"""Stop HomeAssistant docker.
|
||||
@ -209,12 +221,12 @@ class HomeAssistant(JsonConfig, CoreSysAttributes):
|
||||
"""
|
||||
return self.instance.stop()
|
||||
|
||||
def restart(self):
|
||||
"""Restart HomeAssistant docker.
|
||||
async def restart(self):
|
||||
"""Restart HomeAssistant docker."""
|
||||
if not await self.instance.restart():
|
||||
return False
|
||||
|
||||
Return a coroutine.
|
||||
"""
|
||||
return self.instance.restart()
|
||||
return await self._block_till_run()
|
||||
|
||||
def logs(self):
|
||||
"""Get HomeAssistant docker logs.
|
||||
@ -310,3 +322,29 @@ class HomeAssistant(JsonConfig, CoreSysAttributes):
|
||||
_LOGGER.warning("Home-Assistant event %s fails", event_type)
|
||||
return False
|
||||
return True
|
||||
|
||||
async def _block_till_run(self):
|
||||
"""Block until Home-Assistant is booting up or startup timeout."""
|
||||
start_time = time.monotonic()
|
||||
|
||||
def check_port():
|
||||
"""Check if port is mapped."""
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
try:
|
||||
result = sock.connect_ex((str(self.api_ip), self.api_port))
|
||||
sock.close()
|
||||
|
||||
if result == 0:
|
||||
return True
|
||||
return False
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
while time.monotonic() - start_time < self.startup_time:
|
||||
if await self._loop.run_in_executor(None, check_port):
|
||||
_LOGGER.info("Detect a running Home-Assistant instance")
|
||||
return True
|
||||
await asyncio.sleep(10, loop=self._loop)
|
||||
|
||||
_LOGGER.warning("Don't wait anymore of Home-Assistant startup!")
|
||||
return False
|
||||
|
@ -249,7 +249,7 @@ class SnapshotManager(CoreSysAttributes):
|
||||
_LOGGER.info("Full-Restore %s wait until homeassistant ready",
|
||||
snapshot.slug)
|
||||
await task_hass
|
||||
await self._homeassistant.run()
|
||||
await self._homeassistant.start()
|
||||
|
||||
except (OSError, ValueError, tarfile.TarError) as err:
|
||||
_LOGGER.info("Full-Restore %s error: %s", snapshot.slug, err)
|
||||
@ -310,7 +310,7 @@ class SnapshotManager(CoreSysAttributes):
|
||||
await asyncio.wait(tasks, loop=self._loop)
|
||||
|
||||
# make sure homeassistant run agen
|
||||
await self._homeassistant.run()
|
||||
await self._homeassistant.start()
|
||||
|
||||
except (OSError, ValueError, tarfile.TarError) as err:
|
||||
_LOGGER.info("Partial-Restore %s error: %s", snapshot.slug, err)
|
||||
|
@ -15,7 +15,7 @@ from ..const import (
|
||||
ATTR_SLUG, ATTR_NAME, ATTR_DATE, ATTR_ADDONS, ATTR_REPOSITORIES,
|
||||
ATTR_HOMEASSISTANT, ATTR_FOLDERS, ATTR_VERSION, ATTR_TYPE, ATTR_IMAGE,
|
||||
ATTR_PORT, ATTR_SSL, ATTR_PASSWORD, ATTR_WATCHDOG, ATTR_BOOT,
|
||||
ATTR_LAST_VERSION)
|
||||
ATTR_LAST_VERSION, ATTR_STARTUP_TIME)
|
||||
from ..coresys import CoreSysAttributes
|
||||
from ..utils.json import write_json_file
|
||||
|
||||
@ -142,6 +142,16 @@ class Snapshot(CoreSysAttributes):
|
||||
"""Set snapshot homeassistant watchdog options."""
|
||||
self._data[ATTR_HOMEASSISTANT][ATTR_WATCHDOG] = value
|
||||
|
||||
@property
|
||||
def homeassistant_startup_time(self):
|
||||
"""Return snapshot homeassistant startup time options."""
|
||||
return self._data[ATTR_HOMEASSISTANT].get(ATTR_STARTUP_TIME)
|
||||
|
||||
@homeassistant_startup_time.setter
|
||||
def homeassistant_startup_time(self, value):
|
||||
"""Set snapshot homeassistant startup time options."""
|
||||
self._data[ATTR_HOMEASSISTANT][ATTR_STARTUP_TIME] = value
|
||||
|
||||
@property
|
||||
def homeassistant_boot(self):
|
||||
"""Return snapshot homeassistant boot options."""
|
||||
@ -339,6 +349,7 @@ class Snapshot(CoreSysAttributes):
|
||||
self.homeassistant_version = self._homeassistant.version
|
||||
self.homeassistant_watchdog = self._homeassistant.watchdog
|
||||
self.homeassistant_boot = self._homeassistant.boot
|
||||
self.homeassistant_startup_time = self._homeassistant.startup_time
|
||||
|
||||
# custom image
|
||||
if self._homeassistant.is_custom_image:
|
||||
@ -354,6 +365,7 @@ class Snapshot(CoreSysAttributes):
|
||||
"""Write all data to homeassistant object."""
|
||||
self._homeassistant.watchdog = self.homeassistant_watchdog
|
||||
self._homeassistant.boot = self.homeassistant_boot
|
||||
self._homeassistant.startup_time = self.homeassistant_startup_time
|
||||
|
||||
# custom image
|
||||
if self.homeassistant_image:
|
||||
|
@ -6,7 +6,7 @@ from ..const import (
|
||||
ATTR_REPOSITORIES, ATTR_ADDONS, ATTR_NAME, ATTR_SLUG, ATTR_DATE,
|
||||
ATTR_VERSION, ATTR_HOMEASSISTANT, ATTR_FOLDERS, ATTR_TYPE, ATTR_IMAGE,
|
||||
ATTR_PASSWORD, ATTR_PORT, ATTR_SSL, ATTR_WATCHDOG, ATTR_BOOT,
|
||||
ATTR_LAST_VERSION,
|
||||
ATTR_LAST_VERSION, ATTR_STARTUP_TIME,
|
||||
FOLDER_SHARE, FOLDER_HOMEASSISTANT, FOLDER_ADDONS, FOLDER_SSL,
|
||||
SNAPSHOT_FULL, SNAPSHOT_PARTIAL)
|
||||
from ..validate import NETWORK_PORT, REPOSITORIES, DOCKER_IMAGE
|
||||
@ -38,6 +38,8 @@ SCHEMA_SNAPSHOT = vol.Schema({
|
||||
vol.Optional(ATTR_PORT, default=8123): NETWORK_PORT,
|
||||
vol.Optional(ATTR_PASSWORD): vol.Any(None, vol.Coerce(str)),
|
||||
vol.Optional(ATTR_WATCHDOG, default=True): vol.Boolean(),
|
||||
vol.Optional(ATTR_STARTUP_TIME, default=600):
|
||||
vol.All(vol.Coerce(int), vol.Range(min=60)),
|
||||
}, extra=vol.REMOVE_EXTRA),
|
||||
vol.Optional(ATTR_FOLDERS, default=list):
|
||||
vol.All([vol.In(ALL_FOLDERS)], vol.Unique()),
|
||||
|
@ -98,7 +98,7 @@ class Tasks(CoreSysAttributes):
|
||||
return
|
||||
|
||||
_LOGGER.warning("Watchdog found a problem with Home-Assistant docker!")
|
||||
await self._homeassistant.run()
|
||||
await self._homeassistant.start()
|
||||
|
||||
async def _watchdog_homeassistant_api(self):
|
||||
"""Create scheduler task for montoring running state of API.
|
||||
|
@ -8,7 +8,8 @@ from .const import (
|
||||
ATTR_IMAGE, ATTR_LAST_VERSION, ATTR_BETA_CHANNEL, ATTR_TIMEZONE,
|
||||
ATTR_ADDONS_CUSTOM_LIST, ATTR_AUDIO_OUTPUT, ATTR_AUDIO_INPUT,
|
||||
ATTR_PASSWORD, ATTR_HOMEASSISTANT, ATTR_HASSIO, ATTR_BOOT, ATTR_LAST_BOOT,
|
||||
ATTR_SSL, ATTR_PORT, ATTR_WATCHDOG, ATTR_WAIT_BOOT, ATTR_UUID)
|
||||
ATTR_SSL, ATTR_PORT, ATTR_WATCHDOG, ATTR_WAIT_BOOT, ATTR_UUID,
|
||||
ATTR_STARTUP_TIME)
|
||||
|
||||
|
||||
NETWORK_PORT = vol.All(vol.Coerce(int), vol.Range(min=1, max=65535))
|
||||
@ -72,6 +73,8 @@ SCHEMA_HASS_CONFIG = vol.Schema({
|
||||
vol.Optional(ATTR_PASSWORD): vol.Any(None, vol.Coerce(str)),
|
||||
vol.Optional(ATTR_SSL, default=False): vol.Boolean(),
|
||||
vol.Optional(ATTR_WATCHDOG, default=True): vol.Boolean(),
|
||||
vol.Optional(ATTR_STARTUP_TIME, default=600):
|
||||
vol.All(vol.Coerce(int), vol.Range(min=60)),
|
||||
}, extra=vol.REMOVE_EXTRA)
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user