mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-09-19 04:59:01 +00:00
storage: simplified use of df to get disk information
- Use df --block-size=1 instead --human-readable to fix locale issue #1043. - Code cleanup: get available space directly, better variable/module names. Signed-off-by: Johannes Keyser <johanneskeyser@posteo.de> Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
This commit is contained in:
parent
1247f2ef93
commit
10df3004ac
@ -64,8 +64,8 @@ def get_disks():
|
|||||||
def _get_disks_from_df():
|
def _get_disks_from_df():
|
||||||
"""Return the list of disks and free space available using 'df'."""
|
"""Return the list of disks and free space available using 'df'."""
|
||||||
command = ['df', '--exclude-type=tmpfs', '--exclude-type=devtmpfs',
|
command = ['df', '--exclude-type=tmpfs', '--exclude-type=devtmpfs',
|
||||||
'--output=source,target,fstype,size,used,pcent',
|
'--block-size=1',
|
||||||
'--human-readable']
|
'--output=source,target,fstype,size,used,avail,pcent']
|
||||||
try:
|
try:
|
||||||
process = subprocess.run(command, stdout=subprocess.PIPE, check=True)
|
process = subprocess.run(command, stdout=subprocess.PIPE, check=True)
|
||||||
except subprocess.CalledProcessError as exception:
|
except subprocess.CalledProcessError as exception:
|
||||||
@ -78,9 +78,15 @@ def _get_disks_from_df():
|
|||||||
for line in output.splitlines()[1:]:
|
for line in output.splitlines()[1:]:
|
||||||
parts = line.split()
|
parts = line.split()
|
||||||
keys = ('device', 'mount_point', 'file_system_type', 'size', 'used',
|
keys = ('device', 'mount_point', 'file_system_type', 'size', 'used',
|
||||||
'percentage_used')
|
'free', 'percent_used')
|
||||||
disk = dict(zip(keys, parts))
|
disk = dict(zip(keys, parts))
|
||||||
disk['percentage_used'] = int(disk['percentage_used'].rstrip('%'))
|
disk['percent_used'] = int(disk['percent_used'].rstrip('%'))
|
||||||
|
disk['size'] = int(disk['size'])
|
||||||
|
disk['used'] = int(disk['used'])
|
||||||
|
disk['free'] = int(disk['free'])
|
||||||
|
disk['size_str'] = format_bytes(disk['size'])
|
||||||
|
disk['used_str'] = format_bytes(disk['used'])
|
||||||
|
disk['free_str'] = format_bytes(disk['free'])
|
||||||
disks.append(disk)
|
disks.append(disk)
|
||||||
|
|
||||||
return disks
|
return disks
|
||||||
@ -130,3 +136,27 @@ def is_expandable(device):
|
|||||||
def expand_partition(device):
|
def expand_partition(device):
|
||||||
"""Expand a partition."""
|
"""Expand a partition."""
|
||||||
actions.superuser_run('storage', ['expand-partition', device])
|
actions.superuser_run('storage', ['expand-partition', device])
|
||||||
|
|
||||||
|
|
||||||
|
def format_bytes(size):
|
||||||
|
"""Return human readable disk size from bytes."""
|
||||||
|
if not size:
|
||||||
|
return size
|
||||||
|
|
||||||
|
if size < 1024:
|
||||||
|
return _('{disk_size:.1f} bytes').format(disk_size=size)
|
||||||
|
|
||||||
|
if size < 1024 ** 2:
|
||||||
|
size /= 1024
|
||||||
|
return _('{disk_size:.1f} KiB').format(disk_size=size)
|
||||||
|
|
||||||
|
if size < 1024 ** 3:
|
||||||
|
size /= 1024 ** 2
|
||||||
|
return _('{disk_size:.1f} MiB').format(disk_size=size)
|
||||||
|
|
||||||
|
if size < 1024 ** 4:
|
||||||
|
size /= 1024 ** 3
|
||||||
|
return _('{disk_size:.1f} GiB').format(disk_size=size)
|
||||||
|
|
||||||
|
size /= 1024 ** 4
|
||||||
|
return _('{disk_size:.1f} TiB').format(disk_size=size)
|
||||||
|
|||||||
@ -52,20 +52,20 @@
|
|||||||
<td>{{ disk.file_system_type }}</td>
|
<td>{{ disk.file_system_type }}</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="progress">
|
<div class="progress">
|
||||||
{% if disk.percentage_used < 75 %}
|
{% if disk.percent_used < 75 %}
|
||||||
<div class="progress-bar progress-bar-striped progress-bar-success"
|
<div class="progress-bar progress-bar-striped progress-bar-success"
|
||||||
{% elif disk.percentage_used < 90 %}
|
{% elif disk.percent_used < 90 %}
|
||||||
<div class="progress-bar progress-bar-striped progress-bar-warning"
|
<div class="progress-bar progress-bar-striped progress-bar-warning"
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="progress-bar progress-bar-striped progress-bar-danger"
|
<div class="progress-bar progress-bar-striped progress-bar-danger"
|
||||||
{% endif %}
|
{% endif %}
|
||||||
role="progressbar" aria-valuenow="disk.percentage_used"
|
role="progressbar" aria-valuenow="disk.percent_used"
|
||||||
aria-valuemin="0" aria-valuemax="100"
|
aria-valuemin="0" aria-valuemax="100"
|
||||||
style="width: {{ disk.percentage_used }}%;">
|
style="width: {{ disk.percent_used }}%;">
|
||||||
{{ disk.percentage_used }}%
|
{{ disk.percent_used }}%
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>{{ disk.used }} / {{ disk.size }}</div>
|
<div>{{ disk.used_str }} / {{ disk.size_str }}</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|||||||
@ -25,7 +25,7 @@ from django.shortcuts import redirect
|
|||||||
from django.template.response import TemplateResponse
|
from django.template.response import TemplateResponse
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from plinth.modules import storage as storage_module
|
from plinth.modules import storage
|
||||||
from plinth.utils import format_lazy, is_user_admin
|
from plinth.utils import format_lazy, is_user_admin
|
||||||
|
|
||||||
|
|
||||||
@ -34,10 +34,10 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
def index(request):
|
def index(request):
|
||||||
"""Show connection list."""
|
"""Show connection list."""
|
||||||
disks = storage_module.get_disks()
|
disks = storage.get_disks()
|
||||||
root_device = storage_module.get_root_device(disks)
|
root_device = storage.get_root_device(disks)
|
||||||
expandable_root_size = storage_module.is_expandable(root_device)
|
expandable_root_size = storage.is_expandable(root_device)
|
||||||
expandable_root_size = _format_bytes(expandable_root_size)
|
expandable_root_size = storage.format_bytes(expandable_root_size)
|
||||||
|
|
||||||
warn_about_low_disk_space(request)
|
warn_about_low_disk_space(request)
|
||||||
|
|
||||||
@ -49,15 +49,15 @@ def index(request):
|
|||||||
|
|
||||||
def expand(request):
|
def expand(request):
|
||||||
"""Warn and expand the root partition."""
|
"""Warn and expand the root partition."""
|
||||||
disks = storage_module.get_disks()
|
disks = storage.get_disks()
|
||||||
root_device = storage_module.get_root_device(disks)
|
root_device = storage.get_root_device(disks)
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
expand_partition(request, root_device)
|
expand_partition(request, root_device)
|
||||||
return redirect(reverse('storage:index'))
|
return redirect(reverse('storage:index'))
|
||||||
|
|
||||||
expandable_root_size = storage_module.is_expandable(root_device)
|
expandable_root_size = storage.is_expandable(root_device)
|
||||||
expandable_root_size = _format_bytes(expandable_root_size)
|
expandable_root_size = storage.format_bytes(expandable_root_size)
|
||||||
return TemplateResponse(request, 'storage_expand.html',
|
return TemplateResponse(request, 'storage_expand.html',
|
||||||
{'title': _('Expand Root Partition'),
|
{'title': _('Expand Root Partition'),
|
||||||
'expandable_root_size': expandable_root_size})
|
'expandable_root_size': expandable_root_size})
|
||||||
@ -66,7 +66,7 @@ def expand(request):
|
|||||||
def expand_partition(request, device):
|
def expand_partition(request, device):
|
||||||
"""Expand the partition."""
|
"""Expand the partition."""
|
||||||
try:
|
try:
|
||||||
storage_module.expand_partition(device)
|
storage.expand_partition(device)
|
||||||
except Exception as exception:
|
except Exception as exception:
|
||||||
messages.error(request, _('Error expanding partition: {exception}')
|
messages.error(request, _('Error expanding partition: {exception}')
|
||||||
.format(exception=exception))
|
.format(exception=exception))
|
||||||
@ -79,71 +79,26 @@ def warn_about_low_disk_space(request):
|
|||||||
if not is_user_admin(request, cached=True):
|
if not is_user_admin(request, cached=True):
|
||||||
return
|
return
|
||||||
|
|
||||||
disks = storage_module.get_disks()
|
disks = storage.get_disks()
|
||||||
list_root = [disk for disk in disks if disk['mountpoint'] == '/']
|
list_root = [disk for disk in disks if disk['mountpoint'] == '/']
|
||||||
if not list_root:
|
if not list_root:
|
||||||
logger.error('Error getting information about root partition.')
|
logger.error('Error getting information about root partition.')
|
||||||
return
|
return
|
||||||
|
|
||||||
perc_used = list_root[0]['percentage_used']
|
percent_used = list_root[0]['percent_used']
|
||||||
size_bytes = _interpret_size_string(list_root[0]['size'])
|
size_bytes = list_root[0]['size']
|
||||||
free_bytes = size_bytes * (100 - perc_used) / 100
|
free_bytes = list_root[0]['free']
|
||||||
|
free_gib = free_bytes / (1024 ** 3)
|
||||||
|
|
||||||
message = format_lazy(
|
message = format_lazy(
|
||||||
# Translators: xgettext:no-python-format
|
# Translators: xgettext:no-python-format
|
||||||
_('Warning: Low space on system partition ({percent_used}% used, '
|
_('Warning: Low space on system partition ({percent_used}% used, '
|
||||||
'{free_space} free).'),
|
'{free_space} free).'),
|
||||||
percent_used=perc_used, free_space=_format_bytes(free_bytes))
|
percent_used=percent_used,
|
||||||
|
free_space=storage.format_bytes(free_bytes))
|
||||||
|
|
||||||
free_gib = free_bytes / (1024 ** 3)
|
if percent_used > 90 or free_gib < 1:
|
||||||
if perc_used > 90 or free_gib < 1:
|
|
||||||
messages.error(request, message)
|
messages.error(request, message)
|
||||||
elif perc_used > 75 or free_gib < 2:
|
elif percent_used > 75 or free_gib < 2:
|
||||||
messages.warning(request, message)
|
messages.warning(request, message)
|
||||||
|
|
||||||
|
|
||||||
def _interpret_size_string(size_str):
|
|
||||||
"""Convert size string to number of bytes."""
|
|
||||||
# TODO: Drop --human-readable from df command (github issue #1043)
|
|
||||||
size_str = size_str.replace(',', '.') # some locales use commas
|
|
||||||
size_str = size_str.replace('٫', '.') # arabic decimal separator
|
|
||||||
if size_str[-1] in '0123456789':
|
|
||||||
return float(size_str[:-1])
|
|
||||||
|
|
||||||
if size_str[-1] == 'K':
|
|
||||||
return float(size_str[:-1]) * 1024
|
|
||||||
|
|
||||||
if size_str[-1] == 'M':
|
|
||||||
return float(size_str[:-1]) * 1024 ** 2
|
|
||||||
|
|
||||||
if size_str[-1] == 'G':
|
|
||||||
return float(size_str[:-1]) * 1024 ** 3
|
|
||||||
|
|
||||||
if size_str[-1] == 'T':
|
|
||||||
return float(size_str[:-1]) * 1024 ** 4
|
|
||||||
|
|
||||||
return -1
|
|
||||||
|
|
||||||
|
|
||||||
def _format_bytes(size):
|
|
||||||
"""Return human readable disk size from bytes."""
|
|
||||||
if not size:
|
|
||||||
return size
|
|
||||||
|
|
||||||
if size < 1024:
|
|
||||||
return _('{disk_size:.1f} bytes').format(disk_size=size)
|
|
||||||
|
|
||||||
if size < 1024 ** 2:
|
|
||||||
size /= 1024
|
|
||||||
return _('{disk_size:.1f} KiB').format(disk_size=size)
|
|
||||||
|
|
||||||
if size < 1024 ** 3:
|
|
||||||
size /= 1024 ** 2
|
|
||||||
return _('{disk_size:.1f} MiB').format(disk_size=size)
|
|
||||||
|
|
||||||
if size < 1024 ** 4:
|
|
||||||
size /= 1024 ** 3
|
|
||||||
return _('{disk_size:.1f} GiB').format(disk_size=size)
|
|
||||||
|
|
||||||
size /= 1024 ** 4
|
|
||||||
return _('{disk_size:.1f} TiB').format(disk_size=size)
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user