Cleanup API / old rebranding (#3623)

* Cleanup API / old rebranding

* cleanup p2

* next round

* better comments

* cleanup import

* support only installed add-ons

* legacy migration

* test fixes

* add old env back

* revert for Core

* fix issues with old core

* fix

* using installed short cat

* revert

* extend legacy

* cleanup

* fix path

* Fix missing

* add stop

* readd old token

* Add minimal

* extend attributes

* Add repo back

* add more repo info

* Make it working

* Bump frontend to e7848262 (#3680)

* Add icon

Co-authored-by: Joakim Sørensen <joasoe@gmail.com>
This commit is contained in:
Pascal Vizeli 2022-06-21 15:19:04 +02:00 committed by GitHub
parent acfa686bb6
commit e92d8695c7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
109 changed files with 242 additions and 398 deletions

@ -1 +1 @@
Subproject commit 4ad49ef07f65431d047094dda7eb6359fe4d8809 Subproject commit e7848262ea94af35a5333ce704385da511701240

View File

@ -84,8 +84,6 @@ RE_WATCHDOG = re.compile(
r":\/\/\[HOST\]:(?:\[PORT:)?(?P<t_port>\d+)\]?(?P<s_suffix>.*)$" r":\/\/\[HOST\]:(?:\[PORT:)?(?P<t_port>\d+)\]?(?P<s_suffix>.*)$"
) )
RE_OLD_AUDIO = re.compile(r"\d+,\d+")
WATCHDOG_TIMEOUT = aiohttp.ClientTimeout(total=10) WATCHDOG_TIMEOUT = aiohttp.ClientTimeout(total=10)
_OPTIONS_MERGER: Final = Merger( _OPTIONS_MERGER: Final = Merger(
@ -367,13 +365,7 @@ class Addon(AddonModel):
"""Return a pulse profile for output or None.""" """Return a pulse profile for output or None."""
if not self.with_audio: if not self.with_audio:
return None return None
return self.persist.get(ATTR_AUDIO_OUTPUT)
# Fallback with old audio settings
# Remove after 210
output_data = self.persist.get(ATTR_AUDIO_OUTPUT)
if output_data and RE_OLD_AUDIO.fullmatch(output_data):
return None
return output_data
@audio_output.setter @audio_output.setter
def audio_output(self, value: Optional[str]): def audio_output(self, value: Optional[str]):
@ -386,12 +378,7 @@ class Addon(AddonModel):
if not self.with_audio: if not self.with_audio:
return None return None
# Fallback with old audio settings return self.persist.get(ATTR_AUDIO_INPUT)
# Remove after 210
input_data = self.persist.get(ATTR_AUDIO_INPUT)
if input_data and RE_OLD_AUDIO.fullmatch(input_data):
return None
return input_data
@audio_input.setter @audio_input.setter
def audio_input(self, value: Optional[str]) -> None: def audio_input(self, value: Optional[str]) -> None:

View File

@ -240,7 +240,7 @@ class RestAPI(CoreSysAttributes):
[web.get("/available_updates", api_root.available_updates)] [web.get("/available_updates", api_root.available_updates)]
) )
# Remove 2023 # Remove: 2023
self.webapp.add_routes( self.webapp.add_routes(
[web.get("/supervisor/available_updates", api_root.available_updates)] [web.get("/supervisor/available_updates", api_root.available_updates)]
) )
@ -323,17 +323,22 @@ class RestAPI(CoreSysAttributes):
web.post("/core/start", api_hass.start), web.post("/core/start", api_hass.start),
web.post("/core/check", api_hass.check), web.post("/core/check", api_hass.check),
web.post("/core/rebuild", api_hass.rebuild), web.post("/core/rebuild", api_hass.rebuild),
# Remove with old Supervisor fallback ]
)
# Reroute from legacy
self.webapp.add_routes(
[
web.get("/homeassistant/info", api_hass.info), web.get("/homeassistant/info", api_hass.info),
web.get("/homeassistant/logs", api_hass.logs), web.get("/homeassistant/logs", api_hass.logs),
web.get("/homeassistant/stats", api_hass.stats), web.get("/homeassistant/stats", api_hass.stats),
web.post("/homeassistant/options", api_hass.options), web.post("/homeassistant/options", api_hass.options),
web.post("/homeassistant/update", api_hass.update),
web.post("/homeassistant/restart", api_hass.restart), web.post("/homeassistant/restart", api_hass.restart),
web.post("/homeassistant/stop", api_hass.stop), web.post("/homeassistant/stop", api_hass.stop),
web.post("/homeassistant/start", api_hass.start), web.post("/homeassistant/start", api_hass.start),
web.post("/homeassistant/check", api_hass.check), web.post("/homeassistant/update", api_hass.update),
web.post("/homeassistant/rebuild", api_hass.rebuild), web.post("/homeassistant/rebuild", api_hass.rebuild),
web.post("/homeassistant/check", api_hass.check),
] ]
) )
@ -350,7 +355,12 @@ class RestAPI(CoreSysAttributes):
web.post("/core/api/{path:.+}", api_proxy.api), web.post("/core/api/{path:.+}", api_proxy.api),
web.get("/core/api/{path:.+}", api_proxy.api), web.get("/core/api/{path:.+}", api_proxy.api),
web.get("/core/api/", api_proxy.api), web.get("/core/api/", api_proxy.api),
# Remove with old Supervisor fallback ]
)
# Reroute from legacy
self.webapp.add_routes(
[
web.get("/homeassistant/api/websocket", api_proxy.websocket), web.get("/homeassistant/api/websocket", api_proxy.websocket),
web.get("/homeassistant/websocket", api_proxy.websocket), web.get("/homeassistant/websocket", api_proxy.websocket),
web.get("/homeassistant/api/stream", api_proxy.stream), web.get("/homeassistant/api/stream", api_proxy.stream),
@ -368,7 +378,6 @@ class RestAPI(CoreSysAttributes):
self.webapp.add_routes( self.webapp.add_routes(
[ [
web.get("/addons", api_addons.list), web.get("/addons", api_addons.list),
web.post("/addons/reload", api_addons.reload),
web.get("/addons/{addon}/info", api_addons.info), web.get("/addons/{addon}/info", api_addons.info),
web.post("/addons/{addon}/uninstall", api_addons.uninstall), web.post("/addons/{addon}/uninstall", api_addons.uninstall),
web.post("/addons/{addon}/start", api_addons.start), web.post("/addons/{addon}/start", api_addons.start),
@ -381,10 +390,6 @@ class RestAPI(CoreSysAttributes):
web.get("/addons/{addon}/options/config", api_addons.options_config), web.get("/addons/{addon}/options/config", api_addons.options_config),
web.post("/addons/{addon}/rebuild", api_addons.rebuild), web.post("/addons/{addon}/rebuild", api_addons.rebuild),
web.get("/addons/{addon}/logs", api_addons.logs), web.get("/addons/{addon}/logs", api_addons.logs),
web.get("/addons/{addon}/icon", api_addons.icon),
web.get("/addons/{addon}/logo", api_addons.logo),
web.get("/addons/{addon}/changelog", api_addons.changelog),
web.get("/addons/{addon}/documentation", api_addons.documentation),
web.post("/addons/{addon}/stdin", api_addons.stdin), web.post("/addons/{addon}/stdin", api_addons.stdin),
web.post("/addons/{addon}/security", api_addons.security), web.post("/addons/{addon}/security", api_addons.security),
web.get("/addons/{addon}/stats", api_addons.stats), web.get("/addons/{addon}/stats", api_addons.stats),
@ -412,21 +417,6 @@ class RestAPI(CoreSysAttributes):
self.webapp.add_routes( self.webapp.add_routes(
[ [
web.get("/snapshots", api_backups.list),
web.post("/snapshots/reload", api_backups.reload),
web.post("/snapshots/new/full", api_backups.backup_full),
web.post("/snapshots/new/partial", api_backups.backup_partial),
web.post("/snapshots/new/upload", api_backups.upload),
web.get("/snapshots/{slug}/info", api_backups.info),
web.delete("/snapshots/{slug}", api_backups.remove),
web.post("/snapshots/{slug}/restore/full", api_backups.restore_full),
web.post(
"/snapshots/{slug}/restore/partial",
api_backups.restore_partial,
),
web.get("/snapshots/{slug}/download", api_backups.download),
web.post("/snapshots/{slug}/remove", api_backups.remove),
# June 2021: /snapshots was renamed to /backups
web.get("/backups", api_backups.list), web.get("/backups", api_backups.list),
web.post("/backups/reload", api_backups.reload), web.post("/backups/reload", api_backups.reload),
web.post("/backups/new/full", api_backups.backup_full), web.post("/backups/new/full", api_backups.backup_full),
@ -521,6 +511,15 @@ class RestAPI(CoreSysAttributes):
web.get("/store/addons", api_store.addons_list), web.get("/store/addons", api_store.addons_list),
web.get("/store/addons/{addon}", api_store.addons_addon_info), web.get("/store/addons/{addon}", api_store.addons_addon_info),
web.get("/store/addons/{addon}/{version}", api_store.addons_addon_info), web.get("/store/addons/{addon}/{version}", api_store.addons_addon_info),
web.get("/store/addons/{addon}/icon", api_store.addons_addon_icon),
web.get("/store/addons/{addon}/logo", api_store.addons_addon_logo),
web.get(
"/store/addons/{addon}/changelog", api_store.addons_addon_changelog
),
web.get(
"/store/addons/{addon}/documentation",
api_store.addons_addon_documentation,
),
web.post( web.post(
"/store/addons/{addon}/install", api_store.addons_addon_install "/store/addons/{addon}/install", api_store.addons_addon_install
), ),
@ -549,8 +548,16 @@ class RestAPI(CoreSysAttributes):
# Reroute from legacy # Reroute from legacy
self.webapp.add_routes( self.webapp.add_routes(
[ [
web.post("/addons/reload", api_store.reload),
web.post("/addons/{addon}/install", api_store.addons_addon_install), web.post("/addons/{addon}/install", api_store.addons_addon_install),
web.post("/addons/{addon}/update", api_store.addons_addon_update), web.post("/addons/{addon}/update", api_store.addons_addon_update),
web.get("/addons/{addon}/icon", api_store.addons_addon_icon),
web.get("/addons/{addon}/logo", api_store.addons_addon_logo),
web.get("/addons/{addon}/changelog", api_store.addons_addon_changelog),
web.get(
"/addons/{addon}/documentation",
api_store.addons_addon_documentation,
),
] ]
) )

View File

@ -58,7 +58,6 @@ from ..const import (
ATTR_LOGO, ATTR_LOGO,
ATTR_LONG_DESCRIPTION, ATTR_LONG_DESCRIPTION,
ATTR_MACHINE, ATTR_MACHINE,
ATTR_MAINTAINER,
ATTR_MEMORY_LIMIT, ATTR_MEMORY_LIMIT,
ATTR_MEMORY_PERCENT, ATTR_MEMORY_PERCENT,
ATTR_MEMORY_USAGE, ATTR_MEMORY_USAGE,
@ -73,12 +72,10 @@ from ..const import (
ATTR_PROTECTED, ATTR_PROTECTED,
ATTR_PWNED, ATTR_PWNED,
ATTR_RATING, ATTR_RATING,
ATTR_REPOSITORIES,
ATTR_REPOSITORY, ATTR_REPOSITORY,
ATTR_SCHEMA, ATTR_SCHEMA,
ATTR_SERVICES, ATTR_SERVICES,
ATTR_SLUG, ATTR_SLUG,
ATTR_SOURCE,
ATTR_STAGE, ATTR_STAGE,
ATTR_STARTUP, ATTR_STARTUP,
ATTR_STATE, ATTR_STATE,
@ -95,18 +92,14 @@ from ..const import (
ATTR_VIDEO, ATTR_VIDEO,
ATTR_WATCHDOG, ATTR_WATCHDOG,
ATTR_WEBUI, ATTR_WEBUI,
CONTENT_TYPE_BINARY,
CONTENT_TYPE_PNG,
CONTENT_TYPE_TEXT,
REQUEST_FROM, REQUEST_FROM,
AddonBoot, AddonBoot,
AddonState,
) )
from ..coresys import CoreSysAttributes from ..coresys import CoreSysAttributes
from ..docker.stats import DockerStats from ..docker.stats import DockerStats
from ..exceptions import APIError, APIForbidden, PwnedError, PwnedSecret from ..exceptions import APIError, APIForbidden, PwnedError, PwnedSecret
from ..validate import docker_ports from ..validate import docker_ports
from .const import ATTR_SIGNED from .const import ATTR_SIGNED, CONTENT_TYPE_BINARY
from .utils import api_process, api_process_raw, api_validate, json_loads from .utils import api_process, api_process_raw, api_validate, json_loads
_LOGGER: logging.Logger = logging.getLogger(__name__) _LOGGER: logging.Logger = logging.getLogger(__name__)
@ -133,7 +126,7 @@ SCHEMA_SECURITY = vol.Schema({vol.Optional(ATTR_PROTECTED): vol.Boolean()})
class APIAddons(CoreSysAttributes): class APIAddons(CoreSysAttributes):
"""Handle RESTful API for add-on functions.""" """Handle RESTful API for add-on functions."""
def _extract_addon(self, request: web.Request) -> AnyAddon: def _extract_addon(self, request: web.Request) -> Addon:
"""Return addon, throw an exception it it doesn't exist.""" """Return addon, throw an exception it it doesn't exist."""
addon_slug: str = request.match_info.get("addon") addon_slug: str = request.match_info.get("addon")
@ -147,13 +140,9 @@ class APIAddons(CoreSysAttributes):
addon = self.sys_addons.get(addon_slug) addon = self.sys_addons.get(addon_slug)
if not addon: if not addon:
raise APIError(f"Addon {addon_slug} does not exist") raise APIError(f"Addon {addon_slug} does not exist")
return addon
def _extract_addon_installed(self, request: web.Request) -> Addon:
addon = self._extract_addon(request)
if not isinstance(addon, Addon) or not addon.is_installed: if not isinstance(addon, Addon) or not addon.is_installed:
raise APIError("Addon is not installed") raise APIError("Addon is not installed")
return addon return addon
@api_process @api_process
@ -166,11 +155,9 @@ class APIAddons(CoreSysAttributes):
ATTR_DESCRIPTON: addon.description, ATTR_DESCRIPTON: addon.description,
ATTR_ADVANCED: addon.advanced, ATTR_ADVANCED: addon.advanced,
ATTR_STAGE: addon.stage, ATTR_STAGE: addon.stage,
ATTR_VERSION: addon.version if addon.is_installed else None, ATTR_VERSION: addon.version,
ATTR_VERSION_LATEST: addon.latest_version, ATTR_VERSION_LATEST: addon.latest_version,
ATTR_UPDATE_AVAILABLE: addon.need_update ATTR_UPDATE_AVAILABLE: addon.need_update,
if addon.is_installed
else False,
ATTR_INSTALLED: addon.is_installed, ATTR_INSTALLED: addon.is_installed,
ATTR_AVAILABLE: addon.available, ATTR_AVAILABLE: addon.available,
ATTR_DETACHED: addon.is_detached, ATTR_DETACHED: addon.is_detached,
@ -181,20 +168,10 @@ class APIAddons(CoreSysAttributes):
ATTR_ICON: addon.with_icon, ATTR_ICON: addon.with_icon,
ATTR_LOGO: addon.with_logo, ATTR_LOGO: addon.with_logo,
} }
for addon in self.sys_addons.all for addon in self.sys_addons.installed
] ]
data_repositories = [ return {ATTR_ADDONS: data_addons}
{
ATTR_SLUG: repository.slug,
ATTR_NAME: repository.name,
ATTR_SOURCE: repository.source,
ATTR_URL: repository.url,
ATTR_MAINTAINER: repository.maintainer,
}
for repository in self.sys_store.all
]
return {ATTR_ADDONS: data_addons, ATTR_REPOSITORIES: data_repositories}
@api_process @api_process
async def reload(self, request: web.Request) -> None: async def reload(self, request: web.Request) -> None:
@ -215,11 +192,8 @@ class APIAddons(CoreSysAttributes):
ATTR_LONG_DESCRIPTION: addon.long_description, ATTR_LONG_DESCRIPTION: addon.long_description,
ATTR_ADVANCED: addon.advanced, ATTR_ADVANCED: addon.advanced,
ATTR_STAGE: addon.stage, ATTR_STAGE: addon.stage,
ATTR_AUTO_UPDATE: None,
ATTR_REPOSITORY: addon.repository, ATTR_REPOSITORY: addon.repository,
ATTR_VERSION: None,
ATTR_VERSION_LATEST: addon.latest_version, ATTR_VERSION_LATEST: addon.latest_version,
ATTR_UPDATE_AVAILABLE: False,
ATTR_PROTECTED: addon.protected, ATTR_PROTECTED: addon.protected,
ATTR_RATING: rating_security(addon), ATTR_RATING: rating_security(addon),
ATTR_BOOT: addon.boot, ATTR_BOOT: addon.boot,
@ -229,7 +203,6 @@ class APIAddons(CoreSysAttributes):
ATTR_MACHINE: addon.supported_machine, ATTR_MACHINE: addon.supported_machine,
ATTR_HOMEASSISTANT: addon.homeassistant_version, ATTR_HOMEASSISTANT: addon.homeassistant_version,
ATTR_URL: addon.url, ATTR_URL: addon.url,
ATTR_STATE: AddonState.UNKNOWN,
ATTR_DETACHED: addon.is_detached, ATTR_DETACHED: addon.is_detached,
ATTR_AVAILABLE: addon.available, ATTR_AVAILABLE: addon.available,
ATTR_BUILD: addon.need_build, ATTR_BUILD: addon.need_build,
@ -242,13 +215,11 @@ class APIAddons(CoreSysAttributes):
ATTR_PRIVILEGED: addon.privileged, ATTR_PRIVILEGED: addon.privileged,
ATTR_FULL_ACCESS: addon.with_full_access, ATTR_FULL_ACCESS: addon.with_full_access,
ATTR_APPARMOR: addon.apparmor, ATTR_APPARMOR: addon.apparmor,
ATTR_DEVICES: addon.static_devices,
ATTR_ICON: addon.with_icon, ATTR_ICON: addon.with_icon,
ATTR_LOGO: addon.with_logo, ATTR_LOGO: addon.with_logo,
ATTR_CHANGELOG: addon.with_changelog, ATTR_CHANGELOG: addon.with_changelog,
ATTR_DOCUMENTATION: addon.with_documentation, ATTR_DOCUMENTATION: addon.with_documentation,
ATTR_STDIN: addon.with_stdin, ATTR_STDIN: addon.with_stdin,
ATTR_WEBUI: None,
ATTR_HASSIO_API: addon.access_hassio_api, ATTR_HASSIO_API: addon.access_hassio_api,
ATTR_HASSIO_ROLE: addon.hassio_role, ATTR_HASSIO_ROLE: addon.hassio_role,
ATTR_AUTH_API: addon.access_auth_api, ATTR_AUTH_API: addon.access_auth_api,
@ -262,49 +233,35 @@ class APIAddons(CoreSysAttributes):
ATTR_DOCKER_API: addon.access_docker_api, ATTR_DOCKER_API: addon.access_docker_api,
ATTR_VIDEO: addon.with_video, ATTR_VIDEO: addon.with_video,
ATTR_AUDIO: addon.with_audio, ATTR_AUDIO: addon.with_audio,
ATTR_AUDIO_INPUT: None,
ATTR_AUDIO_OUTPUT: None,
ATTR_STARTUP: addon.startup, ATTR_STARTUP: addon.startup,
ATTR_SERVICES: _pretty_services(addon), ATTR_SERVICES: _pretty_services(addon),
ATTR_DISCOVERY: addon.discovery, ATTR_DISCOVERY: addon.discovery,
ATTR_IP_ADDRESS: None,
ATTR_TRANSLATIONS: addon.translations, ATTR_TRANSLATIONS: addon.translations,
ATTR_INGRESS: addon.with_ingress, ATTR_INGRESS: addon.with_ingress,
ATTR_SIGNED: addon.signed, ATTR_SIGNED: addon.signed,
ATTR_INGRESS_ENTRY: None, ATTR_STATE: addon.state,
ATTR_INGRESS_URL: None, ATTR_WEBUI: addon.webui,
ATTR_INGRESS_PORT: None, ATTR_INGRESS_ENTRY: addon.ingress_entry,
ATTR_INGRESS_PANEL: None, ATTR_INGRESS_URL: addon.ingress_url,
ATTR_WATCHDOG: None, ATTR_INGRESS_PORT: addon.ingress_port,
ATTR_INGRESS_PANEL: addon.ingress_panel,
ATTR_AUDIO_INPUT: addon.audio_input,
ATTR_AUDIO_OUTPUT: addon.audio_output,
ATTR_AUTO_UPDATE: addon.auto_update,
ATTR_IP_ADDRESS: str(addon.ip_address),
ATTR_VERSION: addon.version,
ATTR_UPDATE_AVAILABLE: addon.need_update,
ATTR_WATCHDOG: addon.watchdog,
ATTR_DEVICES: addon.static_devices
+ [device.path for device in addon.devices],
} }
if isinstance(addon, Addon) and addon.is_installed:
data.update(
{
ATTR_STATE: addon.state,
ATTR_WEBUI: addon.webui,
ATTR_INGRESS_ENTRY: addon.ingress_entry,
ATTR_INGRESS_URL: addon.ingress_url,
ATTR_INGRESS_PORT: addon.ingress_port,
ATTR_INGRESS_PANEL: addon.ingress_panel,
ATTR_AUDIO_INPUT: addon.audio_input,
ATTR_AUDIO_OUTPUT: addon.audio_output,
ATTR_AUTO_UPDATE: addon.auto_update,
ATTR_IP_ADDRESS: str(addon.ip_address),
ATTR_VERSION: addon.version,
ATTR_UPDATE_AVAILABLE: addon.need_update,
ATTR_WATCHDOG: addon.watchdog,
ATTR_DEVICES: addon.static_devices
+ [device.path for device in addon.devices],
}
)
return data return data
@api_process @api_process
async def options(self, request: web.Request) -> None: async def options(self, request: web.Request) -> None:
"""Store user options for add-on.""" """Store user options for add-on."""
addon = self._extract_addon_installed(request) addon = self._extract_addon(request)
# Update secrets for validation # Update secrets for validation
await self.sys_homeassistant.secrets.reload() await self.sys_homeassistant.secrets.reload()
@ -339,7 +296,7 @@ class APIAddons(CoreSysAttributes):
@api_process @api_process
async def options_validate(self, request: web.Request) -> None: async def options_validate(self, request: web.Request) -> None:
"""Validate user options for add-on.""" """Validate user options for add-on."""
addon = self._extract_addon_installed(request) addon = self._extract_addon(request)
data = {ATTR_MESSAGE: "", ATTR_VALID: True, ATTR_PWNED: False} data = {ATTR_MESSAGE: "", ATTR_VALID: True, ATTR_PWNED: False}
options = await request.json(loads=json_loads) or addon.options options = await request.json(loads=json_loads) or addon.options
@ -381,7 +338,7 @@ class APIAddons(CoreSysAttributes):
slug: str = request.match_info.get("addon") slug: str = request.match_info.get("addon")
if slug != "self": if slug != "self":
raise APIForbidden("This can be only read by the Add-on itself!") raise APIForbidden("This can be only read by the Add-on itself!")
addon = self._extract_addon_installed(request) addon = self._extract_addon(request)
# Lookup/reload secrets # Lookup/reload secrets
await self.sys_homeassistant.secrets.reload() await self.sys_homeassistant.secrets.reload()
@ -393,7 +350,7 @@ class APIAddons(CoreSysAttributes):
@api_process @api_process
async def security(self, request: web.Request) -> None: async def security(self, request: web.Request) -> None:
"""Store security options for add-on.""" """Store security options for add-on."""
addon = self._extract_addon_installed(request) addon = self._extract_addon(request)
body: dict[str, Any] = await api_validate(SCHEMA_SECURITY, request) body: dict[str, Any] = await api_validate(SCHEMA_SECURITY, request)
if ATTR_PROTECTED in body: if ATTR_PROTECTED in body:
@ -405,7 +362,7 @@ class APIAddons(CoreSysAttributes):
@api_process @api_process
async def stats(self, request: web.Request) -> dict[str, Any]: async def stats(self, request: web.Request) -> dict[str, Any]:
"""Return resource information.""" """Return resource information."""
addon = self._extract_addon_installed(request) addon = self._extract_addon(request)
stats: DockerStats = await addon.stats() stats: DockerStats = await addon.stats()
@ -423,83 +380,43 @@ class APIAddons(CoreSysAttributes):
@api_process @api_process
def uninstall(self, request: web.Request) -> Awaitable[None]: def uninstall(self, request: web.Request) -> Awaitable[None]:
"""Uninstall add-on.""" """Uninstall add-on."""
addon = self._extract_addon_installed(request) addon = self._extract_addon(request)
return asyncio.shield(addon.uninstall()) return asyncio.shield(addon.uninstall())
@api_process @api_process
def start(self, request: web.Request) -> Awaitable[None]: def start(self, request: web.Request) -> Awaitable[None]:
"""Start add-on.""" """Start add-on."""
addon = self._extract_addon_installed(request) addon = self._extract_addon(request)
return asyncio.shield(addon.start()) return asyncio.shield(addon.start())
@api_process @api_process
def stop(self, request: web.Request) -> Awaitable[None]: def stop(self, request: web.Request) -> Awaitable[None]:
"""Stop add-on.""" """Stop add-on."""
addon = self._extract_addon_installed(request) addon = self._extract_addon(request)
return asyncio.shield(addon.stop()) return asyncio.shield(addon.stop())
@api_process @api_process
def restart(self, request: web.Request) -> Awaitable[None]: def restart(self, request: web.Request) -> Awaitable[None]:
"""Restart add-on.""" """Restart add-on."""
addon: Addon = self._extract_addon_installed(request) addon: Addon = self._extract_addon(request)
return asyncio.shield(addon.restart()) return asyncio.shield(addon.restart())
@api_process @api_process
def rebuild(self, request: web.Request) -> Awaitable[None]: def rebuild(self, request: web.Request) -> Awaitable[None]:
"""Rebuild local build add-on.""" """Rebuild local build add-on."""
addon = self._extract_addon_installed(request) addon = self._extract_addon(request)
return asyncio.shield(addon.rebuild()) return asyncio.shield(addon.rebuild())
@api_process_raw(CONTENT_TYPE_BINARY) @api_process_raw(CONTENT_TYPE_BINARY)
def logs(self, request: web.Request) -> Awaitable[bytes]: def logs(self, request: web.Request) -> Awaitable[bytes]:
"""Return logs from add-on.""" """Return logs from add-on."""
addon = self._extract_addon_installed(request) addon = self._extract_addon(request)
return addon.logs() return addon.logs()
@api_process_raw(CONTENT_TYPE_PNG)
async def icon(self, request: web.Request) -> bytes:
"""Return icon from add-on."""
addon = self._extract_addon(request)
if not addon.with_icon:
raise APIError(f"No icon found for add-on {addon.slug}!")
with addon.path_icon.open("rb") as png:
return png.read()
@api_process_raw(CONTENT_TYPE_PNG)
async def logo(self, request: web.Request) -> bytes:
"""Return logo from add-on."""
addon = self._extract_addon(request)
if not addon.with_logo:
raise APIError(f"No logo found for add-on {addon.slug}!")
with addon.path_logo.open("rb") as png:
return png.read()
@api_process_raw(CONTENT_TYPE_TEXT)
async def changelog(self, request: web.Request) -> str:
"""Return changelog from add-on."""
addon = self._extract_addon(request)
if not addon.with_changelog:
raise APIError(f"No changelog found for add-on {addon.slug}!")
with addon.path_changelog.open("r") as changelog:
return changelog.read()
@api_process_raw(CONTENT_TYPE_TEXT)
async def documentation(self, request: web.Request) -> str:
"""Return documentation from add-on."""
addon = self._extract_addon(request)
if not addon.with_documentation:
raise APIError(f"No documentation found for add-on {addon.slug}!")
with addon.path_documentation.open("r") as documentation:
return documentation.read()
@api_process @api_process
async def stdin(self, request: web.Request) -> None: async def stdin(self, request: web.Request) -> None:
"""Write to stdin of add-on.""" """Write to stdin of add-on."""
addon = self._extract_addon_installed(request) addon = self._extract_addon(request)
if not addon.with_stdin: if not addon.with_stdin:
raise APIError(f"STDIN not supported the {addon.slug} add-on") raise APIError(f"STDIN not supported the {addon.slug} add-on")
@ -507,6 +424,6 @@ class APIAddons(CoreSysAttributes):
await asyncio.shield(addon.write_stdin(data)) await asyncio.shield(addon.write_stdin(data))
def _pretty_services(addon: AnyAddon) -> list[str]: def _pretty_services(addon: Addon) -> list[str]:
"""Return a simplified services role list.""" """Return a simplified services role list."""
return [f"{name}:{access}" for name, access in addon.services_role.items()] return [f"{name}:{access}" for name, access in addon.services_role.items()]

View File

@ -29,12 +29,12 @@ from ..const import (
ATTR_VERSION, ATTR_VERSION,
ATTR_VERSION_LATEST, ATTR_VERSION_LATEST,
ATTR_VOLUME, ATTR_VOLUME,
CONTENT_TYPE_BINARY,
) )
from ..coresys import CoreSysAttributes from ..coresys import CoreSysAttributes
from ..exceptions import APIError from ..exceptions import APIError
from ..host.sound import StreamType from ..host.sound import StreamType
from ..validate import version_tag from ..validate import version_tag
from .const import CONTENT_TYPE_BINARY
from .utils import api_process, api_process_raw, api_validate from .utils import api_process, api_process_raw, api_validate
_LOGGER: logging.Logger = logging.getLogger(__name__) _LOGGER: logging.Logger = logging.getLogger(__name__)

View File

@ -8,15 +8,10 @@ from aiohttp.web_exceptions import HTTPUnauthorized
import voluptuous as vol import voluptuous as vol
from ..addons.addon import Addon from ..addons.addon import Addon
from ..const import ( from ..const import ATTR_PASSWORD, ATTR_USERNAME, REQUEST_FROM
ATTR_PASSWORD,
ATTR_USERNAME,
CONTENT_TYPE_JSON,
CONTENT_TYPE_URL,
REQUEST_FROM,
)
from ..coresys import CoreSysAttributes from ..coresys import CoreSysAttributes
from ..exceptions import APIForbidden from ..exceptions import APIForbidden
from .const import CONTENT_TYPE_JSON, CONTENT_TYPE_URL
from .utils import api_process, api_validate from .utils import api_process, api_validate
_LOGGER: logging.Logger = logging.getLogger(__name__) _LOGGER: logging.Logger = logging.getLogger(__name__)

View File

@ -26,17 +26,18 @@ from ..const import (
ATTR_SLUG, ATTR_SLUG,
ATTR_TYPE, ATTR_TYPE,
ATTR_VERSION, ATTR_VERSION,
CONTENT_TYPE_TAR,
) )
from ..coresys import CoreSysAttributes from ..coresys import CoreSysAttributes
from ..exceptions import APIError from ..exceptions import APIError
from .const import CONTENT_TYPE_TAR
from .utils import api_process, api_validate from .utils import api_process, api_validate
_LOGGER: logging.Logger = logging.getLogger(__name__) _LOGGER: logging.Logger = logging.getLogger(__name__)
RE_SLUGIFY_NAME = re.compile(r"[^A-Za-z0-9]+") RE_SLUGIFY_NAME = re.compile(r"[^A-Za-z0-9]+")
# Backwards compatible / Remove 2022.08 # Backwards compatible
# Remove: 2022.08
_ALL_FOLDERS = ALL_FOLDERS + [FOLDER_HOMEASSISTANT] _ALL_FOLDERS = ALL_FOLDERS + [FOLDER_HOMEASSISTANT]
# pylint: disable=no-value-for-parameter # pylint: disable=no-value-for-parameter

View File

@ -1,5 +1,17 @@
"""Const for API.""" """Const for API."""
CONTENT_TYPE_BINARY = "application/octet-stream"
CONTENT_TYPE_JSON = "application/json"
CONTENT_TYPE_PNG = "image/png"
CONTENT_TYPE_TAR = "application/tar"
CONTENT_TYPE_TEXT = "text/plain"
CONTENT_TYPE_URL = "application/x-www-form-urlencoded"
COOKIE_INGRESS = "ingress_session"
HEADER_TOKEN_OLD = "X-Hassio-Key"
HEADER_TOKEN = "X-Supervisor-Token"
ATTR_APPARMOR_VERSION = "apparmor_version" ATTR_APPARMOR_VERSION = "apparmor_version"
ATTR_AGENT_VERSION = "agent_version" ATTR_AGENT_VERSION = "agent_version"
ATTR_AVAILABLE_UPDATES = "available_updates" ATTR_AVAILABLE_UPDATES = "available_updates"
@ -19,4 +31,3 @@ ATTR_SIGNED = "signed"
ATTR_STARTUP_TIME = "startup_time" ATTR_STARTUP_TIME = "startup_time"
ATTR_UPDATE_TYPE = "update_type" ATTR_UPDATE_TYPE = "update_type"
ATTR_USE_NTP = "use_ntp" ATTR_USE_NTP = "use_ntp"
ATTR_USE_RTC = "use_rtc"

View File

@ -21,12 +21,11 @@ from ..const import (
ATTR_UPDATE_AVAILABLE, ATTR_UPDATE_AVAILABLE,
ATTR_VERSION, ATTR_VERSION,
ATTR_VERSION_LATEST, ATTR_VERSION_LATEST,
CONTENT_TYPE_BINARY,
) )
from ..coresys import CoreSysAttributes from ..coresys import CoreSysAttributes
from ..exceptions import APIError from ..exceptions import APIError
from ..validate import dns_server_list, version_tag from ..validate import dns_server_list, version_tag
from .const import ATTR_FALLBACK, ATTR_LLMNR, ATTR_MDNS from .const import ATTR_FALLBACK, ATTR_LLMNR, ATTR_MDNS, CONTENT_TYPE_BINARY
from .utils import api_process, api_process_raw, api_validate from .utils import api_process, api_process_raw, api_validate
_LOGGER: logging.Logger = logging.getLogger(__name__) _LOGGER: logging.Logger = logging.getLogger(__name__)

View File

@ -29,13 +29,12 @@ from ..const import (
ATTR_UPDATE_AVAILABLE, ATTR_UPDATE_AVAILABLE,
ATTR_VERSION, ATTR_VERSION,
ATTR_VERSION_LATEST, ATTR_VERSION_LATEST,
ATTR_WAIT_BOOT,
ATTR_WATCHDOG, ATTR_WATCHDOG,
CONTENT_TYPE_BINARY,
) )
from ..coresys import CoreSysAttributes from ..coresys import CoreSysAttributes
from ..exceptions import APIError from ..exceptions import APIError
from ..validate import docker_image, network_port, version_tag from ..validate import docker_image, network_port, version_tag
from .const import CONTENT_TYPE_BINARY
from .utils import api_process, api_process_raw, api_validate from .utils import api_process, api_process_raw, api_validate
_LOGGER: logging.Logger = logging.getLogger(__name__) _LOGGER: logging.Logger = logging.getLogger(__name__)
@ -48,7 +47,6 @@ SCHEMA_OPTIONS = vol.Schema(
vol.Optional(ATTR_PORT): network_port, vol.Optional(ATTR_PORT): network_port,
vol.Optional(ATTR_SSL): vol.Boolean(), vol.Optional(ATTR_SSL): vol.Boolean(),
vol.Optional(ATTR_WATCHDOG): vol.Boolean(), vol.Optional(ATTR_WATCHDOG): vol.Boolean(),
vol.Optional(ATTR_WAIT_BOOT): vol.All(vol.Coerce(int), vol.Range(min=60)),
vol.Optional(ATTR_REFRESH_TOKEN): vol.Maybe(str), vol.Optional(ATTR_REFRESH_TOKEN): vol.Maybe(str),
vol.Optional(ATTR_AUDIO_OUTPUT): vol.Maybe(str), vol.Optional(ATTR_AUDIO_OUTPUT): vol.Maybe(str),
vol.Optional(ATTR_AUDIO_INPUT): vol.Maybe(str), vol.Optional(ATTR_AUDIO_INPUT): vol.Maybe(str),
@ -81,11 +79,8 @@ class APIHomeAssistant(CoreSysAttributes):
ATTR_PORT: self.sys_homeassistant.api_port, ATTR_PORT: self.sys_homeassistant.api_port,
ATTR_SSL: self.sys_homeassistant.api_ssl, ATTR_SSL: self.sys_homeassistant.api_ssl,
ATTR_WATCHDOG: self.sys_homeassistant.watchdog, ATTR_WATCHDOG: self.sys_homeassistant.watchdog,
ATTR_WAIT_BOOT: self.sys_homeassistant.wait_boot,
ATTR_AUDIO_INPUT: self.sys_homeassistant.audio_input, ATTR_AUDIO_INPUT: self.sys_homeassistant.audio_input,
ATTR_AUDIO_OUTPUT: self.sys_homeassistant.audio_output, ATTR_AUDIO_OUTPUT: self.sys_homeassistant.audio_output,
# Remove end of Q3 2020
"last_version": self.sys_homeassistant.latest_version,
} }
@api_process @api_process
@ -108,9 +103,6 @@ class APIHomeAssistant(CoreSysAttributes):
if ATTR_WATCHDOG in body: if ATTR_WATCHDOG in body:
self.sys_homeassistant.watchdog = body[ATTR_WATCHDOG] self.sys_homeassistant.watchdog = body[ATTR_WATCHDOG]
if ATTR_WAIT_BOOT in body:
self.sys_homeassistant.wait_boot = body[ATTR_WAIT_BOOT]
if ATTR_REFRESH_TOKEN in body: if ATTR_REFRESH_TOKEN in body:
self.sys_homeassistant.refresh_token = body[ATTR_REFRESH_TOKEN] self.sys_homeassistant.refresh_token = body[ATTR_REFRESH_TOKEN]

