Temporary directory to executor (#5673)

* Move temporary directory usage to executor

* Use temp_folder.name in Path constructor
This commit is contained in:
Mike Degatano 2025-02-27 11:58:55 -05:00 committed by GitHub
parent c5d4ebcd48
commit 151d4bdd73
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 81 additions and 42 deletions

View File

@ -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."""

View File

@ -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,18 +519,37 @@ 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)
backup = await asyncio.shield(
self.sys_backups.import_backup(
tar_file,
filename,
location=location,
additional_locations=locations,
)
)
except OSError as err: except OSError as err:
if err.errno == errno.EBADMSG and location in { if err.errno == errno.EBADMSG and location in {
LOCATION_CLOUD_BACKUP, LOCATION_CLOUD_BACKUP,
@ -542,14 +562,9 @@ class APIBackups(CoreSysAttributes):
except asyncio.CancelledError: except asyncio.CancelledError:
return False return False
backup = await asyncio.shield( finally:
self.sys_backups.import_backup( if temp_dir or backup:
tar_file, await self.sys_run_in_executor(close_backup_file)
filename,
location=location,
additional_locations=locations,
)
)
if backup: if backup:
return {ATTR_SLUG: backup.slug} return {ATTR_SLUG: backup.slug}

View File

@ -158,10 +158,20 @@ 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: def write_profile() -> Path:
nonlocal temp_dir
temp_dir = TemporaryDirectory(dir=self.sys_config.path_tmp)
profile_file = Path(temp_dir.name, "apparmor.txt")
profile_file.write_text(data, encoding="utf-8") profile_file.write_text(data, encoding="utf-8")
return profile_file
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: except OSError as err:
if err.errno == errno.EBADMSG: if err.errno == errno.EBADMSG:
self.sys_resolution.unhealthy = UnhealthyReason.OSERROR_BAD_MESSAGE self.sys_resolution.unhealthy = UnhealthyReason.OSERROR_BAD_MESSAGE
@ -169,15 +179,15 @@ class Supervisor(CoreSysAttributes):
f"Can't write temporary profile: {err!s}", _LOGGER.error f"Can't write temporary profile: {err!s}", _LOGGER.error
) from err ) from err
try:
await self.sys_host.apparmor.load_profile(
"hassio-supervisor", profile_file
)
except HostAppArmorError as err: except HostAppArmorError as err:
raise SupervisorAppArmorError( raise SupervisorAppArmorError(
"Can't update AppArmor profile!", _LOGGER.error "Can't update AppArmor profile!", _LOGGER.error
) from err ) 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."""
version = version or self.latest_version version = version or self.latest_version

View File

@ -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] = []