Fix request status check on AppArmor profile fetch (#2772)

* Fix reuest statuts check on AppArmor profile fetch

* Adjust logger
This commit is contained in:
Pascal Vizeli 2021-03-31 12:15:42 +02:00 committed by GitHub
parent 8e8e6e48a9
commit 8cd149783c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 57 additions and 18 deletions

View File

@ -80,6 +80,10 @@ class SupervisorUpdateError(SupervisorError):
"""Supervisor update error.""" """Supervisor update error."""
class SupervisorAppArmorError(SupervisorError):
"""Supervisor AppArmor error."""
class SupervisorJobError(SupervisorError, JobException): class SupervisorJobError(SupervisorError, JobException):
"""Raise on job errors.""" """Raise on job errors."""

View File

@ -11,20 +11,23 @@ import aiohttp
from aiohttp.client_exceptions import ClientError from aiohttp.client_exceptions import ClientError
from awesomeversion import AwesomeVersion, AwesomeVersionException from awesomeversion import AwesomeVersion, AwesomeVersionException
from supervisor.jobs.decorator import Job, JobCondition
from .const import ATTR_SUPERVISOR_INTERNET, SUPERVISOR_VERSION, URL_HASSIO_APPARMOR from .const import ATTR_SUPERVISOR_INTERNET, SUPERVISOR_VERSION, URL_HASSIO_APPARMOR
from .coresys import CoreSys, CoreSysAttributes from .coresys import CoreSys, CoreSysAttributes
from .docker.stats import DockerStats from .docker.stats import DockerStats
from .docker.supervisor import DockerSupervisor from .docker.supervisor import DockerSupervisor
from .exceptions import ( from .exceptions import (
CodeNotaryError,
CodeNotaryUntrusted,
DockerError, DockerError,
HostAppArmorError, HostAppArmorError,
SupervisorAppArmorError,
SupervisorError, SupervisorError,
SupervisorJobError, SupervisorJobError,
SupervisorUpdateError, SupervisorUpdateError,
) )
from .jobs.decorator import Job, JobCondition
from .resolution.const import ContextType, IssueType from .resolution.const import ContextType, IssueType
from .utils.codenotary import calc_checksum
_LOGGER: logging.Logger = logging.getLogger(__name__) _LOGGER: logging.Logger = logging.getLogger(__name__)
@ -102,46 +105,76 @@ class Supervisor(CoreSysAttributes):
async def update_apparmor(self) -> None: async def update_apparmor(self) -> None:
"""Fetch last version and update profile.""" """Fetch last version and update profile."""
url = URL_HASSIO_APPARMOR url = URL_HASSIO_APPARMOR
# Fetch
try: try:
_LOGGER.info("Fetching AppArmor profile %s", url) _LOGGER.info("Fetching AppArmor profile %s", url)
async with self.sys_websession.get(url, timeout=10) as request: timeout = aiohttp.ClientTimeout(total=10)
async with self.sys_websession.get(url, timeout=timeout) as request:
if request.status != 200:
raise SupervisorAppArmorError(
f"Fetching AppArmor Profile from {url} response with {request.status}",
_LOGGER.error,
)
data = await request.text() data = await request.text()
except (aiohttp.ClientError, asyncio.TimeoutError) as err: except (aiohttp.ClientError, asyncio.TimeoutError) as err:
self.sys_supervisor.connectivity = False self.sys_supervisor.connectivity = False
_LOGGER.warning("Can't fetch AppArmor profile: %s", err) raise SupervisorAppArmorError(
raise SupervisorError() from err f"Can't fetch AppArmor profile {url}: {str(err) or 'Timeout'}",
_LOGGER.error,
) from err
# Validate
try:
await self.sys_verify_content(checksum=calc_checksum(data))
except CodeNotaryUntrusted as err:
raise SupervisorAppArmorError(
"Content-Trust is broken for the AppArmor profile fetch!",
_LOGGER.critical,
) from err
except CodeNotaryError as err:
raise SupervisorAppArmorError(
f"CodeNotary error while processing AppArmor fetch: {err!s}",
_LOGGER.error,
) from err
# Load
with TemporaryDirectory(dir=self.sys_config.path_tmp) as tmp_dir: with TemporaryDirectory(dir=self.sys_config.path_tmp) as tmp_dir:
profile_file = Path(tmp_dir, "apparmor.txt") profile_file = Path(tmp_dir, "apparmor.txt")
try: try:
profile_file.write_text(data) profile_file.write_text(data)
except OSError as err: except OSError as err:
_LOGGER.error("Can't write temporary profile: %s", err) raise SupervisorAppArmorError(
raise SupervisorError() from err f"Can't write temporary profile: {err!s}", _LOGGER.error
) from err
try: try:
await self.sys_host.apparmor.load_profile( await self.sys_host.apparmor.load_profile(
"hassio-supervisor", profile_file "hassio-supervisor", profile_file
) )
except HostAppArmorError as err: except HostAppArmorError as err:
_LOGGER.error("Can't update AppArmor profile!") raise SupervisorAppArmorError(
raise SupervisorError() from err "Can't update AppArmor profile!", _LOGGER.error
) from err
async def update(self, version: Optional[AwesomeVersion] = None) -> None: async def update(self, version: Optional[AwesomeVersion] = None) -> None:
"""Update Home Assistant version.""" """Update Home Assistant version."""
version = version or self.latest_version version = version or self.latest_version
if version == self.sys_supervisor.version: if version == self.sys_supervisor.version:
_LOGGER.warning("Version %s is already installed", version) raise SupervisorUpdateError(
return f"Version {version!s} is already installed", _LOGGER.warning
)
# First update own AppArmor # First update own AppArmor
try: try:
await self.update_apparmor() await self.update_apparmor()
except SupervisorError as err: except SupervisorAppArmorError as err:
_LOGGER.critical("Abort update because of an issue with AppArmor!") raise SupervisorUpdateError(
raise SupervisorUpdateError() from err f"Abort update because of an issue with AppArmor: {err!s}",
_LOGGER.critical,
) from err
# Update container # Update container
_LOGGER.info("Update Supervisor to version %s", version) _LOGGER.info("Update Supervisor to version %s", version)
@ -153,12 +186,13 @@ class Supervisor(CoreSysAttributes):
self.sys_updater.image_supervisor, version self.sys_updater.image_supervisor, version
) )
except DockerError as err: except DockerError as err:
_LOGGER.error("Update of Supervisor failed!")
self.sys_resolution.create_issue( self.sys_resolution.create_issue(
IssueType.UPDATE_FAILED, ContextType.SUPERVISOR IssueType.UPDATE_FAILED, ContextType.SUPERVISOR
) )
self.sys_capture_exception(err) self.sys_capture_exception(err)
raise SupervisorUpdateError() from err raise SupervisorUpdateError(
f"Update of Supervisor failed: {err!s}", _LOGGER.error
) from err
else: else:
self.sys_config.version = version self.sys_config.version = version
self.sys_config.image = self.sys_updater.image_supervisor self.sys_config.image = self.sys_updater.image_supervisor

View File

@ -201,7 +201,8 @@ class Updater(FileConfiguration, CoreSysAttributes):
except (aiohttp.ClientError, asyncio.TimeoutError) as err: except (aiohttp.ClientError, asyncio.TimeoutError) as err:
self.sys_supervisor.connectivity = False self.sys_supervisor.connectivity = False
raise UpdaterError( raise UpdaterError(
f"Can't fetch versions from {url}: {err}", _LOGGER.warning f"Can't fetch versions from {url}: {str(err) or 'Timeout'}",
_LOGGER.warning,
) from err ) from err
# Validate # Validate
@ -213,7 +214,7 @@ class Updater(FileConfiguration, CoreSysAttributes):
) from err ) from err
except CodeNotaryError as err: except CodeNotaryError as err:
raise UpdaterError( raise UpdaterError(
f"CodeNotary error while processing version checks: {err!s}", f"CodeNotary error while processing version fetch: {err!s}",
_LOGGER.error, _LOGGER.error,
) from err ) from err