View File

@ -22,7 +22,6 @@ from ..const import (
ATTR_SERVICES, ATTR_SERVICES,
ATTR_STATE, ATTR_STATE,
ATTR_TIMEZONE, ATTR_TIMEZONE,
CONTENT_TYPE_BINARY,
) )
from ..coresys import CoreSysAttributes from ..coresys import CoreSysAttributes
from .const import ( from .const import (
@ -36,7 +35,7 @@ from .const import (
ATTR_LLMNR_HOSTNAME, ATTR_LLMNR_HOSTNAME,
ATTR_STARTUP_TIME, ATTR_STARTUP_TIME,
ATTR_USE_NTP, ATTR_USE_NTP,
ATTR_USE_RTC, CONTENT_TYPE_BINARY,
) )
from .utils import api_process, api_process_raw, api_validate from .utils import api_process, api_process_raw, api_validate
@ -70,7 +69,6 @@ class APIHost(CoreSysAttributes):
ATTR_DT_UTC: self.sys_host.info.dt_utc, ATTR_DT_UTC: self.sys_host.info.dt_utc,
ATTR_DT_SYNCHRONIZED: self.sys_host.info.dt_synchronized, ATTR_DT_SYNCHRONIZED: self.sys_host.info.dt_synchronized,
ATTR_USE_NTP: self.sys_host.info.use_ntp, ATTR_USE_NTP: self.sys_host.info.use_ntp,
ATTR_USE_RTC: self.sys_host.info.use_rtc,
ATTR_STARTUP_TIME: self.sys_host.info.startup_time, ATTR_STARTUP_TIME: self.sys_host.info.startup_time,
ATTR_BOOT_TIMESTAMP: self.sys_host.info.boot_timestamp, ATTR_BOOT_TIMESTAMP: self.sys_host.info.boot_timestamp,
ATTR_BROADCAST_LLMNR: self.sys_host.info.broadcast_llmnr, ATTR_BROADCAST_LLMNR: self.sys_host.info.broadcast_llmnr,
@ -101,11 +99,7 @@ class APIHost(CoreSysAttributes):
@api_process @api_process
def reload(self, request): def reload(self, request):
"""Reload host data.""" """Reload host data."""
return asyncio.shield( return asyncio.shield(self.sys_host.reload())
asyncio.wait(
[self.sys_host.reload(), self.sys_resolution.evaluate.evaluate_system()]
)
)
@api_process @api_process
async def services(self, request): async def services(self, request):

View File

@ -22,11 +22,9 @@ from ..const import (
ATTR_PANELS, ATTR_PANELS,
ATTR_SESSION, ATTR_SESSION,
ATTR_TITLE, ATTR_TITLE,
COOKIE_INGRESS,
HEADER_TOKEN,
HEADER_TOKEN_OLD,
) )
from ..coresys import CoreSysAttributes from ..coresys import CoreSysAttributes
from .const import COOKIE_INGRESS, HEADER_TOKEN, HEADER_TOKEN_OLD
from .utils import api_process, api_validate, require_home_assistant from .utils import api_process, api_validate, require_home_assistant
_LOGGER: logging.Logger = logging.getLogger(__name__) _LOGGER: logging.Logger = logging.getLogger(__name__)

