]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
orchestrator: intergrate LSM information with device ls
authorPaul Cuzner <pcuzner@redhat.com>
Mon, 31 Aug 2020 02:20:15 +0000 (14:20 +1200)
committerPaul Cuzner <pcuzner@redhat.com>
Mon, 31 Aug 2020 02:20:15 +0000 (14:20 +1200)
libstoragemgmt metatdata is now available with ceph-volume,
so this patch reformats the plain text output mode of the
orch device ls command to include device health and LED
states.

In addition ; the headings have been camel cased for readability,
the device size is given in dec (since you buy drives in GB not GiB),
a new wide mode has been added and the default output focuses
on the most frequently referred to fields to keep it brief.

Signed-off-by: Paul Cuzner <pcuzner@redhat.com>
src/pybind/mgr/orchestrator/module.py
src/python-common/ceph/deployment/inventory.py

index f46ab29f6346392ed91561db2fa4df41f95b5ad5..4650d38ca89b7f70444c83c4a3c5af73646e59a2 100644 (file)
@@ -12,7 +12,7 @@ from ceph.deployment.inventory import Device
 from ceph.deployment.drive_group import DriveGroupSpec, DeviceSelection
 from ceph.deployment.service_spec import PlacementSpec, ServiceSpec
 
-from mgr_util import format_bytes, to_pretty_timedelta
+from mgr_util import format_bytes, to_pretty_timedelta, format_dimless
 from mgr_module import MgrModule, HandleCommandResult
 
 from ._interface import OrchestratorClientMixin, DeviceLightLoc, _cli_read_command, \
@@ -364,9 +364,10 @@ class OrchestratorCli(OrchestratorClientMixin, MgrModule,
         'orch device ls',
         "name=hostname,type=CephString,n=N,req=false "
         "name=format,type=CephChoices,strings=plain|json|json-pretty|yaml,req=false "
-        "name=refresh,type=CephBool,req=false",
+        "name=refresh,type=CephBool,req=false "
+        "name=wide,type=CephBool,req=false",
         'List devices on a host')
-    def _list_devices(self, hostname=None, format='plain', refresh=False):
+    def _list_devices(self, hostname=None, format='plain', refresh=False, wide=False):
         # type: (Optional[List[str]], str, bool) -> HandleCommandResult
         """
         Provide information about storage devices present in cluster hosts
@@ -385,32 +386,71 @@ class OrchestratorCli(OrchestratorClientMixin, MgrModule,
         if format != 'plain':
             return HandleCommandResult(stdout=to_format(completion.result, format, many=True, cls=InventoryHost))
         else:
-            out = []
+            display_map = {
+                "Unsupported": "N/A",
+                "N/A": "N/A",
+                "On": "On",
+                "Off": "Off",
+                True: "Yes",
+                False: "No",
+            }
 
-            table = PrettyTable(
-                ['HOST', 'PATH', 'TYPE', 'SIZE', 'DEVICE_ID', 'MODEL', 'VENDOR', 'ROTATIONAL', 'AVAIL',
-                 'REJECT REASONS'],
-                border=False)
+            out = []
+            if wide:
+                table = PrettyTable(
+                    ['Hostname', 'Path', 'Type', 'Transport', 'RPM', 'Vendor', 'Model', 'Serial', 'Size', 'Health',
+                     'Ident', 'Fault', 'Available', 'Reject Reasons'],
+                    border=False)
+            else:
+                table = PrettyTable(
+                    ['Hostname', 'Path', 'Type', 'Serial', 'Size', 'Health', 'Ident', 'Fault', 'Available'],
+                    border=False)
             table.align = 'l'
             table._align['SIZE'] = 'r'
             table.left_padding_width = 0
             table.right_padding_width = 2
             for host_ in completion.result:  # type: InventoryHost
                 for d in host_.devices.devices:  # type: Device
-                    table.add_row(
-                        (
-                            host_.name,
-                            d.path,
-                            d.human_readable_type,
-                            format_bytes(d.sys_api.get('size', 0), 5),
-                            d.device_id,
-                            d.sys_api.get('model') or 'n/a',
-                            d.sys_api.get('vendor') or 'n/a',
-                            d.sys_api.get('rotational') or 'n/a',
-                            d.available,
-                            ', '.join(d.rejected_reasons)
+
+                    led_ident = 'N/A'
+                    led_fail = 'N/A'
+                    if d.lsm_data.get('ledSupport', None):
+                        led_ident = d.lsm_data['ledSupport']['IDENTstatus']
+                        led_fail = d.lsm_data['ledSupport']['FAILstatus']
+
+                    if wide:
+                        table.add_row(
+                            (
+                                host_.name,
+                                d.path,
+                                d.human_readable_type,
+                                d.lsm_data.get('transport', 'Unknown'),
+                                d.lsm_data.get('rpm', 'Unknown'),
+                                d.sys_api.get('vendor') or 'N/A',
+                                d.sys_api.get('model') or 'N/A',
+                                d.lsm_data.get('serialNum', d.device_id.split('_')[-1]),
+                                format_dimless(d.sys_api.get('size', 0), 5),
+                                d.lsm_data.get('health', 'Unknown'),
+                                display_map[led_ident],
+                                display_map[led_fail],
+                                display_map[d.available],
+                                ', '.join(d.rejected_reasons)
+                            )
+                        )
+                    else:
+                        table.add_row(
+                            (
+                                host_.name,
+                                d.path,
+                                d.human_readable_type,
+                                d.lsm_data.get('serialNum', d.device_id.split('_')[-1]),
+                                format_dimless(d.sys_api.get('size', 0), 5),
+                                d.lsm_data.get('health', 'Unknown'),
+                                display_map[led_ident],
+                                display_map[led_fail],
+                                display_map[d.available]
+                            )
                         )
-                    )
             out.append(table.get_string())
             return HandleCommandResult(stdout='\n'.join(out))
 
index 94dcb5024b5bd6ab39fce30398a91cab5ced854d..9bea5c8cdf0e6d1a69450255df26a5483f8b317e 100644 (file)
@@ -40,7 +40,8 @@ class Device(object):
         'sys_api',
         'lvs',
         'human_readable_type',
-        'device_id'
+        'device_id',
+        'lsm_data',
     ]
 
     def __init__(self,
@@ -50,6 +51,7 @@ class Device(object):
                  rejected_reasons=None,  # type: Optional[List[str]]
                  lvs=None,  # type: Optional[List[str]]
                  device_id=None,  # type: Optional[str]
+                 lsm_data=None,  # type: Optional[str]
                  ):
         self.path = path
         self.sys_api = sys_api if sys_api is not None else {}  # type: Dict[str, Any]
@@ -57,6 +59,7 @@ class Device(object):
         self.rejected_reasons = rejected_reasons if rejected_reasons is not None else []
         self.lvs = lvs
         self.device_id = device_id
+        self.lsm_data = lsm_data
 
     def to_json(self):
         # type: () -> dict