Skip to content

Commit 253a63c

Browse files
committed
Handle missing D-Bus property in pool listing
Systematically test by simulating each one raising an exception. Signed-off-by: mulhern <amulhern@redhat.com>
1 parent 4c18364 commit 253a63c

2 files changed

Lines changed: 316 additions & 82 deletions

File tree

src/stratis_cli/_actions/_list_pool.py

Lines changed: 189 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@
3030
# isort: THIRDPARTY
3131
from justbytes import Range
3232

33+
# isort: FIRSTPARTY
34+
from dbus_client_gen import DbusClientMissingPropertyError
35+
3336
from .._alerts import (
3437
PoolAllocSpaceAlert,
3538
PoolDeviceSizeChangeAlert,
@@ -245,12 +248,14 @@ class Default(ListPool):
245248
def metadata_version(mopool: Any) -> MetadataVersion | None:
246249
"""
247250
Return the metadata version, dealing with the possibility that it
248-
might be an error string.
251+
might be unparsable.
249252
"""
250253
try:
251254
return MetadataVersion(int(mopool.MetadataVersion()))
252255
except ValueError: # pragma: no cover
253256
return None
257+
except DbusClientMissingPropertyError:
258+
return None
254259

255260
@staticmethod
256261
def _volume_key_loaded(mopool: Any) -> tuple[bool, bool | str]:
@@ -268,62 +273,86 @@ def alert_codes(
268273
mopool: Any,
269274
) -> list[PoolEncryptionAlert | PoolAllocSpaceAlert | PoolMaintenanceAlert]:
270275
"""
271-
Return alert code objects for a pool.
276+
Return alert code objects for a pool. If some D-Bus properties are
277+
missing, the information related to those D-Bus properties is simply
278+
omitted.
272279
273280
:param mopool: object to access pool properties
274281
275282
:returns: list of alerts obtainable from GetManagedObjects properties
276283
"""
277-
action_availability = PoolActionAvailability[str(mopool.AvailableActions())]
278-
availability_alerts = action_availability.pool_maintenance_alerts()
284+
try:
285+
action_availability = PoolActionAvailability[str(mopool.AvailableActions())]
286+
availability_alerts = action_availability.pool_maintenance_alerts()
279287

280-
no_alloc_space_alerts = (
281-
[PoolAllocSpaceAlert.NO_ALLOC_SPACE] if mopool.NoAllocSpace() else []
282-
)
288+
except DbusClientMissingPropertyError:
289+
availability_alerts = []
283290

284-
metadata_version = Default.metadata_version(mopool)
291+
try:
292+
no_alloc_space_alerts = (
293+
[PoolAllocSpaceAlert.NO_ALLOC_SPACE] if mopool.NoAllocSpace() else []
294+
)
295+
except DbusClientMissingPropertyError:
296+
no_alloc_space_alerts = []
285297

286-
(vkl_is_bool, volume_key_loaded) = Default._volume_key_loaded(mopool)
287-
288-
pool_encryption_alerts: list[PoolEncryptionAlert] = (
289-
[PoolEncryptionAlert.VOLUME_KEY_NOT_LOADED]
290-
if metadata_version is MetadataVersion.V2
291-
and mopool.Encrypted()
292-
and vkl_is_bool
293-
and not volume_key_loaded
294-
else []
295-
) + (
296-
[PoolEncryptionAlert.VOLUME_KEY_STATUS_UNKNOWN]
297-
if metadata_version is MetadataVersion.V2
298-
and mopool.Encrypted()
299-
and not vkl_is_bool
300-
else []
301-
)
298+
metadata_version = Default.metadata_version(mopool)
302299

300+
try:
301+
(vkl_is_bool, volume_key_loaded) = Default._volume_key_loaded(mopool)
302+
encrypted = bool(mopool.Encrypted())
303+
pool_encryption_alerts: list[PoolEncryptionAlert] = (
304+
[PoolEncryptionAlert.VOLUME_KEY_NOT_LOADED]
305+
if metadata_version is MetadataVersion.V2
306+
and encrypted
307+
and vkl_is_bool
308+
and not volume_key_loaded
309+
else []
310+
) + (
311+
[PoolEncryptionAlert.VOLUME_KEY_STATUS_UNKNOWN]
312+
if metadata_version is MetadataVersion.V2
313+
and encrypted
314+
and not vkl_is_bool
315+
else []
316+
)
317+
except DbusClientMissingPropertyError:
318+
pool_encryption_alerts = [PoolEncryptionAlert.VOLUME_KEY_STATUS_UNKNOWN]
303319
return availability_alerts + no_alloc_space_alerts + pool_encryption_alerts
304320

305321
@staticmethod
306322
def size_triple(mopool: Any) -> SizeTriple:
307323
"""
308324
Calculate SizeTriple from size information.
309325
"""
310-
return SizeTriple(
311-
Range(mopool.TotalPhysicalSize()),
312-
get_property(mopool.TotalPhysicalUsed(), Range, None),
313-
)
326+
try:
327+
size = Range(mopool.TotalPhysicalSize())
328+
except DbusClientMissingPropertyError:
329+
size = None
330+
331+
try:
332+
used = get_property(mopool.TotalPhysicalUsed(), Range, None)
333+
except DbusClientMissingPropertyError:
334+
used = None
335+
336+
return SizeTriple(size, used)
314337

315338
def uuid_str(self, mopool: Any) -> str:
316339
"""
317340
Return a string representation of UUID, correctly formatted.
318341
"""
319-
return self.uuid_formatter(mopool.Uuid())
342+
try:
343+
return self.uuid_formatter(mopool.Uuid())
344+
except DbusClientMissingPropertyError:
345+
return TABLE_UNKNOWN_STRING
320346

321347
@staticmethod
322348
def name_str(mopool: Any) -> str:
323349
"""
324350
Return a string representation of the pool name.
325351
"""
326-
return mopool.Name()
352+
try:
353+
return mopool.Name()
354+
except DbusClientMissingPropertyError:
355+
return TABLE_UNKNOWN_STRING
327356

328357

329358
class DefaultDetail(Default): # pylint: disable=too-few-public-methods
@@ -343,7 +372,7 @@ def __init__(self, uuid_formatter: Callable[[str | UUID], str], selection: PoolI
343372

344373
def _print_detail_view(
345374
self, pool_object_path: str, mopool: Any, alerts: DeviceSizeChangedAlerts
346-
): # pylint: disable=too-many-locals
375+
): # pylint: disable=too-many-locals,too-many-statements,too-many-branches
347376
"""
348377
Print the detailed view for a single pool.
349378
@@ -352,8 +381,6 @@ def _print_detail_view(
352381
:param MOPool mopool: properties of the pool
353382
:param DeviceSizeChangedAlerts alerts: pool alerts
354383
"""
355-
encrypted = mopool.Encrypted()
356-
357384
print(f"UUID: {self.uuid_str(mopool)}")
358385
print(f"Name: {Default.name_str(mopool)}")
359386

@@ -363,75 +390,130 @@ def _print_detail_view(
363390
+ Default.alert_codes(mopool)
364391
)
365392
print(f"Alerts: {len(alert_summary)}")
366-
for line in alert_summary: # pragma: no cover
393+
for line in alert_summary:
367394
print(f" {line}")
368395

369396
metadata_version = Default.metadata_version(mopool)
397+
metadata_version_str = (
398+
metadata_version if metadata_version is not None else TABLE_UNKNOWN_STRING
399+
)
400+
print(f"Metadata Version: {metadata_version_str}")
370401

371-
print(f"Metadata Version: {metadata_version}")
402+
try:
403+
actions_allowed_str = PoolActionAvailability[
404+
str(mopool.AvailableActions())
405+
].name
406+
except DbusClientMissingPropertyError:
407+
actions_allowed_str = TABLE_UNKNOWN_STRING
408+
print(f"Actions Allowed: {actions_allowed_str}")
372409

373-
print(
374-
f"Actions Allowed: "
375-
f"{PoolActionAvailability[str(mopool.AvailableActions())].name}"
376-
)
377-
print(f"Cache: {'Yes' if mopool.HasCache() else 'No'}")
378-
print(f"Filesystem Limit: {mopool.FsLimit()}")
379-
print(
380-
f"Allows Overprovisioning: "
381-
f"{'Yes' if mopool.Overprovisioning() else 'No'}"
382-
)
410+
try:
411+
cache_str = "Yes" if mopool.HasCache() else "No"
412+
except DbusClientMissingPropertyError:
413+
cache_str = TABLE_UNKNOWN_STRING
414+
print(f"Cache: {cache_str}")
383415

384-
if encrypted:
416+
try:
417+
fs_limit_str = mopool.FsLimit()
418+
except DbusClientMissingPropertyError:
419+
fs_limit_str = TABLE_UNKNOWN_STRING
420+
print(f"Filesystem Limit: {fs_limit_str}")
421+
422+
try:
423+
allow_overprovisioning_str = "Yes" if mopool.Overprovisioning() else "No"
424+
except DbusClientMissingPropertyError:
425+
allow_overprovisioning_str = TABLE_UNKNOWN_STRING
426+
print(f"Allows Overprovisioning: {allow_overprovisioning_str}")
427+
428+
try:
429+
encrypted = bool(mopool.Encrypted())
430+
except DbusClientMissingPropertyError:
431+
encrypted = None
432+
433+
if encrypted is None:
434+
print(f"Encryption Enabled: {TABLE_UNKNOWN_STRING}")
435+
elif encrypted is True:
385436
print("Encryption Enabled: Yes")
386437

387438
if metadata_version is MetadataVersion.V1: # pragma: no cover
388-
key_description_str = _non_existent_or_inconsistent_to_str(
389-
EncryptionInfoKeyDescription(mopool.KeyDescriptions())
390-
)
439+
try:
440+
key_description_str = _non_existent_or_inconsistent_to_str(
441+
EncryptionInfoKeyDescription(mopool.KeyDescriptions())
442+
)
443+
except DbusClientMissingPropertyError:
444+
key_description_str = TABLE_UNKNOWN_STRING
391445
print(f" Key Description: {key_description_str}")
392446

393-
clevis_info_str = _non_existent_or_inconsistent_to_str(
394-
EncryptionInfoClevis(mopool.ClevisInfos()),
395-
interp=_clevis_to_str,
396-
)
447+
try:
448+
clevis_info_str = _non_existent_or_inconsistent_to_str(
449+
EncryptionInfoClevis(mopool.ClevisInfos()),
450+
interp=_clevis_to_str,
451+
)
452+
except DbusClientMissingPropertyError:
453+
clevis_info_str = TABLE_UNKNOWN_STRING
397454
print(f" Clevis Configuration: {clevis_info_str}")
398455
elif metadata_version is MetadataVersion.V2:
399-
encryption_infos = sorted(
400-
[
456+
457+
try:
458+
free_str = get_property(
459+
mopool.FreeTokenSlots(),
460+
lambda x: str(int(x)),
461+
TABLE_UNKNOWN_STRING,
462+
)
463+
except DbusClientMissingPropertyError:
464+
free_str = TABLE_UNKNOWN_STRING
465+
print(f" Free Token Slots Remaining: {free_str}")
466+
467+
try:
468+
key_encryption_infos = [
401469
TokenSlotInfo(token_slot, key=str(description))
402470
for token_slot, description in mopool.KeyDescriptions()
403471
]
404-
+ [
472+
except DbusClientMissingPropertyError:
473+
key_encryption_infos = []
474+
475+
try:
476+
clevis_encryption_infos = [
405477
TokenSlotInfo(
406478
token_slot, clevis=(str(pin), json.loads(str(config)))
407479
)
408480
for token_slot, (pin, config) in mopool.ClevisInfos()
409-
],
410-
key=lambda x: x.token_slot,
411-
)
481+
]
482+
except DbusClientMissingPropertyError:
483+
clevis_encryption_infos = []
412484

413-
free_valid, free = mopool.FreeTokenSlots()
414-
print(
415-
f' Free Token Slots Remaining: {int(free) if free_valid else "<UNKNOWN>"}'
485+
encryption_infos = sorted(
486+
key_encryption_infos + clevis_encryption_infos,
487+
key=lambda x: x.token_slot,
416488
)
417-
418-
for info in encryption_infos:
419-
for line in str(info).split(os.linesep):
420-
print(f" {line}")
421-
else: # pragma: no cover
422-
pass
489+
if encryption_infos == []: # pragma: no cover
490+
print(" No token slot information available")
491+
else:
492+
for info in encryption_infos:
493+
for line in str(info).split(os.linesep):
494+
print(f" {line}")
423495
else:
424496
print("Encryption Enabled: No")
425497

426498
size_triple = Default.size_triple(mopool)
427499

428-
print(f"Fully Allocated: {'Yes' if mopool.NoAllocSpace() else 'No'}")
429-
print(f" Size: {size_triple.total()}")
430-
print(f" Allocated: {Range(mopool.AllocatedSize())}")
431-
print(
432-
" Used: "
433-
f"{TABLE_UNKNOWN_STRING if size_triple.used() is None else size_triple.used()}"
434-
)
500+
def size_str(value: Range | None) -> str:
501+
return TABLE_UNKNOWN_STRING if value is None else str(value)
502+
503+
try:
504+
fully_allocated_str = "Yes" if mopool.NoAllocSpace() else "No"
505+
except DbusClientMissingPropertyError:
506+
fully_allocated_str = TABLE_UNKNOWN_STRING
507+
print(f"Fully Allocated: {fully_allocated_str}")
508+
509+
print(f" Size: {size_str(size_triple.total())}")
510+
511+
try:
512+
allocated_size = Range(mopool.AllocatedSize())
513+
except DbusClientMissingPropertyError:
514+
allocated_size = None
515+
print(f" Allocated: {size_str(allocated_size)}")
516+
print(f" Used: {size_str(size_triple.used())}")
435517

436518
def display(self):
437519
"""
@@ -507,7 +589,7 @@ def properties_string(mopool: Any) -> str:
507589
:type props_map: dict of str * any
508590
"""
509591

510-
def gen_string(has_property: bool, code: str) -> str:
592+
def gen_string(has_property: bool | None, code: str) -> str:
511593
"""
512594
Generate the display string for a boolean property
513595
@@ -516,15 +598,41 @@ def gen_string(has_property: bool, code: str) -> str:
516598
:returns: the generated string
517599
:rtype: str
518600
"""
519-
return (" " if has_property else "~") + code
601+
return (
602+
"?"
603+
if has_property is None
604+
else (" " if has_property else "~") + code
605+
)
520606

521607
metadata_version = Default.metadata_version(mopool)
522608

609+
try:
610+
has_cache = bool(mopool.HasCache())
611+
except DbusClientMissingPropertyError:
612+
has_cache = None
613+
614+
try:
615+
encrypted = bool(mopool.Encrypted())
616+
except DbusClientMissingPropertyError:
617+
encrypted = None
618+
619+
try:
620+
overprovisioning = bool(mopool.Overprovisioning())
621+
except DbusClientMissingPropertyError:
622+
overprovisioning = None
623+
523624
props_list = [
524-
(metadata_version in (MetadataVersion.V1, None), "Le"),
525-
(bool(mopool.HasCache()), "Ca"),
526-
(bool(mopool.Encrypted()), "Cr"),
527-
(bool(mopool.Overprovisioning()), "Op"),
625+
(
626+
(
627+
None
628+
if metadata_version is None
629+
else metadata_version is MetadataVersion.V1
630+
),
631+
"Le",
632+
),
633+
(has_cache, "Ca"),
634+
(encrypted, "Cr"),
635+
(overprovisioning, "Op"),
528636
]
529637
return ",".join(gen_string(x, y) for x, y in props_list)
530638

0 commit comments

Comments
 (0)