View File

@ -77,7 +77,6 @@ ADDONS_ROLE_ACCESS = {
r"^(?:" r"^(?:"
r"|/.+/info" r"|/.+/info"
r"|/backups.*" r"|/backups.*"
r"|/snapshots.*"
r")$" r")$"
), ),
ROLE_MANAGER: re.compile( ROLE_MANAGER: re.compile(

View File

@ -18,11 +18,11 @@ from ..const import (
ATTR_UPDATE_AVAILABLE, ATTR_UPDATE_AVAILABLE,
ATTR_VERSION, ATTR_VERSION,
ATTR_VERSION_LATEST, ATTR_VERSION_LATEST,
CONTENT_TYPE_BINARY,
) )
from ..coresys import CoreSysAttributes from ..coresys import CoreSysAttributes
from ..exceptions import APIError from ..exceptions import APIError
from ..validate import version_tag from ..validate import version_tag
from .const import CONTENT_TYPE_BINARY
from .utils import api_process, api_process_raw, api_validate from .utils import api_process, api_process_raw, api_validate
_LOGGER: logging.Logger = logging.getLogger(__name__) _LOGGER: logging.Logger = logging.getLogger(__name__)

View File

@ -1,14 +1,14 @@
function loadES5() { function loadES5() {
var el = document.createElement('script'); var el = document.createElement('script');
el.src = '/api/hassio/app/frontend_es5/entrypoint.073e9cdc.js'; el.src = '/api/hassio/app/frontend_es5/entrypoint.f8f83860.js';
document.body.appendChild(el); document.body.appendChild(el);
} }
if (/.*Version\/(?:11|12)(?:\.\d+)*.*Safari\//.test(navigator.userAgent)) { if (/.*Version\/(?:11|12)(?:\.\d+)*.*Safari\//.test(navigator.userAgent)) {
loadES5(); loadES5();
} else { } else {
try { try {
new Function("import('/api/hassio/app/frontend_latest/entrypoint.e7839dce.js')")(); new Function("import('/api/hassio/app/frontend_latest/entrypoint.b6cf778b.js')")();
} catch (err) { } catch (err) {
loadES5(); loadES5();
} }

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,3 +1,3 @@
{ {
"entrypoint.js": "/api/hassio/app/frontend_es5/entrypoint.073e9cdc.js" "entrypoint.js": "/api/hassio/app/frontend_es5/entrypoint.f8f83860.js"
} }

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -55,4 +55,4 @@
--app-header-border-bottom: 1px solid var(--divider-color); --app-header-border-bottom: 1px solid var(--divider-color);
} }
`}}]}}),i.oi)}}]); `}}]}}),i.oi)}}]);
//# sourceMappingURL=99edc920.js.map //# sourceMappingURL=5d68c82a.js.map

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -108,4 +108,4 @@
padding-bottom: 8px; padding-bottom: 8px;
} }
`}}]}}),i.oi)},4450:(e,t,r)=>{r.d(t,{I:()=>i,H:()=>n});const i=(0,r(4516).Z)(((e,t)=>t.some((t=>e.includes(t))))),n=(e,t)=>{if(t.startsWith("# Changelog")&&(t=t.substr(12,t.length)),t.includes(`# ${e.version}`)&&t.includes(`# ${e.version_latest}`)){const r=t.split(`# ${e.version}`)[0];r.includes(`# ${e.version_latest}`)&&(t=r)}return t}}}]); `}}]}}),i.oi)},4450:(e,t,r)=>{r.d(t,{I:()=>i,H:()=>n});const i=(0,r(4516).Z)(((e,t)=>t.some((t=>e.includes(t))))),n=(e,t)=>{if(t.startsWith("# Changelog")&&(t=t.substr(12,t.length)),t.includes(`# ${e.version}`)&&t.includes(`# ${e.version_latest}`)){const r=t.split(`# ${e.version}`)[0];r.includes(`# ${e.version_latest}`)&&(t=r)}return t}}}]);
//# sourceMappingURL=fe3336e8.js.map //# sourceMappingURL=bf6a06c2.js.map

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@ -1,3 +1,3 @@
{ {
"entrypoint.js": "/api/hassio/app/frontend_latest/entrypoint.e7839dce.js" "entrypoint.js": "/api/hassio/app/frontend_latest/entrypoint.b6cf778b.js"
} }

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -8,7 +8,7 @@ import voluptuous as vol
from ..addons import AnyAddon from ..addons import AnyAddon
from ..addons.utils import rating_security from ..addons.utils import rating_security
from ..api.const import ATTR_SIGNED from ..api.const import ATTR_SIGNED
from ..api.utils import api_process, api_validate from ..api.utils import api_process, api_process_raw, api_validate
from ..const import ( from ..const import (
ATTR_ADDONS, ATTR_ADDONS,
ATTR_ADVANCED, ATTR_ADVANCED,
@ -53,6 +53,7 @@ from ..exceptions import APIError, APIForbidden
from ..store.addon import AddonStore from ..store.addon import AddonStore
from ..store.repository import Repository from ..store.repository import Repository
from ..store.validate import validate_repository from ..store.validate import validate_repository
from .const import CONTENT_TYPE_PNG, CONTENT_TYPE_TEXT
SCHEMA_UPDATE = vol.Schema( SCHEMA_UPDATE = vol.Schema(
{ {
@ -206,6 +207,46 @@ class APIStore(CoreSysAttributes):
addon: AddonStore = self._extract_addon(request) addon: AddonStore = self._extract_addon(request)
return self._generate_addon_information(addon, True) return self._generate_addon_information(addon, True)
@api_process_raw(CONTENT_TYPE_PNG)
async def addons_addon_icon(self, request: web.Request) -> bytes:
"""Return icon from add-on."""
addon = self._extract_addon(request)
if not addon.with_icon:
raise APIError(f"No icon found for add-on {addon.slug}!")
with addon.path_icon.open("rb") as png:
return png.read()
@api_process_raw(CONTENT_TYPE_PNG)
async def addons_addon_logo(self, request: web.Request) -> bytes:
"""Return logo from add-on."""
addon = self._extract_addon(request)
if not addon.with_logo:
raise APIError(f"No logo found for add-on {addon.slug}!")
with addon.path_logo.open("rb") as png:
return png.read()
@api_process_raw(CONTENT_TYPE_TEXT)
async def addons_addon_changelog(self, request: web.Request) -> str:
"""Return changelog from add-on."""
addon = self._extract_addon(request)
if not addon.with_changelog:
raise APIError(f"No changelog found for add-on {addon.slug}!")
with addon.path_changelog.open("r") as changelog:
return changelog.read()
@api_process_raw(CONTENT_TYPE_TEXT)
async def addons_addon_documentation(self, request: web.Request) -> str:
"""Return documentation from add-on."""
addon = self._extract_addon(request)
if not addon.with_documentation:
raise APIError(f"No documentation found for add-on {addon.slug}!")
with addon.path_documentation.open("r") as documentation:
return documentation.read()
@api_process @api_process
async def repositories_list(self, request: web.Request) -> list[dict[str, Any]]: async def repositories_list(self, request: web.Request) -> list[dict[str, Any]]:
"""Return all repositories.""" """Return all repositories."""

View File

@ -17,14 +17,12 @@ from ..const import (
ATTR_CPU_PERCENT, ATTR_CPU_PERCENT,
ATTR_DEBUG, ATTR_DEBUG,
ATTR_DEBUG_BLOCK, ATTR_DEBUG_BLOCK,
ATTR_DESCRIPTON,
ATTR_DIAGNOSTICS, ATTR_DIAGNOSTICS,
ATTR_FORCE_SECURITY, ATTR_FORCE_SECURITY,
ATTR_HEALTHY, ATTR_HEALTHY,
ATTR_ICON, ATTR_ICON,
ATTR_IP_ADDRESS, ATTR_IP_ADDRESS,
ATTR_LOGGING, ATTR_LOGGING,
ATTR_LOGO,
ATTR_MEMORY_LIMIT, ATTR_MEMORY_LIMIT,
ATTR_MEMORY_PERCENT, ATTR_MEMORY_PERCENT,
ATTR_MEMORY_USAGE, ATTR_MEMORY_USAGE,
@ -40,7 +38,6 @@ from ..const import (
ATTR_VERSION, ATTR_VERSION,
ATTR_VERSION_LATEST, ATTR_VERSION_LATEST,
ATTR_WAIT_BOOT, ATTR_WAIT_BOOT,
CONTENT_TYPE_BINARY,
LogLevel, LogLevel,
UpdateChannel, UpdateChannel,
) )
@ -49,6 +46,7 @@ from ..exceptions import APIError
from ..store.validate import repositories from ..store.validate import repositories
from ..utils.validate import validate_timezone from ..utils.validate import validate_timezone
from ..validate import version_tag, wait_boot from ..validate import version_tag, wait_boot
from .const import CONTENT_TYPE_BINARY
from .utils import api_process, api_process_raw, api_validate from .utils import api_process, api_process_raw, api_validate
_LOGGER: logging.Logger = logging.getLogger(__name__) _LOGGER: logging.Logger = logging.getLogger(__name__)
@ -83,23 +81,6 @@ class APISupervisor(CoreSysAttributes):
@api_process @api_process
async def info(self, request: web.Request) -> dict[str, Any]: async def info(self, request: web.Request) -> dict[str, Any]:
"""Return host information.""" """Return host information."""
list_addons = []
for addon in self.sys_addons.installed:
list_addons.append(
{
ATTR_NAME: addon.name,
ATTR_SLUG: addon.slug,
ATTR_DESCRIPTON: addon.description,
ATTR_STATE: addon.state,
ATTR_VERSION: addon.version,
ATTR_VERSION_LATEST: addon.latest_version,
ATTR_UPDATE_AVAILABLE: addon.need_update,
ATTR_REPOSITORY: addon.repository,
ATTR_ICON: addon.with_icon,
ATTR_LOGO: addon.with_logo,
}
)
return { return {
ATTR_VERSION: self.sys_supervisor.version, ATTR_VERSION: self.sys_supervisor.version,
ATTR_VERSION_LATEST: self.sys_supervisor.latest_version, ATTR_VERSION_LATEST: self.sys_supervisor.latest_version,
@ -115,8 +96,24 @@ class APISupervisor(CoreSysAttributes):
ATTR_DEBUG: self.sys_config.debug, ATTR_DEBUG: self.sys_config.debug,
ATTR_DEBUG_BLOCK: self.sys_config.debug_block, ATTR_DEBUG_BLOCK: self.sys_config.debug_block,
ATTR_DIAGNOSTICS: self.sys_config.diagnostics, ATTR_DIAGNOSTICS: self.sys_config.diagnostics,
ATTR_ADDONS: list_addons, # Depricated
ATTR_ADDONS_REPOSITORIES: self.sys_store.repository_urls, ATTR_ADDONS: [
{
ATTR_NAME: addon.name,
ATTR_SLUG: addon.slug,
ATTR_VERSION: addon.version,
ATTR_VERSION_LATEST: addon.latest_version,
ATTR_UPDATE_AVAILABLE: addon.need_update,
ATTR_STATE: addon.state,
ATTR_REPOSITORY: addon.repository,
ATTR_ICON: addon.with_icon,
}
for addon in self.sys_addons.local.values()
],
ATTR_ADDONS_REPOSITORIES: [
{ATTR_NAME: store.name, ATTR_SLUG: store.slug}
for store in self.sys_store.all
],
} }
@api_process @api_process
@ -146,18 +143,11 @@ class APISupervisor(CoreSysAttributes):
if ATTR_LOGGING in body: if ATTR_LOGGING in body:
self.sys_config.logging = body[ATTR_LOGGING] self.sys_config.logging = body[ATTR_LOGGING]
# REMOVE: 2021.7
if ATTR_CONTENT_TRUST in body:
self.sys_security.content_trust = body[ATTR_CONTENT_TRUST]
# REMOVE: 2021.7
if ATTR_FORCE_SECURITY in body:
self.sys_security.force = body[ATTR_FORCE_SECURITY]
# Save changes before processing addons in case of errors # Save changes before processing addons in case of errors
self.sys_updater.save_data() self.sys_updater.save_data()
self.sys_config.save_data() self.sys_config.save_data()
# Remove: 2022.9
if ATTR_ADDONS_REPOSITORIES in body: if ATTR_ADDONS_REPOSITORIES in body:
await asyncio.shield( await asyncio.shield(
self.sys_store.update_repositories(set(body[ATTR_ADDONS_REPOSITORIES])) self.sys_store.update_repositories(set(body[ATTR_ADDONS_REPOSITORIES]))

View File

@ -10,9 +10,6 @@ import voluptuous as vol
from voluptuous.humanize import humanize_error from voluptuous.humanize import humanize_error
from ..const import ( from ..const import (
CONTENT_TYPE_BINARY,
HEADER_TOKEN,
HEADER_TOKEN_OLD,
JSON_DATA, JSON_DATA,
JSON_MESSAGE, JSON_MESSAGE,
JSON_RESULT, JSON_RESULT,
@ -25,22 +22,20 @@ from ..exceptions import APIError, APIForbidden, DockerAPIError, HassioError
from ..utils import check_exception_chain, get_message_from_exception_chain from ..utils import check_exception_chain, get_message_from_exception_chain
from ..utils.json import JSONEncoder from ..utils.json import JSONEncoder
from ..utils.log_format import format_message from ..utils.log_format import format_message
from .const import CONTENT_TYPE_BINARY, HEADER_TOKEN, HEADER_TOKEN_OLD
def excract_supervisor_token(request: web.Request) -> Optional[str]: def excract_supervisor_token(request: web.Request) -> Optional[str]:
"""Extract Supervisor token from request.""" """Extract Supervisor token from request."""
supervisor_token = request.headers.get(HEADER_TOKEN) if supervisor_token := request.headers.get(HEADER_TOKEN):
if supervisor_token:
return supervisor_token return supervisor_token
# Remove with old Supervisor fallback # Old Supervisor fallback
supervisor_token = request.headers.get(HEADER_TOKEN_OLD) if supervisor_token := request.headers.get(HEADER_TOKEN_OLD):
if supervisor_token:
return supervisor_token return supervisor_token
# API access only # API access only
supervisor_token = request.headers.get(AUTHORIZATION) if supervisor_token := request.headers.get(AUTHORIZATION):
if supervisor_token:
return supervisor_token.split(" ")[-1] return supervisor_token.split(" ")[-1]
return None return None

View File

@ -68,21 +68,6 @@ JSON_RESULT = "result"
RESULT_ERROR = "error" RESULT_ERROR = "error"
RESULT_OK = "ok" RESULT_OK = "ok"
CONTENT_TYPE_BINARY = "application/octet-stream"
CONTENT_TYPE_JSON = "application/json"
CONTENT_TYPE_PNG = "image/png"
CONTENT_TYPE_TAR = "application/tar"
CONTENT_TYPE_TEXT = "text/plain"
CONTENT_TYPE_URL = "application/x-www-form-urlencoded"
COOKIE_INGRESS = "ingress_session"
HEADER_TOKEN = "X-Supervisor-Token"
HEADER_TOKEN_OLD = "X-Hassio-Key"
ENV_TIME = "TZ"
ENV_TOKEN = "SUPERVISOR_TOKEN"
ENV_TOKEN_HASSIO = "HASSIO_TOKEN"
ENV_HOMEASSISTANT_REPOSITORY = "HOMEASSISTANT_REPOSITORY" ENV_HOMEASSISTANT_REPOSITORY = "HOMEASSISTANT_REPOSITORY"
ENV_SUPERVISOR_DEV = "SUPERVISOR_DEV" ENV_SUPERVISOR_DEV = "SUPERVISOR_DEV"
ENV_SUPERVISOR_MACHINE = "SUPERVISOR_MACHINE" ENV_SUPERVISOR_MACHINE = "SUPERVISOR_MACHINE"

View File

@ -97,7 +97,6 @@ DBUS_ATTR_LAST_ERROR = "LastError"
DBUS_ATTR_LLMNR = "LLMNR" DBUS_ATTR_LLMNR = "LLMNR"
DBUS_ATTR_LLMNR_HOSTNAME = "LLMNRHostname" DBUS_ATTR_LLMNR_HOSTNAME = "LLMNRHostname"
DBUS_ATTR_LOADER_TIMESTAMP_MONOTONIC = "LoaderTimestampMonotonic" DBUS_ATTR_LOADER_TIMESTAMP_MONOTONIC = "LoaderTimestampMonotonic"
DBUS_ATTR_LOCALRTC = "LocalRTC"
DBUS_ATTR_MANAGED = "Managed" DBUS_ATTR_MANAGED = "Managed"
DBUS_ATTR_MODE = "Mode" DBUS_ATTR_MODE = "Mode"
DBUS_ATTR_MULTICAST_DNS = "MulticastDNS" DBUS_ATTR_MULTICAST_DNS = "MulticastDNS"

View File

@ -7,7 +7,6 @@ from ..exceptions import DBusError, DBusInterfaceError
from ..utils.dbus import DBus from ..utils.dbus import DBus
from ..utils.dt import utc_from_timestamp from ..utils.dt import utc_from_timestamp
from .const import ( from .const import (
DBUS_ATTR_LOCALRTC,
DBUS_ATTR_NTP, DBUS_ATTR_NTP,
DBUS_ATTR_NTPSYNCHRONIZED, DBUS_ATTR_NTPSYNCHRONIZED,
DBUS_ATTR_TIMEUSEC, DBUS_ATTR_TIMEUSEC,
@ -37,12 +36,6 @@ class TimeDate(DBusInterface):
"""Return host timezone.""" """Return host timezone."""
return self.properties[DBUS_ATTR_TIMEZONE] return self.properties[DBUS_ATTR_TIMEZONE]
@property
@dbus_property
def local_rtc(self) -> bool:
"""Return if a local RTC exists."""
return self.properties[DBUS_ATTR_LOCALRTC]
@property @property
@dbus_property @dbus_property
def ntp(self) -> bool: def ntp(self) -> bool:

View File

@ -17,9 +17,6 @@ from ..addons.build import AddonBuild
from ..bus import EventListener from ..bus import EventListener
from ..const import ( from ..const import (
DOCKER_CPU_RUNTIME_ALLOCATION, DOCKER_CPU_RUNTIME_ALLOCATION,
ENV_TIME,
ENV_TOKEN,
ENV_TOKEN_HASSIO,
MAP_ADDONS, MAP_ADDONS,
MAP_BACKUP, MAP_BACKUP,
MAP_CONFIG, MAP_CONFIG,
@ -46,7 +43,14 @@ from ..hardware.data import Device
from ..jobs.decorator import Job, JobCondition from ..jobs.decorator import Job, JobCondition
from ..resolution.const import ContextType, IssueType, SuggestionType from ..resolution.const import ContextType, IssueType, SuggestionType
from ..utils import process_lock from ..utils import process_lock
from .const import DBUS_PATH, DBUS_VOLUME, Capabilities from .const import (
DBUS_PATH,
DBUS_VOLUME,
ENV_TIME,
ENV_TOKEN,
ENV_TOKEN_OLD,
Capabilities,
)
from .interface import DockerInterface from .interface import DockerInterface
if TYPE_CHECKING: if TYPE_CHECKING:
@ -128,7 +132,7 @@ class DockerAddon(DockerInterface):
**addon_env, **addon_env,
ENV_TIME: self.sys_timezone, ENV_TIME: self.sys_timezone,
ENV_TOKEN: self.addon.supervisor_token, ENV_TOKEN: self.addon.supervisor_token,
ENV_TOKEN_HASSIO: self.addon.supervisor_token, ENV_TOKEN_OLD: self.addon.supervisor_token,
} }
@property @property

View File

@ -4,15 +4,10 @@ from typing import Optional
import docker import docker
from ..const import ( from ..const import DOCKER_CPU_RUNTIME_ALLOCATION, MACHINE_ID
DOCKER_CPU_RUNTIME_ALLOCATION,
ENV_SUPERVISOR_MACHINE,
ENV_TIME,
MACHINE_ID,
)
from ..coresys import CoreSysAttributes from ..coresys import CoreSysAttributes
from ..hardware.const import PolicyGroup from ..hardware.const import PolicyGroup
from .const import Capabilities from .const import ENV_TIME, Capabilities
from .interface import DockerInterface from .interface import DockerInterface
_LOGGER: logging.Logger = logging.getLogger(__name__) _LOGGER: logging.Logger = logging.getLogger(__name__)
@ -101,7 +96,6 @@ class DockerAudio(DockerInterface, CoreSysAttributes):
device_cgroup_rules=self.cgroups_rules, device_cgroup_rules=self.cgroups_rules,
environment={ environment={
ENV_TIME: self.sys_timezone, ENV_TIME: self.sys_timezone,
ENV_SUPERVISOR_MACHINE: self.sys_machine,
}, },
volumes=self.volumes, volumes=self.volumes,
) )

View File

@ -1,8 +1,8 @@
"""HA Cli docker object.""" """HA Cli docker object."""
import logging import logging
from ..const import ENV_TIME, ENV_TOKEN
from ..coresys import CoreSysAttributes from ..coresys import CoreSysAttributes
from .const import ENV_TIME, ENV_TOKEN
from .interface import DockerInterface from .interface import DockerInterface
_LOGGER: logging.Logger = logging.getLogger(__name__) _LOGGER: logging.Logger = logging.getLogger(__name__)

View File

@ -19,3 +19,7 @@ class Capabilities(str, Enum):
DBUS_PATH = "/run/dbus" DBUS_PATH = "/run/dbus"
DBUS_VOLUME = {"bind": DBUS_PATH, "mode": "ro"} DBUS_VOLUME = {"bind": DBUS_PATH, "mode": "ro"}
ENV_TIME = "TZ"
ENV_TOKEN = "SUPERVISOR_TOKEN"
ENV_TOKEN_OLD = "HASSIO_TOKEN"

Some files were not shown because too many files have changed in this diff Show More