]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
node-proxy: move the output formatting logic to orchestrator
authorGuillaume Abrioux <gabrioux@ibm.com>
Wed, 6 Dec 2023 14:25:28 +0000 (14:25 +0000)
committerGuillaume Abrioux <gabrioux@ibm.com>
Thu, 25 Jan 2024 16:01:04 +0000 (16:01 +0000)
Implementing this in the cephadm module doesn't follow the general idea
of the orchestrator interface. This is where the output formatting should
be done so let's move the logic to the orchestrator module.

Signed-off-by: Guillaume Abrioux <gabrioux@ibm.com>
(cherry picked from commit aa170850b8e7f63120169b89e39b21bee2c5287e)

src/pybind/mgr/cephadm/module.py
src/pybind/mgr/orchestrator/_interface.py
src/pybind/mgr/orchestrator/module.py

index 249bdc11bd4c512c90ad3918fdcff25bd54e8162..df5a846c5a3961dc3cd7069d7dfbea5016e90b88 100644 (file)
@@ -1637,105 +1637,20 @@ Then run the following:
         return self._add_host(spec)
 
     @handle_orch_error
-    def hardware_status(self,
-                        hostname: Optional[str] = None,
-                        category: str = 'summary',
-                        format: Format = Format.plain) -> str:
-        """
-        Display hardware status summary
-
-        :param hostname: hostname
-        """
-
-        table_heading_mapping = {
-            'summary': ['HOST', 'STORAGE', 'CPU', 'NET', 'MEMORY', 'POWER', 'FANS'],
-            'firmwares': ['HOST', 'COMPONENT', 'NAME', 'DATE', 'VERSION', 'STATUS'],
-            'criticals': ['HOST', 'COMPONENT', 'NAME', 'STATUS', 'STATE'],
-            'memory': ['HOST', 'NAME', 'STATUS', 'STATE'],
-            'storage': ['HOST', 'NAME', 'MODEL', 'SIZE', 'PROTOCOL', 'SN', 'STATUS', 'STATE'],
-            'processors': ['HOST', 'NAME', 'MODEL', 'CORES', 'THREADS', 'STATUS', 'STATE'],
-            'network': ['HOST', 'NAME', 'SPEED', 'STATUS', 'STATE'],
-            'power': ['HOST', 'ID', 'NAME', 'MODEL', 'MANUFACTURER', 'STATUS', 'STATE'],
-            'fans': ['HOST', 'ID', 'NAME', 'STATUS', 'STATE']
-        }
-
-        if category not in table_heading_mapping.keys():
-            return f"'{category}' is not a valid category."
+    def node_proxy_summary(self, hostname: Optional[str] = None) -> Dict[str, Any]:
+        return self.node_proxy.summary(hostname=hostname)
 
-        table_headings = table_heading_mapping.get(category, [])
-        table = PrettyTable(table_headings,border=True)
-        output = None
-
-        if category == 'summary':
-            data = self.node_proxy.summary(hostname=hostname)
-            if format == Format.json:
-                output = json.dumps(data)
-            else:
-                for k, v in data.items():
-                    row = [k]
-                    row.extend([v['status'][key] for key in ['storage', 'processors', 'network', 'memory', 'power', 'fans']])
-                    table.add_row(row)
-                output = table.get_string()
-        elif category == 'firmwares':
-            output = "Missing host name" if hostname is None else self._firmwares_table(hostname, table, format)
-        elif category == 'criticals':
-            output = self._criticals_table(hostname, table, format)
-        else:
-            output = self._common_table(category, hostname, table, format)
-
-        return output if output else table.get_string()
-
-    def _firmwares_table(self, hostname, table, format):
-        data = self.node_proxy.firmwares(hostname=hostname)
-        if format == Format.json:
-            return json.dumps(data)
-        for host, details in data.items():
-            for k, v in details.items():
-                table.add_row((host, k, v['name'], v['release_date'], v['version'], v['status']['health']))
-        return table.get_string()
-
-    def _criticals_table(self, hostname, table, format):
-        data = self.node_proxy.criticals(hostname=hostname)
-        if format == Format.json:
-            return json.dumps(data)
-        for host, host_details in data.items():
-            for component, component_details in host_details.items():
-                for member, member_details in component_details.items():
-                    description = member_details.get('description') or member_details.get('name')
-                    table.add_row((host, component, description, member_details['status']['health'], member_details['status']['state']))
-        return table.get_string()
-
-    def _common_table(self, category, hostname, table, format):
-        data = self.node_proxy.common(endpoint=category, hostname=hostname)
-        if format == Format.json:
-            return json.dumps(data)
-        mapping = {
-            'memory': ('description', 'health', 'state'),
-            'storage': ('description', 'model', 'capacity_bytes', 'protocol', 'serial_number', 'health', 'state'),
-            'processors': ('model', 'total_cores', 'total_threads', 'health', 'state'),
-            'network': ('name', 'speed_mbps', 'health', 'state'),
-            'power': ('name', 'model', 'manufacturer', 'health', 'state'),
-            'fans': ('name', 'health', 'state')
-        }
-
-        fields = mapping.get(category, ())
-        for host, details in data.items():
-            for k, v in details.items():
-                row = []
-                for field in fields:
-                    if field in v:
-                        row.append(v[field])
-                    elif field in v.get('status', {}):
-                        row.append(v['status'][field])
-                    else:
-                        row.append('')
-                if category in ('power', 'fans', 'processors'):
-                    table.add_row((host,) + (k,) + tuple(row))
-                else:
-                    table.add_row((host,) + tuple(row))
+    @handle_orch_error
+    def node_proxy_firmwares(self, hostname: Optional[str] = None) -> Dict[str, Any]:
+        return self.node_proxy.firmwares(hostname=hostname)
 
