mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-07-21 08:06:30 +00:00
Temporary directory to executor (#5673)
* Move temporary directory usage to executor * Use temp_folder.name in Path constructor
This commit is contained in:
parent
c5d4ebcd48
commit
151d4bdd73
@ -977,11 +977,21 @@ class Addon(AddonModel):
|
|||||||
return
|
return
|
||||||
|
|
||||||
# Need install/update
|
# Need install/update
|
||||||
with TemporaryDirectory(dir=self.sys_config.path_tmp) as tmp_folder:
|
tmp_folder: TemporaryDirectory | None = None
|
||||||
profile_file = Path(tmp_folder, "apparmor.txt")
|
|
||||||
|
|
||||||
|
def install_update_profile() -> Path:
|
||||||
|
nonlocal tmp_folder
|
||||||
|
tmp_folder = TemporaryDirectory(dir=self.sys_config.path_tmp)
|
||||||
|
profile_file = Path(tmp_folder.name, "apparmor.txt")
|
||||||
adjust_profile(self.slug, self.path_apparmor, profile_file)
|
adjust_profile(self.slug, self.path_apparmor, profile_file)
|
||||||
|
return profile_file
|
||||||
|
|
||||||
|
try:
|
||||||
|
profile_file = await self.sys_run_in_executor(install_update_profile)
|
||||||
await self.sys_host.apparmor.load_profile(self.slug, profile_file)
|
await self.sys_host.apparmor.load_profile(self.slug, profile_file)
|
||||||
|
finally:
|
||||||
|
if tmp_folder:
|
||||||
|
await self.sys_run_in_executor(tmp_folder.cleanup)
|
||||||
|
|
||||||
async def uninstall_apparmor(self) -> None:
|
async def uninstall_apparmor(self) -> None:
|
||||||
"""Remove AppArmor profile for Add-on."""
|
"""Remove AppArmor profile for Add-on."""
|
||||||
|
@ -5,6 +5,7 @@ from __future__ import annotations
|
|||||||
import asyncio
|
import asyncio
|
||||||
from collections.abc import Callable
|
from collections.abc import Callable
|
||||||
import errno
|
import errno
|
||||||
|
from io import IOBase
|
||||||
import logging
|
import logging
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import re
|
import re
|
||||||
@ -518,29 +519,28 @@ class APIBackups(CoreSysAttributes):
|
|||||||
except vol.Invalid as ex:
|
except vol.Invalid as ex:
|
||||||
raise APIError(humanize_error(filename, ex)) from None
|
raise APIError(humanize_error(filename, ex)) from None
|
||||||
|
|
||||||
with TemporaryDirectory(dir=tmp_path.as_posix()) as temp_dir:
|
temp_dir: TemporaryDirectory | None = None
|
||||||
tar_file = Path(temp_dir, "backup.tar")
|
backup_file_stream: IOBase | None = None
|
||||||
|
|
||||||
|
def open_backup_file() -> Path:
|
||||||
|
nonlocal temp_dir, backup_file_stream
|
||||||
|
temp_dir = TemporaryDirectory(dir=tmp_path.as_posix())
|
||||||
|
tar_file = Path(temp_dir.name, "backup.tar")
|
||||||
|
backup_file_stream = tar_file.open("wb")
|
||||||
|
return tar_file
|
||||||
|
|
||||||
|
def close_backup_file() -> None:
|
||||||
|
if backup_file_stream:
|
||||||
|
backup_file_stream.close()
|
||||||
|
if temp_dir:
|
||||||
|
temp_dir.cleanup()
|
||||||
|
|
||||||
|
try:
|
||||||
reader = await request.multipart()
|
reader = await request.multipart()
|
||||||
contents = await reader.next()
|
contents = await reader.next()
|
||||||
try:
|
tar_file = await self.sys_run_in_executor(open_backup_file)
|
||||||
with tar_file.open("wb") as backup:
|
while chunk := await contents.read_chunk(size=2**16):
|
||||||
while True:
|
await self.sys_run_in_executor(backup_file_stream.write, chunk)
|
||||||
chunk = await contents.read_chunk()
|
|
||||||
if not chunk:
|
|
||||||
break
|
|
||||||
backup.write(chunk)
|
|
||||||
|
|
||||||
except OSError as err:
|
|
||||||
if err.errno == errno.EBADMSG and location in {
|
|
||||||
LOCATION_CLOUD_BACKUP,
|
|
||||||
None,
|
|
||||||
}:
|
|
||||||
self.sys_resolution.unhealthy = UnhealthyReason.OSERROR_BAD_MESSAGE
|
|
||||||
_LOGGER.error("Can't write new backup file: %s", err)
|
|
||||||
return False
|
|
||||||
|
|
||||||
except asyncio.CancelledError:
|
|
||||||
return False
|
|
||||||
|
|
||||||
backup = await asyncio.shield(
|
backup = await asyncio.shield(
|
||||||
self.sys_backups.import_backup(
|
self.sys_backups.import_backup(
|
||||||
@ -550,6 +550,21 @@ class APIBackups(CoreSysAttributes):
|
|||||||
additional_locations=locations,
|
additional_locations=locations,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
except OSError as err:
|
||||||
|
if err.errno == errno.EBADMSG and location in {
|
||||||
|
LOCATION_CLOUD_BACKUP,
|
||||||
|
None,
|
||||||
|
}:
|
||||||
|
self.sys_resolution.unhealthy = UnhealthyReason.OSERROR_BAD_MESSAGE
|
||||||
|
_LOGGER.error("Can't write new backup file: %s", err)
|
||||||
|
return False
|
||||||
|
|
||||||
|
except asyncio.CancelledError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
finally:
|
||||||
|
if temp_dir or backup:
|
||||||
|
await self.sys_run_in_executor(close_backup_file)
|
||||||
|
|
||||||
if backup:
|
if backup:
|
||||||
return {ATTR_SLUG: backup.slug}
|
return {ATTR_SLUG: backup.slug}
|
||||||
|
@ -158,25 +158,35 @@ class Supervisor(CoreSysAttributes):
|
|||||||
) from err
|
) from err
|
||||||
|
|
||||||
# Load
|
# Load
|
||||||
with TemporaryDirectory(dir=self.sys_config.path_tmp) as tmp_dir:
|
temp_dir: TemporaryDirectory | None = None
|
||||||
profile_file = Path(tmp_dir, "apparmor.txt")
|
|
||||||
try:
|
|
||||||
profile_file.write_text(data, encoding="utf-8")
|
|
||||||
except OSError as err:
|
|
||||||
if err.errno == errno.EBADMSG:
|
|
||||||
self.sys_resolution.unhealthy = UnhealthyReason.OSERROR_BAD_MESSAGE
|
|
||||||
raise SupervisorAppArmorError(
|
|
||||||
f"Can't write temporary profile: {err!s}", _LOGGER.error
|
|
||||||
) from err
|
|
||||||
|
|
||||||
try:
|
def write_profile() -> Path:
|
||||||
await self.sys_host.apparmor.load_profile(
|
nonlocal temp_dir
|
||||||
"hassio-supervisor", profile_file
|
temp_dir = TemporaryDirectory(dir=self.sys_config.path_tmp)
|
||||||
)
|
profile_file = Path(temp_dir.name, "apparmor.txt")
|
||||||
except HostAppArmorError as err:
|
profile_file.write_text(data, encoding="utf-8")
|
||||||
raise SupervisorAppArmorError(
|
return profile_file
|
||||||
"Can't update AppArmor profile!", _LOGGER.error
|
|
||||||
) from err
|
try:
|
||||||
|
profile_file = await self.sys_run_in_executor(write_profile)
|
||||||
|
|
||||||
|
await self.sys_host.apparmor.load_profile("hassio-supervisor", profile_file)
|
||||||
|
|
||||||
|
except OSError as err:
|
||||||
|
if err.errno == errno.EBADMSG:
|
||||||
|
self.sys_resolution.unhealthy = UnhealthyReason.OSERROR_BAD_MESSAGE
|
||||||
|
raise SupervisorAppArmorError(
|
||||||
|
f"Can't write temporary profile: {err!s}", _LOGGER.error
|
||||||
|
) from err
|
||||||
|
|
||||||
|
except HostAppArmorError as err:
|
||||||
|
raise SupervisorAppArmorError(
|
||||||
|
"Can't update AppArmor profile!", _LOGGER.error
|
||||||
|
) from err
|
||||||
|
|
||||||
|
finally:
|
||||||
|
if temp_dir:
|
||||||
|
await self.sys_run_in_executor(temp_dir.cleanup)
|
||||||
|
|
||||||
async def update(self, version: AwesomeVersion | None = None) -> None:
|
async def update(self, version: AwesomeVersion | None = None) -> None:
|
||||||
"""Update Supervisor version."""
|
"""Update Supervisor version."""
|
||||||
|
@ -90,6 +90,7 @@ def remove_folder(
|
|||||||
Is needed to avoid issue with:
|
Is needed to avoid issue with:
|
||||||
- CAP_DAC_OVERRIDE
|
- CAP_DAC_OVERRIDE
|
||||||
- CAP_DAC_READ_SEARCH
|
- CAP_DAC_READ_SEARCH
|
||||||
|
Must be run in executor.
|
||||||
"""
|
"""
|
||||||
find_args = []
|
find_args = []
|
||||||
if content_only:
|
if content_only:
|
||||||
@ -114,7 +115,10 @@ def remove_folder_with_excludes(
|
|||||||
excludes: list[str],
|
excludes: list[str],
|
||||||
tmp_dir: Path | None = None,
|
tmp_dir: Path | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Remove folder with excludes."""
|
"""Remove folder with excludes.
|
||||||
|
|
||||||
|
Must be run in executor.
|
||||||
|
"""
|
||||||
with TemporaryDirectory(dir=tmp_dir) as temp_path:
|
with TemporaryDirectory(dir=tmp_dir) as temp_path:
|
||||||
temp_path = Path(temp_path)
|
temp_path = Path(temp_path)
|
||||||
moved_files: list[Path] = []
|
moved_files: list[Path] = []
|
||||||
|
Loading…
x
Reference in New Issue
Block a user