Add free disk space log on docker install error (#1868)

* Add free disk space info

* Log available space on docker image install error

* Add unit to log message

* Add 404 check and better log message

* Set default path to supervisor data path

* Clean up attribute access

Co-authored-by: Pascal Vizeli <pvizeli@syshack.ch>

* Move free space helper to hardware

* Add hardware test

Co-authored-by: Pascal Vizeli <pvizeli@syshack.ch>
This commit is contained in:
Martin Hjelmare 2020-08-03 15:00:07 +02:00 committed by GitHub
parent 4ffaee6013
commit 4f1ed690cd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 43 additions and 1 deletions

View File

@ -99,6 +99,13 @@ class DockerInterface(CoreSysAttributes):
docker_image.tag(image, tag="latest") docker_image.tag(image, tag="latest")
except docker.errors.APIError as err: except docker.errors.APIError as err:
_LOGGER.error("Can't install %s:%s -> %s.", image, tag, err) _LOGGER.error("Can't install %s:%s -> %s.", image, tag, err)
if err.status_code == 404:
free_space = self.sys_host.info.free_space
_LOGGER.info(
"This error is often caused by not having enough disk space available. "
"Available space in /data is: %s GiB",
free_space,
)
raise DockerAPIError() from None raise DockerAPIError() from None
else: else:
self._meta = docker_image.attrs self._meta = docker_image.attrs

View File

@ -51,6 +51,13 @@ class InfoCenter(CoreSysAttributes):
"""Return local CPE.""" """Return local CPE."""
return self.sys_dbus.hostname.cpe return self.sys_dbus.hostname.cpe
@property
def free_space(self) -> float:
"""Return available space (GiB) on disk for supervisor data directory."""
return self.coresys.hardware.get_disk_free_space(
self.coresys.config.path_supervisor
)
async def get_dmesg(self) -> bytes: async def get_dmesg(self) -> bytes:
"""Return host dmesg output.""" """Return host dmesg output."""
proc = await asyncio.create_subprocess_shell( proc = await asyncio.create_subprocess_shell(

View File

@ -4,7 +4,8 @@ from datetime import datetime
import logging import logging
from pathlib import Path from pathlib import Path
import re import re
from typing import Any, Dict, List, Optional, Set import shutil
from typing import Any, Dict, List, Optional, Set, Union
import attr import attr
import pyudev import pyudev
@ -195,6 +196,11 @@ class Hardware:
return datetime.utcfromtimestamp(int(found.group(1))) return datetime.utcfromtimestamp(int(found.group(1)))
def get_disk_free_space(self, path: Union[str, Path]) -> float:
"""Return free space (GiB) on disk for path."""
_, _, free = shutil.disk_usage(path)
return round(free / (1024.0 ** 3), 1)
async def udev_trigger(self) -> None: async def udev_trigger(self) -> None:
"""Trigger a udev reload.""" """Trigger a udev reload."""
proc = await asyncio.create_subprocess_shell( proc = await asyncio.create_subprocess_shell(

13
tests/host/test_info.py Normal file
View File

@ -0,0 +1,13 @@
"""Test host info."""
from unittest.mock import patch
from supervisor.host.info import InfoCenter
def test_host_free_space(coresys):
"""Test host free space."""
info = InfoCenter(coresys)
with patch("shutil.disk_usage", return_value=(42, 42, 2 * (1024.0 ** 3))):
free = info.free_space
assert free == 2.0

View File

@ -32,3 +32,12 @@ def test_video_devices():
Device("cec0", Path("/dev/cec0"), []), Device("cec0", Path("/dev/cec0"), []),
Device("video1", Path("/dev/video1"), []), Device("video1", Path("/dev/video1"), []),
] ]
def test_free_space():
"""Test free space helper."""
system = Hardware()
with patch("shutil.disk_usage", return_value=(42, 42, 2 * (1024.0 ** 3))):
free = system.get_disk_free_space("/data")
assert free == 2.0