mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-07-19 15:16:33 +00:00
Use updater for image data (#1628)
* Use updater for image data * Fix message * Fix handling * Update code * fix lint * fix names * Fix log * Fix error log * make it better
This commit is contained in:
parent
9350e4f961
commit
fcebc9d1ed
@ -92,7 +92,7 @@ class APISupervisor(CoreSysAttributes):
|
||||
|
||||
return {
|
||||
ATTR_VERSION: SUPERVISOR_VERSION,
|
||||
ATTR_VERSION_LATEST: self.sys_updater.version_hassio,
|
||||
ATTR_VERSION_LATEST: self.sys_updater.version_supervisor,
|
||||
ATTR_CHANNEL: self.sys_updater.channel,
|
||||
ATTR_ARCH: self.sys_supervisor.arch,
|
||||
ATTR_IP_ADDRESS: str(self.sys_supervisor.ip_address),
|
||||
@ -153,7 +153,7 @@ class APISupervisor(CoreSysAttributes):
|
||||
async def update(self, request: web.Request) -> None:
|
||||
"""Update Supervisor OS."""
|
||||
body = await api_validate(SCHEMA_VERSION, request)
|
||||
version = body.get(ATTR_VERSION, self.sys_updater.version_hassio)
|
||||
version = body.get(ATTR_VERSION, self.sys_updater.version_supervisor)
|
||||
|
||||
if version == self.sys_supervisor.version:
|
||||
raise APIError("Version {} is already in use".format(version))
|
||||
|
@ -128,36 +128,40 @@ class Audio(JsonConfig, CoreSysAttributes):
|
||||
|
||||
if self.latest_version:
|
||||
with suppress(DockerAPIError):
|
||||
await self.instance.install(self.latest_version)
|
||||
await self.instance.install(
|
||||
self.latest_version, image=self.sys_updater.image_audio
|
||||
)
|
||||
break
|
||||
_LOGGER.warning("Error on install Audio plugin. Retry in 30sec")
|
||||
await asyncio.sleep(30)
|
||||
|
||||
_LOGGER.info("Audio plugin now installed")
|
||||
self.version = self.instance.version
|
||||
self.image = self.instance.image
|
||||
self.image = self.sys_updater.image_audio
|
||||
self.save_data()
|
||||
|
||||
async def update(self, version: Optional[str] = None) -> None:
|
||||
"""Update Audio plugin."""
|
||||
version = version or self.latest_version
|
||||
old_image = self.image
|
||||
|
||||
if version == self.version:
|
||||
_LOGGER.warning("Version %s is already installed for Audio", version)
|
||||
return
|
||||
|
||||
try:
|
||||
await self.instance.update(version)
|
||||
await self.instance.update(version, image=self.sys_updater.image_audio)
|
||||
except DockerAPIError:
|
||||
_LOGGER.error("Audio update fails")
|
||||
raise AudioUpdateError() from None
|
||||
else:
|
||||
# Cleanup
|
||||
with suppress(DockerAPIError):
|
||||
await self.instance.cleanup()
|
||||
self.version = version
|
||||
self.image = self.sys_updater.image_audio
|
||||
self.save_data()
|
||||
|
||||
self.version = version
|
||||
self.save_data()
|
||||
# Cleanup
|
||||
with suppress(DockerAPIError):
|
||||
await self.instance.cleanup(old_image=old_image)
|
||||
|
||||
# Start Audio
|
||||
await self.start()
|
||||
|
@ -12,7 +12,14 @@ from .api import RestAPI
|
||||
from .arch import CpuArch
|
||||
from .auth import Auth
|
||||
from .audio import Audio
|
||||
from .const import SOCKET_DOCKER, UpdateChannels
|
||||
from .const import (
|
||||
SOCKET_DOCKER,
|
||||
UpdateChannels,
|
||||
ENV_SUPERVISOR_SHARE,
|
||||
ENV_SUPERVISOR_NAME,
|
||||
ENV_HOMEASSISTANT_REPOSITORY,
|
||||
ENV_SUPERVISOR_MACHINE,
|
||||
)
|
||||
from .core import Core
|
||||
from .cli import HaCli
|
||||
from .coresys import CoreSys
|
||||
@ -35,9 +42,6 @@ from .utils.dt import fetch_timezone
|
||||
|
||||
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
ENV_SHARE = "SUPERVISOR_SHARE"
|
||||
ENV_NAME = "SUPERVISOR_NAME"
|
||||
ENV_REPO = "HOMEASSISTANT_REPOSITORY"
|
||||
|
||||
MACHINE_ID = Path("/etc/machine-id")
|
||||
|
||||
@ -81,6 +85,13 @@ async def initialize_coresys():
|
||||
if coresys.config.timezone == "UTC":
|
||||
coresys.config.timezone = await fetch_timezone(coresys.websession)
|
||||
|
||||
# Set machine type
|
||||
if os.environ.get(ENV_SUPERVISOR_MACHINE):
|
||||
coresys.machine = os.environ[ENV_SUPERVISOR_MACHINE]
|
||||
elif os.environ.get(ENV_HOMEASSISTANT_REPOSITORY):
|
||||
coresys.machine = os.environ[ENV_HOMEASSISTANT_REPOSITORY][14:-14]
|
||||
_LOGGER.info("Setup coresys for machine: %s", coresys.machine)
|
||||
|
||||
return coresys
|
||||
|
||||
|
||||
@ -165,7 +176,7 @@ def migrate_system_env(coresys: CoreSys):
|
||||
config = coresys.config
|
||||
|
||||
# hass.io 0.37 -> 0.38
|
||||
old_build = Path(config.path_hassio, "addons/build")
|
||||
old_build = Path(config.path_supervisor, "addons/build")
|
||||
if old_build.is_dir():
|
||||
try:
|
||||
old_build.rmdir()
|
||||
@ -202,12 +213,20 @@ def initialize_logging():
|
||||
def check_environment() -> None:
|
||||
"""Check if all environment are exists."""
|
||||
# check environment variables
|
||||
for key in (ENV_SHARE, ENV_NAME, ENV_REPO):
|
||||
for key in (ENV_SUPERVISOR_SHARE, ENV_SUPERVISOR_NAME):
|
||||
try:
|
||||
os.environ[key]
|
||||
except KeyError:
|
||||
_LOGGER.fatal("Can't find %s in env!", key)
|
||||
|
||||
# Check Machine info
|
||||
if not os.environ.get(ENV_HOMEASSISTANT_REPOSITORY) and not os.environ.get(
|
||||
ENV_SUPERVISOR_MACHINE
|
||||
):
|
||||
_LOGGER.fatal("Can't find any kind of machine/homeassistant details!")
|
||||
elif not os.environ.get(ENV_SUPERVISOR_MACHINE):
|
||||
_LOGGER.info("Use the old homeassistant repository for machine extraction")
|
||||
|
||||
# check docker socket
|
||||
if not SOCKET_DOCKER.is_socket():
|
||||
_LOGGER.fatal("Can't find Docker socket!")
|
||||
|
@ -102,36 +102,44 @@ class HaCli(CoreSysAttributes, JsonConfig):
|
||||
|
||||
if self.latest_version:
|
||||
with suppress(DockerAPIError):
|
||||
await self.instance.install(self.latest_version, latest=True)
|
||||
await self.instance.install(
|
||||
self.latest_version,
|
||||
image=self.sys_updater.image_cli,
|
||||
latest=True,
|
||||
)
|
||||
break
|
||||
_LOGGER.warning("Error on install cli plugin. Retry in 30sec")
|
||||
await asyncio.sleep(30)
|
||||
|
||||
_LOGGER.info("cli plugin now installed")
|
||||
self.version = self.instance.version
|
||||
self.image = self.instance.image
|
||||
self.image = self.sys_updater.image_cli
|
||||
self.save_data()
|
||||
|
||||
async def update(self, version: Optional[str] = None) -> None:
|
||||
"""Update local HA cli."""
|
||||
version = version or self.latest_version
|
||||
old_image = self.image
|
||||
|
||||
if version == self.version:
|
||||
_LOGGER.warning("Version %s is already installed for cli", version)
|
||||
return
|
||||
|
||||
try:
|
||||
await self.instance.update(version, latest=True)
|
||||
await self.instance.update(
|
||||
version, image=self.sys_updater.image_cli, latest=True
|
||||
)
|
||||
except DockerAPIError:
|
||||
_LOGGER.error("HA cli update fails")
|
||||
raise CliUpdateError() from None
|
||||
else:
|
||||
self.version = version
|
||||
self.image = self.sys_updater.image_cli
|
||||
self.save_data()
|
||||
|
||||
# Cleanup
|
||||
with suppress(DockerAPIError):
|
||||
await self.instance.cleanup()
|
||||
|
||||
self.version = version
|
||||
self.save_data()
|
||||
await self.instance.cleanup(old_image=old_image)
|
||||
|
||||
# Start cli
|
||||
await self.start()
|
||||
|
@ -12,6 +12,7 @@ from .const import (
|
||||
ATTR_LOGGING,
|
||||
ATTR_TIMEZONE,
|
||||
ATTR_WAIT_BOOT,
|
||||
ENV_SUPERVISOR_SHARE,
|
||||
FILE_HASSIO_CONFIG,
|
||||
SUPERVISOR_DATA,
|
||||
)
|
||||
@ -119,19 +120,19 @@ class CoreConfig(JsonConfig):
|
||||
self._data[ATTR_LAST_BOOT] = value.isoformat()
|
||||
|
||||
@property
|
||||
def path_hassio(self):
|
||||
def path_supervisor(self):
|
||||
"""Return Supervisor data path."""
|
||||
return SUPERVISOR_DATA
|
||||
|
||||
@property
|
||||
def path_extern_hassio(self):
|
||||
def path_extern_supervisor(self):
|
||||
"""Return Supervisor data path external for Docker."""
|
||||
return PurePath(os.environ["SUPERVISOR_SHARE"])
|
||||
return PurePath(os.environ[ENV_SUPERVISOR_SHARE])
|
||||
|
||||
@property
|
||||
def path_extern_homeassistant(self):
|
||||
"""Return config path external for Docker."""
|
||||
return str(PurePath(self.path_extern_hassio, HOMEASSISTANT_CONFIG))
|
||||
return str(PurePath(self.path_extern_supervisor, HOMEASSISTANT_CONFIG))
|
||||
|
||||
@property
|
||||
def path_homeassistant(self):
|
||||
@ -141,7 +142,7 @@ class CoreConfig(JsonConfig):
|
||||
@property
|
||||
def path_extern_ssl(self):
|
||||
"""Return SSL path external for Docker."""
|
||||
return str(PurePath(self.path_extern_hassio, HASSIO_SSL))
|
||||
return str(PurePath(self.path_extern_supervisor, HASSIO_SSL))
|
||||
|
||||
@property
|
||||
def path_ssl(self):
|
||||
@ -166,7 +167,7 @@ class CoreConfig(JsonConfig):
|
||||
@property
|
||||
def path_extern_addons_local(self):
|
||||
"""Return path for custom Add-ons."""
|
||||
return PurePath(self.path_extern_hassio, ADDONS_LOCAL)
|
||||
return PurePath(self.path_extern_supervisor, ADDONS_LOCAL)
|
||||
|
||||
@property
|
||||
def path_addons_data(self):
|
||||
@ -176,7 +177,7 @@ class CoreConfig(JsonConfig):
|
||||
@property
|
||||
def path_extern_addons_data(self):
|
||||
"""Return root add-on data folder external for Docker."""
|
||||
return PurePath(self.path_extern_hassio, ADDONS_DATA)
|
||||
return PurePath(self.path_extern_supervisor, ADDONS_DATA)
|
||||
|
||||
@property
|
||||
def path_audio(self):
|
||||
@ -186,7 +187,7 @@ class CoreConfig(JsonConfig):
|
||||
@property
|
||||
def path_extern_audio(self):
|
||||
"""Return root audio data folder external for Docker."""
|
||||
return PurePath(self.path_extern_hassio, AUDIO_DATA)
|
||||
return PurePath(self.path_extern_supervisor, AUDIO_DATA)
|
||||
|
||||
@property
|
||||
def path_tmp(self):
|
||||
@ -196,7 +197,7 @@ class CoreConfig(JsonConfig):
|
||||
@property
|
||||
def path_extern_tmp(self):
|
||||
"""Return Supervisor temp folder for Docker."""
|
||||
return PurePath(self.path_extern_hassio, TMP_DATA)
|
||||
return PurePath(self.path_extern_supervisor, TMP_DATA)
|
||||
|
||||
@property
|
||||
def path_backup(self):
|
||||
@ -206,7 +207,7 @@ class CoreConfig(JsonConfig):
|
||||
@property
|
||||
def path_extern_backup(self):
|
||||
"""Return root backup data folder external for Docker."""
|
||||
return PurePath(self.path_extern_hassio, BACKUP_DATA)
|
||||
return PurePath(self.path_extern_supervisor, BACKUP_DATA)
|
||||
|
||||
@property
|
||||
def path_share(self):
|
||||
@ -221,12 +222,12 @@ class CoreConfig(JsonConfig):
|
||||
@property
|
||||
def path_extern_share(self):
|
||||
"""Return root share data folder external for Docker."""
|
||||
return PurePath(self.path_extern_hassio, SHARE_DATA)
|
||||
return PurePath(self.path_extern_supervisor, SHARE_DATA)
|
||||
|
||||
@property
|
||||
def path_extern_dns(self):
|
||||
"""Return dns path external for Docker."""
|
||||
return str(PurePath(self.path_extern_hassio, DNS_DATA))
|
||||
return str(PurePath(self.path_extern_supervisor, DNS_DATA))
|
||||
|
||||
@property
|
||||
def path_dns(self):
|
||||
|
@ -68,8 +68,14 @@ ENV_TOKEN_OLD = "HASSIO_TOKEN"
|
||||
ENV_TOKEN = "SUPERVISOR_TOKEN"
|
||||
ENV_TIME = "TZ"
|
||||
|
||||
ENV_HOMEASSISTANT_REPOSITORY = "HOMEASSISTANT_REPOSITORY"
|
||||
ENV_SUPERVISOR_SHARE = "SUPERVISOR_SHARE"
|
||||
ENV_SUPERVISOR_NAME = "SUPERVISOR_NAME"
|
||||
ENV_SUPERVISOR_MACHINE = "SUPERVISOR_MACHINE"
|
||||
|
||||
REQUEST_FROM = "HASSIO_FROM"
|
||||
|
||||
ATTR_SUPERVISOR = "supervisor"
|
||||
ATTR_MACHINE = "machine"
|
||||
ATTR_WAIT_BOOT = "wait_boot"
|
||||
ATTR_DEPLOYMENT = "deployment"
|
||||
@ -138,7 +144,6 @@ ATTR_USER = "user"
|
||||
ATTR_SYSTEM = "system"
|
||||
ATTR_SNAPSHOTS = "snapshots"
|
||||
ATTR_HOMEASSISTANT = "homeassistant"
|
||||
ATTR_HASSIO = "hassio"
|
||||
ATTR_HASSIO_API = "hassio_api"
|
||||
ATTR_HOMEASSISTANT_API = "homeassistant_api"
|
||||
ATTR_UUID = "uuid"
|
||||
|
@ -203,10 +203,12 @@ class Core(CoreSysAttributes):
|
||||
_LOGGER.info("Start repairing of Supervisor Environment")
|
||||
await self.sys_run_in_executor(self.sys_docker.repair)
|
||||
|
||||
# Fix plugins
|
||||
await asyncio.wait(
|
||||
[self.sys_dns.repair(), self.sys_audio.repair(), self.sys_cli.repair()]
|
||||
)
|
||||
|
||||
# Restore core functionality
|
||||
await self.sys_dns.repair()
|
||||
await self.sys_audio.repair()
|
||||
await self.sys_cli.repair()
|
||||
await self.sys_addons.repair()
|
||||
await self.sys_homeassistant.repair()
|
||||
|
||||
|
@ -42,7 +42,8 @@ class CoreSys:
|
||||
def __init__(self):
|
||||
"""Initialize coresys."""
|
||||
# Static attributes
|
||||
self.machine_id: Optional[str] = None
|
||||
self._machine_id: Optional[str] = None
|
||||
self._machine: Optional[str] = None
|
||||
|
||||
# External objects
|
||||
self._loop: asyncio.BaseEventLoop = asyncio.get_running_loop()
|
||||
@ -81,13 +82,6 @@ class CoreSys:
|
||||
self._discovery: Optional[Discovery] = None
|
||||
self._hwmonitor: Optional[HwMonitor] = None
|
||||
|
||||
@property
|
||||
def machine(self) -> str:
|
||||
"""Return running machine type of the Supervisor system."""
|
||||
if self._homeassistant:
|
||||
return self._homeassistant.machine
|
||||
return None
|
||||
|
||||
@property
|
||||
def dev(self) -> bool:
|
||||
"""Return True if we run dev mode."""
|
||||
@ -397,6 +391,30 @@ class CoreSys:
|
||||
raise RuntimeError("HassOS already set!")
|
||||
self._hassos = value
|
||||
|
||||
@property
|
||||
def machine(self) -> Optional[str]:
|
||||
"""Return machine type string."""
|
||||
return self._machine
|
||||
|
||||
@machine.setter
|
||||
def machine(self, value: str):
|
||||
"""Set a machine type string."""
|
||||
if self._machine:
|
||||
raise RuntimeError("Machine type already set!")
|
||||
self._machine = value
|
||||
|
||||
@property
|
||||
def machine_id(self) -> Optional[str]:
|
||||
"""Return machine-id type string."""
|
||||
return self._machine_id
|
||||
|
||||
@machine_id.setter
|
||||
def machine_id(self, value: str):
|
||||
"""Set a machine-id type string."""
|
||||
if self._machine_id:
|
||||
raise RuntimeError("Machine-ID type already set!")
|
||||
self._machine_id = value
|
||||
|
||||
|
||||
class CoreSysAttributes:
|
||||
"""Inheret basic CoreSysAttributes."""
|
||||
|
@ -167,14 +167,16 @@ class CoreDNS(JsonConfig, CoreSysAttributes):
|
||||
|
||||
if self.latest_version:
|
||||
with suppress(DockerAPIError):
|
||||
await self.instance.install(self.latest_version)
|
||||
await self.instance.install(
|
||||
self.latest_version, image=self.sys_updater.image_dns
|
||||
)
|
||||
break
|
||||
_LOGGER.warning("Error on install CoreDNS plugin. Retry in 30sec")
|
||||
await asyncio.sleep(30)
|
||||
|
||||
_LOGGER.info("CoreDNS plugin now installed")
|
||||
self.version = self.instance.version
|
||||
self.image = self.instance.image
|
||||
self.image = self.sys_updater.image_dns
|
||||
self.save_data()
|
||||
|
||||
# Init Hosts
|
||||
@ -183,6 +185,7 @@ class CoreDNS(JsonConfig, CoreSysAttributes):
|
||||
async def update(self, version: Optional[str] = None) -> None:
|
||||
"""Update CoreDNS plugin."""
|
||||
version = version or self.latest_version
|
||||
old_image = self.image
|
||||
|
||||
if version == self.version:
|
||||
_LOGGER.warning("Version %s is already installed for CoreDNS", version)
|
||||
@ -190,17 +193,18 @@ class CoreDNS(JsonConfig, CoreSysAttributes):
|
||||
|
||||
# Update
|
||||
try:
|
||||
await self.instance.update(version)
|
||||
await self.instance.update(version, image=self.sys_updater.image_dns)
|
||||
except DockerAPIError:
|
||||
_LOGGER.error("CoreDNS update fails")
|
||||
raise CoreDNSUpdateError() from None
|
||||
else:
|
||||
self.version = version
|
||||
self.image = self.sys_updater.image_dns
|
||||
self.save_data()
|
||||
|
||||
# Cleanup
|
||||
with suppress(DockerAPIError):
|
||||
await self.instance.cleanup()
|
||||
|
||||
self.version = version
|
||||
self.save_data()
|
||||
await self.instance.cleanup(old_image=old_image)
|
||||
|
||||
# Start CoreDNS
|
||||
await self.start()
|
||||
|
@ -60,5 +60,5 @@ class DockerCli(DockerInterface, CoreSysAttributes):
|
||||
"Start CLI %s with version %s - %s",
|
||||
self.image,
|
||||
self.version,
|
||||
self.sys_docker.network.audio,
|
||||
self.sys_docker.network.cli,
|
||||
)
|
||||
|
@ -302,11 +302,11 @@ class DockerInterface(CoreSysAttributes):
|
||||
_LOGGER.warning("Can't grep logs from %s: %s", self.image, err)
|
||||
|
||||
@process_lock
|
||||
def cleanup(self) -> Awaitable[None]:
|
||||
def cleanup(self, old_image: Optional[str] = None) -> Awaitable[None]:
|
||||
"""Check if old version exists and cleanup."""
|
||||
return self.sys_run_in_executor(self._cleanup)
|
||||
return self.sys_run_in_executor(self._cleanup, old_image)
|
||||
|
||||
def _cleanup(self) -> None:
|
||||
def _cleanup(self, old_image: Optional[str] = None) -> None:
|
||||
"""Check if old version exists and cleanup.
|
||||
|
||||
Need run inside executor.
|
||||
@ -317,6 +317,7 @@ class DockerInterface(CoreSysAttributes):
|
||||
_LOGGER.warning("Can't find %s for cleanup", self.image)
|
||||
raise DockerAPIError() from None
|
||||
|
||||
# Cleanup Current
|
||||
for image in self.sys_docker.images.list(name=self.image):
|
||||
if origin.id == image.id:
|
||||
continue
|
||||
@ -325,6 +326,15 @@ class DockerInterface(CoreSysAttributes):
|
||||
_LOGGER.info("Cleanup images: %s", image.tags)
|
||||
self.sys_docker.images.remove(image.id, force=True)
|
||||
|
||||
# Cleanup Old
|
||||
if not old_image or self.image == old_image:
|
||||
return
|
||||
|
||||
for image in self.sys_docker.images.list(name=old_image):
|
||||
with suppress(docker.errors.DockerException):
|
||||
_LOGGER.info("Cleanup images: %s", image.tags)
|
||||
self.sys_docker.images.remove(image.id, force=True)
|
||||
|
||||
@process_lock
|
||||
def restart(self) -> Awaitable[None]:
|
||||
"""Restart docker container."""
|
||||
|
@ -4,7 +4,6 @@ from contextlib import asynccontextmanager, suppress
|
||||
from datetime import datetime, timedelta
|
||||
from ipaddress import IPv4Address
|
||||
import logging
|
||||
import os
|
||||
from pathlib import Path
|
||||
import re
|
||||
import secrets
|
||||
@ -24,7 +23,6 @@ from .const import (
|
||||
ATTR_AUDIO_OUTPUT,
|
||||
ATTR_BOOT,
|
||||
ATTR_IMAGE,
|
||||
ATTR_VERSION_LATEST,
|
||||
ATTR_PORT,
|
||||
ATTR_REFRESH_TOKEN,
|
||||
ATTR_SSL,
|
||||
@ -166,20 +164,12 @@ class HomeAssistant(JsonConfig, CoreSysAttributes):
|
||||
"""Return last available version of Home Assistant."""
|
||||
return self.sys_updater.version_homeassistant
|
||||
|
||||
@latest_version.setter
|
||||
def latest_version(self, value: str):
|
||||
"""Set last available version of Home Assistant."""
|
||||
if value:
|
||||
self._data[ATTR_VERSION_LATEST] = value
|
||||
else:
|
||||
self._data.pop(ATTR_VERSION_LATEST, None)
|
||||
|
||||
@property
|
||||
def image(self) -> str:
|
||||
"""Return image name of the Home Assistant container."""
|
||||
if self._data.get(ATTR_IMAGE):
|
||||
return self._data[ATTR_IMAGE]
|
||||
return os.environ["HOMEASSISTANT_REPOSITORY"]
|
||||
return f"homeassistant/{self.sys_machine}-homeassistant"
|
||||
|
||||
@image.setter
|
||||
def image(self, value: str) -> None:
|
||||
@ -262,12 +252,15 @@ class HomeAssistant(JsonConfig, CoreSysAttributes):
|
||||
_LOGGER.info("Setup HomeAssistant landingpage")
|
||||
while True:
|
||||
try:
|
||||
await self.instance.install("landingpage")
|
||||
await self.instance.install(
|
||||
"landingpage", image=self.sys_updater.image_homeassistant
|
||||
)
|
||||
except DockerAPIError:
|
||||
_LOGGER.warning("Fails install landingpage, retry after 30sec")
|
||||
await asyncio.sleep(30)
|
||||
else:
|
||||
self.version = self.instance.version
|
||||
self.image = self.sys_updater.image_homeassistant
|
||||
self.save_data()
|
||||
break
|
||||
|
||||
@ -288,14 +281,16 @@ class HomeAssistant(JsonConfig, CoreSysAttributes):
|
||||
tag = self.latest_version
|
||||
if tag:
|
||||
with suppress(DockerAPIError):
|
||||
await self.instance.update(tag)
|
||||
await self.instance.update(
|
||||
tag, image=self.sys_updater.image_homeassistant
|
||||
)
|
||||
break
|
||||
_LOGGER.warning("Error on install Home Assistant. Retry in 30sec")
|
||||
await asyncio.sleep(30)
|
||||
|
||||
_LOGGER.info("Home Assistant docker now installed")
|
||||
self.version = self.instance.version
|
||||
self.image = self.instance.image
|
||||
self.image = self.sys_updater.image_homeassistant
|
||||
self.save_data()
|
||||
|
||||
# finishing
|
||||
@ -313,6 +308,7 @@ class HomeAssistant(JsonConfig, CoreSysAttributes):
|
||||
async def update(self, version: Optional[str] = None) -> None:
|
||||
"""Update HomeAssistant version."""
|
||||
version = version or self.latest_version
|
||||
old_image = self.image
|
||||
rollback = self.version if not self.error_state else None
|
||||
running = await self.instance.is_running()
|
||||
exists = await self.instance.exists()
|
||||
@ -326,20 +322,24 @@ class HomeAssistant(JsonConfig, CoreSysAttributes):
|
||||
"""Run Home Assistant update."""
|
||||
_LOGGER.info("Update Home Assistant to version %s", to_version)
|
||||
try:
|
||||
await self.instance.update(to_version)
|
||||
await self.instance.update(
|
||||
to_version, image=self.sys_updater.image_homeassistant
|
||||
)
|
||||
except DockerAPIError:
|
||||
_LOGGER.warning("Update Home Assistant image fails")
|
||||
raise HomeAssistantUpdateError() from None
|
||||
else:
|
||||
self.version = self.instance.version
|
||||
self.image = self.sys_updater.image_homeassistant
|
||||
|
||||
if running:
|
||||
await self._start()
|
||||
|
||||
_LOGGER.info("Successful run Home Assistant %s", to_version)
|
||||
|
||||
# Successfull - last step
|
||||
self.save_data()
|
||||
with suppress(DockerAPIError):
|
||||
await self.instance.cleanup()
|
||||
await self.instance.cleanup(old_image=old_image)
|
||||
|
||||
# Update Home Assistant
|
||||
with suppress(HomeAssistantError):
|
||||
|
@ -127,6 +127,11 @@ class Ingress(JsonConfig, CoreSysAttributes):
|
||||
|
||||
async def update_hass_panel(self, addon: Addon):
|
||||
"""Return True if Home Assistant up and running."""
|
||||
if not await self.sys_homeassistant.is_running():
|
||||
_LOGGER.debug("Ignore panel update on Core")
|
||||
return
|
||||
|
||||
# Update UI
|
||||
method = "post" if addon.ingress_panel else "delete"
|
||||
async with self.sys_homeassistant.make_request(
|
||||
method, f"api/hassio_push/panel/{addon.slug}"
|
||||
|
@ -359,7 +359,7 @@ class Snapshot(CoreSysAttributes):
|
||||
"""Internal function to snapshot a folder."""
|
||||
slug_name = name.replace("/", "_")
|
||||
tar_name = Path(self._tmp.name, f"{slug_name}.tar.gz")
|
||||
origin_dir = Path(self.sys_config.path_hassio, name)
|
||||
origin_dir = Path(self.sys_config.path_supervisor, name)
|
||||
|
||||
# Check if exists
|
||||
if not origin_dir.is_dir():
|
||||
@ -396,7 +396,7 @@ class Snapshot(CoreSysAttributes):
|
||||
"""Intenal function to restore a folder."""
|
||||
slug_name = name.replace("/", "_")
|
||||
tar_name = Path(self._tmp.name, f"{slug_name}.tar.gz")
|
||||
origin_dir = Path(self.sys_config.path_hassio, name)
|
||||
origin_dir = Path(self.sys_config.path_supervisor, name)
|
||||
|
||||
# Check if exists inside snapshot
|
||||
if not tar_name.exists():
|
||||
|
@ -65,7 +65,7 @@ class Supervisor(CoreSysAttributes):
|
||||
@property
|
||||
def latest_version(self) -> str:
|
||||
"""Return last available version of Home Assistant."""
|
||||
return self.sys_updater.version_hassio
|
||||
return self.sys_updater.version_supervisor
|
||||
|
||||
@property
|
||||
def image(self) -> str:
|
||||
@ -115,7 +115,9 @@ class Supervisor(CoreSysAttributes):
|
||||
|
||||
_LOGGER.info("Update Supervisor to version %s", version)
|
||||
try:
|
||||
await self.instance.install(version, image=None, latest=True)
|
||||
await self.instance.install(
|
||||
version, image=self.sys_updater.image_supervisor, latest=True
|
||||
)
|
||||
except DockerAPIError:
|
||||
_LOGGER.error("Update of Supervisor fails!")
|
||||
raise SupervisorUpdateError() from None
|
||||
|
@ -13,9 +13,10 @@ from .const import (
|
||||
ATTR_CHANNEL,
|
||||
ATTR_CLI,
|
||||
ATTR_DNS,
|
||||
ATTR_HASSIO,
|
||||
ATTR_SUPERVISOR,
|
||||
ATTR_HASSOS,
|
||||
ATTR_HOMEASSISTANT,
|
||||
ATTR_IMAGE,
|
||||
FILE_HASSIO_UPDATER,
|
||||
URL_HASSIO_VERSION,
|
||||
UpdateChannels,
|
||||
@ -53,9 +54,9 @@ class Updater(JsonConfig, CoreSysAttributes):
|
||||
return self._data.get(ATTR_HOMEASSISTANT)
|
||||
|
||||
@property
|
||||
def version_hassio(self) -> Optional[str]:
|
||||
def version_supervisor(self) -> Optional[str]:
|
||||
"""Return latest version of Supervisor."""
|
||||
return self._data.get(ATTR_HASSIO)
|
||||
return self._data.get(ATTR_SUPERVISOR)
|
||||
|
||||
@property
|
||||
def version_hassos(self) -> Optional[str]:
|
||||
@ -77,6 +78,51 @@ class Updater(JsonConfig, CoreSysAttributes):
|
||||
"""Return latest version of Audio."""
|
||||
return self._data.get(ATTR_AUDIO)
|
||||
|
||||
@property
|
||||
def image_homeassistant(self) -> Optional[str]:
|
||||
"""Return latest version of Home Assistant."""
|
||||
return (
|
||||
self._data[ATTR_IMAGE]
|
||||
.get(ATTR_HOMEASSISTANT, "")
|
||||
.format(machine=self.sys_machine)
|
||||
)
|
||||
|
||||
@property
|
||||
def image_supervisor(self) -> Optional[str]:
|
||||
"""Return latest version of Supervisor."""
|
||||
return (
|
||||
self._data[ATTR_IMAGE]
|
||||
.get(ATTR_SUPERVISOR, "")
|
||||
.format(arch=self.sys_arch.supervisor)
|
||||
)
|
||||
|
||||
@property
|
||||
def image_cli(self) -> Optional[str]:
|
||||
"""Return latest version of CLI."""
|
||||
return (
|
||||
self._data[ATTR_IMAGE]
|
||||
.get(ATTR_CLI, "")
|
||||
.format(arch=self.sys_arch.supervisor)
|
||||
)
|
||||
|
||||
@property
|
||||
def image_dns(self) -> Optional[str]:
|
||||
"""Return latest version of DNS."""
|
||||
return (
|
||||
self._data[ATTR_IMAGE]
|
||||
.get(ATTR_DNS, "")
|
||||
.format(arch=self.sys_arch.supervisor)
|
||||
)
|
||||
|
||||
@property
|
||||
def image_audio(self) -> Optional[str]:
|
||||
"""Return latest version of Audio."""
|
||||
return (
|
||||
self._data[ATTR_IMAGE]
|
||||
.get(ATTR_AUDIO, "")
|
||||
.format(arch=self.sys_arch.supervisor)
|
||||
)
|
||||
|
||||
@property
|
||||
def channel(self) -> UpdateChannels:
|
||||
"""Return upstream channel of Supervisor instance."""
|
||||
@ -116,7 +162,7 @@ class Updater(JsonConfig, CoreSysAttributes):
|
||||
|
||||
try:
|
||||
# Update supervisor version
|
||||
self._data[ATTR_HASSIO] = data["supervisor"]
|
||||
self._data[ATTR_SUPERVISOR] = data["supervisor"]
|
||||
|
||||
# Update Home Assistant core version
|
||||
self._data[ATTR_HOMEASSISTANT] = data["homeassistant"][machine]
|
||||
@ -130,6 +176,13 @@ class Updater(JsonConfig, CoreSysAttributes):
|
||||
self._data[ATTR_DNS] = data["dns"]
|
||||
self._data[ATTR_AUDIO] = data["audio"]
|
||||
|
||||
# Update images for that versions
|
||||
self._data[ATTR_IMAGE][ATTR_HOMEASSISTANT] = data["image"]["core"]
|
||||
self._data[ATTR_IMAGE][ATTR_SUPERVISOR] = data["image"]["supervisor"]
|
||||
self._data[ATTR_IMAGE][ATTR_AUDIO] = data["image"]["audio"]
|
||||
self._data[ATTR_IMAGE][ATTR_CLI] = data["image"]["cli"]
|
||||
self._data[ATTR_IMAGE][ATTR_DNS] = data["image"]["dns"]
|
||||
|
||||
except KeyError as err:
|
||||
_LOGGER.warning("Can't process version data: %s", err)
|
||||
raise HassioUpdaterError() from None
|
||||
|
@ -17,7 +17,7 @@ from .const import (
|
||||
ATTR_DEBUG,
|
||||
ATTR_DEBUG_BLOCK,
|
||||
ATTR_DNS,
|
||||
ATTR_HASSIO,
|
||||
ATTR_SUPERVISOR,
|
||||
ATTR_HASSOS,
|
||||
ATTR_HOMEASSISTANT,
|
||||
ATTR_IMAGE,
|
||||
@ -124,11 +124,21 @@ SCHEMA_UPDATER_CONFIG = vol.Schema(
|
||||
UpdateChannels
|
||||
),
|
||||
vol.Optional(ATTR_HOMEASSISTANT): vol.Coerce(str),
|
||||
vol.Optional(ATTR_HASSIO): vol.Coerce(str),
|
||||
vol.Optional(ATTR_SUPERVISOR): vol.Coerce(str),
|
||||
vol.Optional(ATTR_HASSOS): vol.Coerce(str),
|
||||
vol.Optional(ATTR_CLI): vol.Coerce(str),
|
||||
vol.Optional(ATTR_DNS): vol.Coerce(str),
|
||||
vol.Optional(ATTR_AUDIO): vol.Coerce(str),
|
||||
vol.Optional(ATTR_IMAGE, default=dict): vol.Schema(
|
||||
{
|
||||
vol.Optional(ATTR_HOMEASSISTANT): docker_image,
|
||||
vol.Optional(ATTR_SUPERVISOR): docker_image,
|
||||
vol.Optional(ATTR_CLI): docker_image,
|
||||
vol.Optional(ATTR_DNS): docker_image,
|
||||
vol.Optional(ATTR_AUDIO): docker_image,
|
||||
},
|
||||
extra=vol.REMOVE_EXTRA,
|
||||
),
|
||||
},
|
||||
extra=vol.REMOVE_EXTRA,
|
||||
)
|
||||
|
Loading…
x
Reference in New Issue
Block a user