+    @handle_orch_error
+    def node_proxy_criticals(self, hostname: Optional[str] = None) -> Dict[str, Any]:
+        return self.node_proxy.criticals(hostname=hostname)
 
-        return table.get_string()
+    @handle_orch_error
+    def node_proxy_common(self, category: str, hostname: Optional[str] = None) -> Dict[str, Any]:
+        return self.node_proxy.common(category, hostname=hostname)
 
     @handle_orch_error
     def remove_host(self, host: str, force: bool = False, offline: bool = False) -> str:
index 6157e5eec304431ded637b5feaa19a244e48313e..5878f3ed6488599b5a9f8fff61f66a14d6057515 100644 (file)
@@ -368,6 +368,38 @@ class Orchestrator(object):
         """
         raise NotImplementedError()
 
+    def node_proxy_summary(self, hostname: Optional[str] = None) -> OrchResult[Dict[str, Any]]:
+        """
+        Return node-proxy summary
+
+        :param hostname: hostname
+        """
+        raise NotImplementedError()
+
+    def node_proxy_firmwares(self, hostname: Optional[str] = None) -> OrchResult[Dict[str, Any]]:
+        """
+        Return node-proxy firmwares report
+
+        :param hostname: hostname
+        """
+        raise NotImplementedError()
+
+    def node_proxy_criticals(self, hostname: Optional[str] = None) -> OrchResult[Dict[str, Any]]:
+        """
+        Return node-proxy criticals report
+
+        :param hostname: hostname
+        """
+        raise NotImplementedError()
+
+    def node_proxy_common(self, category: str, hostname: Optional[str] = None) -> OrchResult[Dict[str, Any]]:
+        """
+        Return node-proxy generic report
+
+        :param hostname: hostname
+        """
+        raise NotImplementedError()
+
     def remove_host(self, host: str, force: bool, offline: bool) -> OrchResult[str]:
         """
         Remove a host from the orchestrator inventory.
