storage: Use DBus directly for listing disks

Bring us closer to avoiding the use of two different methods to access UDisks
DBus API: UDisks2 client library and direct DBus access with GDBus.

Perform formatting of the bytes outside of udisks2 module to avoid depending on
Django.

Tests performed:

- Visit the storage page. Disks are listed properly.

- Sizes are formatted to be human readable.

- Filesystem type is show properly: ext4, btrfs

- Labels for disks are shown as set by tune2fs etc.

- Device paths are shown properly.

- Mount point is shown properly.

Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org>
Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
This commit is contained in:
Sunil Mohan Adapa 2020-05-29 16:09:07 -07:00 committed by James Valleroy
parent 34a28e35c9
commit 225d86e344
No known key found for this signature in database
GPG Key ID: 77C0C75E7B650808
2 changed files with 42 additions and 37 deletions

View File

@ -13,7 +13,7 @@ from django.utils.translation import ugettext_noop
from plinth import actions
from plinth import app as app_module
from plinth import cfg, glib, menu, utils
from plinth import cfg, glib, menu
from plinth.errors import ActionError, PlinthError
from plinth.utils import format_lazy, import_from_gi
@ -77,50 +77,19 @@ def init():
def get_disks():
"""Returns list of disks by combining information from df and udisks."""
disks = _get_disks_from_df()
disks_from_udisks = _get_disks_from_udisks()
disks_from_udisks = udisks2.get_disks()
for disk in disks_from_udisks:
disk['size'] = format_bytes(disk['size'])
# Add info from udisks to the disks from df based on mount point.
for disk_from_df in disks:
for disk_from_udisks in disks_from_udisks:
if disk_from_udisks['mount_point'] == disk_from_df['mount_point']:
if disk_from_df['mount_point'] in disk_from_udisks['mount_points']:
disk_from_df.update(disk_from_udisks)
return sorted(disks, key=lambda disk: disk['device'])
def _get_disks_from_udisks():
"""List devices that can be ejected."""
udisks = utils.import_from_gi('UDisks', '2.0')
client = udisks.Client.new_sync()
object_manager = client.get_object_manager()
devices = []
for obj in object_manager.get_objects():
if not obj.get_block():
continue
block = obj.get_block()
if block.props.id_usage != 'filesystem':
continue
device = {
'device': block.props.device,
'label': block.props.id_label,
'size': format_bytes(block.props.size),
'filesystem_type': block.props.id_type,
'is_removable': not block.props.hint_system
}
try:
device['mount_point'] = obj.get_filesystem().props.mount_points[0]
except Exception:
continue
devices.append(device)
return devices
def _get_disks_from_df():
"""Return the list of disks and free space available using 'df'."""
try:

View File

@ -79,7 +79,7 @@ class Proxy:
if signature == 'aay':
return [bytes(value_item).decode()[:-1] for value_item in value]
if signature in ('s', 'b', 'o', 'u'):
if signature in ('s', 'b', 'o', 'u', 't'):
return glib.Variant.unpack(value)
raise ValueError('Unhandled type')
@ -100,7 +100,11 @@ class BlockDevice(Proxy):
'hint_ignore': ('b', 'HintIgnore'),
'hint_system': ('b', 'HintSystem'),
'id': ('s', 'Id'),
'id_label': ('s', 'IdLabel'),
'id_type': ('s', 'IdType'),
'id_usage': ('s', 'IdUsage'),
'preferred_device': ('ay', 'PreferredDevice'),
'size': ('t', 'Size'),
'symlinks': ('aay', 'Symlinks'),
}
@ -119,6 +123,38 @@ class Filesystem(Proxy):
properties = {'mount_points': ('aay', 'MountPoints')}
def get_disks():
"""List devices that can be ejected."""
devices = []
manager = _get_dbus_proxy(_OBJECTS['UDisks2'],
_INTERFACES['ObjectManager'])
objects = manager.GetManagedObjects()
for object_, interface_and_properties in objects.items():
if _INTERFACES['Block'] not in interface_and_properties:
continue
block = BlockDevice(object_)
if block.id_usage != 'filesystem':
continue
device = {
'device': block.device,
'label': block.id_label,
'size': block.size,
'filesystem_type': block.id_type,
'is_removable': not block.hint_system
}
try:
file_system = Filesystem(object_)
device['mount_points'] = file_system.mount_points
except Exception:
continue
devices.append(device)
return devices
def _mount(object_path):
"""Start the mount operation on an block device.