index 1c288a848f2f6fcb3574fc0c00c322675e261437..561367195b786b3de6bacaa1ab6f305017b9eb96 100644 (file)
@@ -489,10 +489,106 @@ class OrchestratorCli(OrchestratorClientMixin, MgrModule,
 
     @_cli_write_command('orch hardware status')
     def _hardware_status(self, hostname: Optional[str] = None, _end_positional_: int = 0, category: str = 'summary', format: Format = Format.plain) -> HandleCommandResult:
-        """Display hardware status"""
-        completion = self.hardware_status(hostname, category, format)
-        raise_if_exception(completion)
-        return HandleCommandResult(stdout=completion.result_str())
+        """
+        Display hardware status summary
+
+        :param hostname: hostname
+        """
+        table_heading_mapping = {
+            'summary': ['HOST', 'STORAGE', 'CPU', 'NET', 'MEMORY', 'POWER', 'FANS'],
+            'firmwares': ['HOST', 'COMPONENT', 'NAME', 'DATE', 'VERSION', 'STATUS'],
+            'criticals': ['HOST', 'COMPONENT', 'NAME', 'STATUS', 'STATE'],
+            'memory': ['HOST', 'NAME', 'STATUS', 'STATE'],
+            'storage': ['HOST', 'NAME', 'MODEL', 'SIZE', 'PROTOCOL', 'SN', 'STATUS', 'STATE'],
+            'processors': ['HOST', 'NAME', 'MODEL', 'CORES', 'THREADS', 'STATUS', 'STATE'],
+            'network': ['HOST', 'NAME', 'SPEED', 'STATUS', 'STATE'],
+            'power': ['HOST', 'ID', 'NAME', 'MODEL', 'MANUFACTURER', 'STATUS', 'STATE'],
+            'fans': ['HOST', 'ID', 'NAME', 'STATUS', 'STATE']
+        }
+
+        if category not in table_heading_mapping.keys():
+            return HandleCommandResult(stdout=f"'{category}' is not a valid category.")
+
+        table_headings = table_heading_mapping.get(category, [])
+        table = PrettyTable(table_headings, border=True)
+        output = ''
+
+        if category == 'summary':
+            completion = self.node_proxy_summary(hostname=hostname)
+            summary: Dict[str, Any] = raise_if_exception(completion)
+            if format == Format.json:
+                output = json.dumps(summary)
+            else:
+                for k, v in summary.items():
+                    row = [k]
+                    row.extend([v['status'][key] for key in ['storage', 'processors', 'network', 'memory', 'power', 'fans']])
+                    table.add_row(row)
+                output = table.get_string()
+        elif category == 'firmwares':
+            output = "Missing host name" if hostname is None else self._firmwares_table(hostname, table, format)
+        elif category == 'criticals':
+            output = self._criticals_table(hostname, table, format)
+        else:
+            output = self._common_table(category, hostname, table, format)
+
+        return HandleCommandResult(stdout=output)
+
+    def _firmwares_table(self, hostname: Optional[str], table: PrettyTable, format: Format) -> str:
+        completion = self.node_proxy_firmwares(hostname=hostname)
+        data = raise_if_exception(completion)
+        # data = self.node_proxy_firmware(hostname=hostname)
+        if format == Format.json:
+            return json.dumps(data)
+        for host, details in data.items():
+            for k, v in details.items():
+                table.add_row((host, k, v['name'], v['release_date'], v['version'], v['status']['health']))
+        return table.get_string()
+
+    def _criticals_table(self, hostname: Optional[str], table: PrettyTable, format: Format) -> str:
+        completion = self.node_proxy_criticals(hostname=hostname)
+        data = raise_if_exception(completion)
+        # data = self.node_proxy_criticals(hostname=hostname)
+        if format == Format.json:
+            return json.dumps(data)
+        for host, host_details in data.items():
+            for component, component_details in host_details.items():
+                for member, member_details in component_details.items():
+                    description = member_details.get('description') or member_details.get('name')
+                    table.add_row((host, component, description, member_details['status']['health'], member_details['status']['state']))
+        return table.get_string()
+
+    def _common_table(self, category: str, hostname: Optional[str], table: PrettyTable, format: Format) -> str:
+        completion = self.node_proxy_common(category=category, hostname=hostname)
+        data = raise_if_exception(completion)
+        # data = self.node_proxy_common(category=category, hostname=hostname)
+        if format == Format.json:
+            return json.dumps(data)
+        mapping = {
+            'memory': ('description', 'health', 'state'),
+            'storage': ('description', 'model', 'capacity_bytes', 'protocol', 'serial_number', 'health', 'state'),
+            'processors': ('model', 'total_cores', 'total_threads', 'health', 'state'),
+            'network': ('name', 'speed_mbps', 'health', 'state'),
+            'power': ('name', 'model', 'manufacturer', 'health', 'state'),
+            'fans': ('name', 'health', 'state')
+        }
+
+        fields = mapping.get(category, ())
+        for host, details in data.items():
+            for k, v in details.items():
+                row = []
+                for field in fields:
+                    if field in v:
+                        row.append(v[field])
+                    elif field in v.get('status', {}):
+                        row.append(v['status'][field])
+                    else:
+                        row.append('')
+                if category in ('power', 'fans', 'processors'):
+                    table.add_row((host,) + (k,) + tuple(row))
+                else:
+                    table.add_row((host,) + tuple(row))
+
+        return table.get_string()
 
     @_cli_write_command('orch host rm')
     def _remove_host(self, hostname: str, force: bool = False, offline: bool = False) -> HandleCommandResult: