diff options
author | Guillaume Abrioux <gabrioux@ibm.com> | 2024-04-09 17:07:45 +0200 |
---|---|---|
committer | Guillaume Abrioux <gabrioux@redhat.com> | 2024-05-06 09:06:49 +0200 |
commit | ce360a4a5f67329b95a4b75bc7b5e59dc7633637 (patch) | |
tree | e79f3b2becc20f61ba6e88010287e40cf0106b90 /src/pybind | |
parent | node-proxy: do not fail when empty data is received (diff) | |
download | ceph-ce360a4a5f67329b95a4b75bc7b5e59dc7633637.tar.xz ceph-ce360a4a5f67329b95a4b75bc7b5e59dc7633637.zip |
node-proxy: make the daemon discover endpoints
Add logic in order to explore the API.
This will allow node-proxy to be compatible with more
hardware.
Fixes: https://tracker.ceph.com/issues/65394
Signed-off-by: Guillaume Abrioux <gabrioux@ibm.com>
Diffstat (limited to 'src/pybind')
-rw-r--r-- | src/pybind/mgr/cephadm/agent.py | 26 | ||||
-rw-r--r-- | src/pybind/mgr/cephadm/inventory.py | 61 | ||||
-rw-r--r-- | src/pybind/mgr/cephadm/tests/node_proxy_data.py | 4 | ||||
-rw-r--r-- | src/pybind/mgr/cephadm/tests/test_node_proxy.py | 6 | ||||
-rw-r--r-- | src/pybind/mgr/orchestrator/module.py | 61 |
5 files changed, 89 insertions, 69 deletions
diff --git a/src/pybind/mgr/cephadm/agent.py b/src/pybind/mgr/cephadm/agent.py index 12c03901de8..e38122ddc4b 100644 --- a/src/pybind/mgr/cephadm/agent.py +++ b/src/pybind/mgr/cephadm/agent.py @@ -192,16 +192,18 @@ class NodeProxyEndpoint: """ nok_members: List[Dict[str, str]] = [] - for member in data.keys(): - _status = data[member]['status']['health'].lower() - if _status.lower() != 'ok': - state = data[member]['status']['state'] - _member = dict( - member=member, - status=_status, - state=state - ) - nok_members.append(_member) + for sys_id in data.keys(): + for member in data[sys_id].keys(): + _status = data[sys_id][member]['status']['health'].lower() + if _status.lower() != 'ok': + state = data[sys_id][member]['status']['state'] + _member = dict( + sys_id=sys_id, + member=member, + status=_status, + state=state + ) + nok_members.append(_member) return nok_members @@ -229,7 +231,7 @@ class NodeProxyEndpoint: """ for component in data['patch']['status'].keys(): - alert_name = f"HARDWARE_{component.upper()}" + alert_name = f'HARDWARE_{component.upper()}' self.mgr.remove_health_warning(alert_name) nok_members = self.get_nok_members(data['patch']['status'][component]) @@ -239,7 +241,7 @@ class NodeProxyEndpoint: alert_name, summary=f'{count} {component} member{"s" if count > 1 else ""} {"are" if count > 1 else "is"} not ok', count=count, - detail=[f"{member['member']} is {member['status']}: {member['state']}" for member in nok_members], + detail=[f"[{member['sys_id']}]: {member['member']} is {member['status']}: {member['state']}" for member in nok_members], ) @cherrypy.expose diff --git a/src/pybind/mgr/cephadm/inventory.py b/src/pybind/mgr/cephadm/inventory.py index cbaff8a5b00..5ecb142cb6a 100644 --- a/src/pybind/mgr/cephadm/inventory.py +++ b/src/pybind/mgr/cephadm/inventory.py @@ -1410,7 +1410,7 @@ class HostCache(): class NodeProxyCache: - def __init__(self, mgr: "CephadmOrchestrator") -> None: + def __init__(self, mgr: 'CephadmOrchestrator') -> None: self.mgr = mgr self.data: Dict[str, Any] = {} self.oob: Dict[str, Any] = {} @@ -1428,7 +1428,7 @@ class NodeProxyCache: if host not in self.mgr.inventory.keys(): # remove entry for host that no longer exists - self.mgr.set_store(f"{NODE_PROXY_CACHE_PREFIX}/data/{host}", None) + self.mgr.set_store(f'{NODE_PROXY_CACHE_PREFIX}/data/{host}', None) try: self.oob.pop(host) self.data.pop(host) @@ -1442,15 +1442,15 @@ class NodeProxyCache: def save(self, host: str = '', data: Dict[str, Any] = {}) -> None: - self.mgr.set_store(f"{NODE_PROXY_CACHE_PREFIX}/data/{host}", json.dumps(data)) + self.mgr.set_store(f'{NODE_PROXY_CACHE_PREFIX}/data/{host}', json.dumps(data)) def update_oob(self, host: str, host_oob_info: Dict[str, str]) -> None: self.oob[host] = host_oob_info - self.mgr.set_store(f"{NODE_PROXY_CACHE_PREFIX}/oob", json.dumps(self.oob)) + self.mgr.set_store(f'{NODE_PROXY_CACHE_PREFIX}/oob', json.dumps(self.oob)) def update_keyring(self, host: str, key: str) -> None: self.keyrings[host] = key - self.mgr.set_store(f"{NODE_PROXY_CACHE_PREFIX}/keyrings", json.dumps(self.keyrings)) + self.mgr.set_store(f'{NODE_PROXY_CACHE_PREFIX}/keyrings', json.dumps(self.keyrings)) def fullreport(self, **kw: Any) -> Dict[str, Any]: """ @@ -1500,19 +1500,29 @@ class NodeProxyCache: for host in hosts: _result[host] = {} _result[host]['status'] = {} + state: str = '' data = self.data[host] - for component in data['status'].keys(): - values = data['status'][component].values() - if is_error(values): - state = 'error' - elif is_unknown(values): + for component, details in data['status'].items(): + _sys_id_res: List[str] = [] + for element in details.values(): + values = element.values() + if is_error(values): + state = 'error' + elif is_unknown(values) or not values: + state = 'unknown' + else: + state = 'ok' + _sys_id_res.append(state) + if any([s == 'unknown' for s in _sys_id_res]): state = 'unknown' + elif any([s == 'error' for s in _sys_id_res]): + state = 'error' else: state = 'ok' _result[host]['status'][component] = state - _result[host]['sn'] = data['sn'] - _result[host]['host'] = data['host'] - _result[host]['firmwares'] = data['firmwares'] + _result[host]['sn'] = data['sn'] + _result[host]['host'] = data['host'] + _result[host]['status']['firmwares'] = data['firmwares'] return _result def common(self, endpoint: str, **kw: Any) -> Dict[str, Any]: @@ -1562,18 +1572,19 @@ class NodeProxyCache: def get_critical_from_host(self, hostname: str) -> Dict[str, Any]: results: Dict[str, Any] = {} - for component, data_component in self.data[hostname]['status'].items(): - if component not in results.keys(): - results[component] = {} - for member, data_member in data_component.items(): - if component == 'power': - data_member['status']['health'] = 'critical' - data_member['status']['state'] = 'unplugged' - if component == 'memory': - data_member['status']['health'] = 'critical' - data_member['status']['state'] = 'errors detected' - if data_member['status']['health'].lower() != 'ok': - results[component][member] = data_member + for sys_id, component in self.data[hostname]['status'].items(): + for component_name, data_component in component.items(): + if component_name not in results.keys(): + results[component_name] = {} + for member, data_member in data_component.items(): + if component_name == 'power': + data_member['status']['health'] = 'critical' + data_member['status']['state'] = 'unplugged' + if component_name == 'memory': + data_member['status']['health'] = 'critical' + data_member['status']['state'] = 'errors detected' + if data_member['status']['health'].lower() != 'ok': + results[component_name][member] = data_member return results def criticals(self, **kw: Any) -> Dict[str, Any]: diff --git a/src/pybind/mgr/cephadm/tests/node_proxy_data.py b/src/pybind/mgr/cephadm/tests/node_proxy_data.py index 37e6aaa46c8..fa768f1d4c6 100644 --- a/src/pybind/mgr/cephadm/tests/node_proxy_data.py +++ b/src/pybind/mgr/cephadm/tests/node_proxy_data.py @@ -1,3 +1,3 @@ -full_set_with_critical = {'host': 'host01', 'sn': '12345', 'status': {'storage': {'disk.bay.0:enclosure.internal.0-1:raid.integrated.1-1': {'description': 'Solid State Disk 0:1:0', 'entity': 'RAID.Integrated.1-1', 'capacity_bytes': 959656755200, 'model': 'KPM5XVUG960G', 'protocol': 'SAS', 'serial_number': '8080A1CRTP5F', 'status': {'health': 'Critical', 'healthrollup': 'OK', 'state': 'Enabled'}, 'physical_location': {'partlocation': {'locationordinalvalue': 0, 'locationtype': 'Slot'}}}, 'disk.bay.9:enclosure.internal.0-1': {'description': 'PCIe SSD in Slot 9 in Bay 1', 'entity': 'CPU.1', 'capacity_bytes': 1600321314816, 'model': 'Dell Express Flash NVMe P4610 1.6TB SFF', 'protocol': 'PCIe', 'serial_number': 'PHLN035305MN1P6AGN', 'status': {'health': 'Critical', 'healthrollup': 'OK', 'state': 'Enabled'}, 'physical_location': {'partlocation': {'locationordinalvalue': 9, 'locationtype': 'Slot'}}}}, 'processors': {'cpu.socket.2': {'description': 'Represents the properties of a Processor attached to this System', 'total_cores': 20, 'total_threads': 40, 'processor_type': 'CPU', 'model': 'Intel(R) Xeon(R) Gold 6230 CPU @ 2.10GHz', 'status': {'health': 'OK', 'state': 'Enabled'}, 'manufacturer': 'Intel'}}, 'network': {'nic.slot.1-1-1': {'description': 'NIC in Slot 1 Port 1 Partition 1', 'name': 'System Ethernet Interface', 'speed_mbps': 0, 'status': {'health': 'OK', 'state': 'StandbyOffline'}}}, 'memory': {'dimm.socket.a1': {'description': 'DIMM A1', 'memory_device_type': 'DDR4', 'capacity_mi_b': 31237, 'status': {'health': 'Critical', 'state': 'Enabled'}}}}, 'firmwares': {}} +full_set_with_critical = {'host': 'host01', 'sn': '12345', 'status': {'storage': {'1': {'disk.bay.0:enclosure.internal.0-1:raid.integrated.1-1': {'description': 'Solid State Disk 0:1:0', 'entity': 'RAID.Integrated.1-1', 'capacity_bytes': 959656755200, 'model': 'KPM5XVUG960G', 'protocol': 'SAS', 'serial_number': '8080A1CRTP5F', 'status': {'health': 'Critical', 'healthrollup': 'OK', 'state': 'Enabled'}, 'physical_location': {'partlocation': {'locationordinalvalue': 0, 'locationtype': 'Slot'}}}, 'disk.bay.9:enclosure.internal.0-1': {'description': 'PCIe SSD in Slot 9 in Bay 1', 'entity': 'CPU.1', 'capacity_bytes': 1600321314816, 'model': 'Dell Express Flash NVMe P4610 1.6TB SFF', 'protocol': 'PCIe', 'serial_number': 'PHLN035305MN1P6AGN', 'status': {'health': 'Critical', 'healthrollup': 'OK', 'state': 'Enabled'}, 'physical_location': {'partlocation': {'locationordinalvalue': 9, 'locationtype': 'Slot'}}}}}, 'processors': {'1': {'cpu.socket.2': {'description': 'Represents the properties of a Processor attached to this System', 'total_cores': 20, 'total_threads': 40, 'processor_type': 'CPU', 'model': 'Intel(R) Xeon(R) Gold 6230 CPU @ 2.10GHz', 'status': {'health': 'OK', 'state': 'Enabled'}, 'manufacturer': 'Intel'}}}, 'network': {'1': {'nic.slot.1-1-1': {'description': 'NIC in Slot 1 Port 1 Partition 1', 'name': 'System Ethernet Interface', 'speed_mbps': 0, 'status': {'health': 'OK', 'state': 'StandbyOffline'}}}}, 'memory': {'1': {'dimm.socket.a1': {'description': 'DIMM A1', 'memory_device_type': 'DDR4', 'capacity_mi_b': 31237, 'status': {'health': 'Critical', 'state': 'Enabled'}}}}}, 'firmwares': {}} mgr_inventory_cache = {'host01': {'hostname': 'host01', 'addr': '10.10.10.11', 'labels': ['_admin'], 'status': '', 'oob': {'hostname': '10.10.10.11', 'username': 'root', 'password': 'ceph123'}}, 'host02': {'hostname': 'host02', 'addr': '10.10.10.12', 'labels': [], 'status': '', 'oob': {'hostname': '10.10.10.12', 'username': 'root', 'password': 'ceph123'}}} -full_set = {'host01': {'host': 'host01', 'sn': 'FR8Y5X3', 'status': {'storage': {'disk.bay.8:enclosure.internal.0-1:nonraid.slot.2-1': {'description': 'Disk 8 in Backplane 1 of Storage Controller in Slot 2', 'entity': 'NonRAID.Slot.2-1', 'capacity_bytes': 20000588955136, 'model': 'ST20000NM008D-3D', 'protocol': 'SATA', 'serial_number': 'ZVT99QLL', 'status': {'health': 'OK', 'healthrollup': 'OK', 'state': 'Enabled'}, 'physical_location': {'partlocation': {'locationordinalvalue': 8, 'locationtype': 'Slot'}}}}, 'processors': {'cpu.socket.2': {'description': 'Represents the properties of a Processor attached to this System', 'total_cores': 16, 'total_threads': 32, 'processor_type': 'CPU', 'model': 'Intel(R) Xeon(R) Silver 4314 CPU @ 2.40GHz', 'status': {'health': 'OK', 'state': 'Enabled'}, 'manufacturer': 'Intel'}, 'cpu.socket.1': {'description': 'Represents the properties of a Processor attached to this System', 'total_cores': 16, 'total_threads': 32, 'processor_type': 'CPU', 'model': 'Intel(R) Xeon(R) Silver 4314 CPU @ 2.40GHz', 'status': {'health': 'OK', 'state': 'Enabled'}, 'manufacturer': 'Intel'}}, 'network': {'oslogicalnetwork.2': {'description': 'eno8303', 'name': 'eno8303', 'speed_mbps': 0, 'status': {'health': 'OK', 'state': 'Enabled'}}}, 'memory': {'dimm.socket.a1': {'description': 'DIMM A1', 'memory_device_type': 'DDR4', 'capacity_mi_b': 16384, 'status': {'health': 'OK', 'state': 'Enabled'}}}, 'power': {'0': {'name': 'PS1 Status', 'model': 'PWR SPLY,800W,RDNT,LTON', 'manufacturer': 'DELL', 'status': {'health': 'OK', 'state': 'Enabled'}}, '1': {'name': 'PS2 Status', 'model': 'PWR SPLY,800W,RDNT,LTON', 'manufacturer': 'DELL', 'status': {'health': 'OK', 'state': 'Enabled'}}}, 'fans': {'0': {'name': 'System Board Fan1A', 'physical_context': 'SystemBoard', 'status': {'health': 'OK', 'state': 'Enabled'}}}}, 'firmwares': {'installed-28897-6.10.30.20__usc.embedded.1:lc.embedded.1': {'name': 'Lifecycle Controller', 'description': 'Represents Firmware Inventory', 'release_date': '00:00:00Z', 'version': '6.10.30.20', 'updateable': True, 'status': {'health': 'OK', 'state': 'Enabled'}}}}, 'host02': {'host': 'host02', 'sn': 'FR8Y5X4', 'status': {'storage': {'disk.bay.8:enclosure.internal.0-1:nonraid.slot.2-1': {'description': 'Disk 8 in Backplane 1 of Storage Controller in Slot 2', 'entity': 'NonRAID.Slot.2-1', 'capacity_bytes': 20000588955136, 'model': 'ST20000NM008D-3D', 'protocol': 'SATA', 'serial_number': 'ZVT99QLL', 'status': {'health': 'OK', 'healthrollup': 'OK', 'state': 'Enabled'}, 'physical_location': {'partlocation': {'locationordinalvalue': 8, 'locationtype': 'Slot'}}}}, 'processors': {'cpu.socket.2': {'description': 'Represents the properties of a Processor attached to this System', 'total_cores': 16, 'total_threads': 32, 'processor_type': 'CPU', 'model': 'Intel(R) Xeon(R) Silver 4314 CPU @ 2.40GHz', 'status': {'health': 'OK', 'state': 'Enabled'}, 'manufacturer': 'Intel'}, 'cpu.socket.1': {'description': 'Represents the properties of a Processor attached to this System', 'total_cores': 16, 'total_threads': 32, 'processor_type': 'CPU', 'model': 'Intel(R) Xeon(R) Silver 4314 CPU @ 2.40GHz', 'status': {'health': 'OK', 'state': 'Enabled'}, 'manufacturer': 'Intel'}}, 'network': {'oslogicalnetwork.2': {'description': 'eno8303', 'name': 'eno8303', 'speed_mbps': 0, 'status': {'health': 'OK', 'state': 'Enabled'}}}, 'memory': {'dimm.socket.a1': {'description': 'DIMM A1', 'memory_device_type': 'DDR4', 'capacity_mi_b': 16384, 'status': {'health': 'OK', 'state': 'Enabled'}}}, 'power': {'0': {'name': 'PS1 Status', 'model': 'PWR SPLY,800W,RDNT,LTON', 'manufacturer': 'DELL', 'status': {'health': 'OK', 'state': 'Enabled'}}, '1': {'name': 'PS2 Status', 'model': 'PWR SPLY,800W,RDNT,LTON', 'manufacturer': 'DELL', 'status': {'health': 'OK', 'state': 'Enabled'}}}, 'fans': {'0': {'name': 'System Board Fan1A', 'physical_context': 'SystemBoard', 'status': {'health': 'OK', 'state': 'Enabled'}}}}, 'firmwares': {'installed-28897-6.10.30.20__usc.embedded.1:lc.embedded.1': {'name': 'Lifecycle Controller', 'description': 'Represents Firmware Inventory', 'release_date': '00:00:00Z', 'version': '6.10.30.20', 'updateable': True, 'status': {'health': 'OK', 'state': 'Enabled'}}}}} +full_set = {'host01': {'host': 'host01', 'sn': 'FR8Y5X3', 'status': {'storage': {'1': {'disk.bay.8:enclosure.internal.0-1:nonraid.slot.2-1': {'description': 'Disk 8 in Backplane 1 of Storage Controller in Slot 2', 'entity': 'NonRAID.Slot.2-1', 'capacity_bytes': 20000588955136, 'model': 'ST20000NM008D-3D', 'protocol': 'SATA', 'serial_number': 'ZVT99QLL', 'status': {'health': 'OK', 'healthrollup': 'OK', 'state': 'Enabled'}, 'physical_location': {'partlocation': {'locationordinalvalue': 8, 'locationtype': 'Slot'}}}}}, 'processors': {'1': {'cpu.socket.2': {'description': 'Represents the properties of a Processor attached to this System', 'total_cores': 16, 'total_threads': 32, 'processor_type': 'CPU', 'model': 'Intel(R) Xeon(R) Silver 4314 CPU @ 2.40GHz', 'status': {'health': 'OK', 'state': 'Enabled'}, 'manufacturer': 'Intel'}, 'cpu.socket.1': {'description': 'Represents the properties of a Processor attached to this System', 'total_cores': 16, 'total_threads': 32, 'processor_type': 'CPU', 'model': 'Intel(R) Xeon(R) Silver 4314 CPU @ 2.40GHz', 'status': {'health': 'OK', 'state': 'Enabled'}, 'manufacturer': 'Intel'}}}, 'network': {'1': {'oslogicalnetwork.2': {'description': 'eno8303', 'name': 'eno8303', 'speed_mbps': 0, 'status': {'health': 'OK', 'state': 'Enabled'}}}}, 'memory': {'1': {'dimm.socket.a1': {'description': 'DIMM A1', 'memory_device_type': 'DDR4', 'capacity_mi_b': 16384, 'status': {'health': 'OK', 'state': 'Enabled'}}}}, 'power': {'1': {'0': {'name': 'PS1 Status', 'model': 'PWR SPLY,800W,RDNT,LTON', 'manufacturer': 'DELL', 'status': {'health': 'OK', 'state': 'Enabled'}}, '1': {'name': 'PS2 Status', 'model': 'PWR SPLY,800W,RDNT,LTON', 'manufacturer': 'DELL', 'status': {'health': 'OK', 'state': 'Enabled'}}}}, 'fans': {'1': {'0': {'name': 'System Board Fan1A', 'physical_context': 'SystemBoard', 'status': {'health': 'OK', 'state': 'Enabled'}}}}}, 'firmwares': {'installed-28897-6.10.30.20__usc.embedded.1:lc.embedded.1': {'name': 'Lifecycle Controller', 'description': 'Represents Firmware Inventory', 'release_date': '00:00:00Z', 'version': '6.10.30.20', 'updateable': True, 'status': {'health': 'OK', 'state': 'Enabled'}}}}, 'host02': {'host': 'host02', 'sn': 'FR8Y5X4', 'status': {'storage': {'1': {'disk.bay.8:enclosure.internal.0-1:nonraid.slot.2-1': {'description': 'Disk 8 in Backplane 1 of Storage Controller in Slot 2', 'entity': 'NonRAID.Slot.2-1', 'capacity_bytes': 20000588955136, 'model': 'ST20000NM008D-3D', 'protocol': 'SATA', 'serial_number': 'ZVT99QLL', 'status': {'health': 'OK', 'healthrollup': 'OK', 'state': 'Enabled'}, 'physical_location': {'partlocation': {'locationordinalvalue': 8, 'locationtype': 'Slot'}}}}}, 'processors': {'1': {'cpu.socket.2': {'description': 'Represents the properties of a Processor attached to this System', 'total_cores': 16, 'total_threads': 32, 'processor_type': 'CPU', 'model': 'Intel(R) Xeon(R) Silver 4314 CPU @ 2.40GHz', 'status': {'health': 'OK', 'state': 'Enabled'}, 'manufacturer': 'Intel'}, 'cpu.socket.1': {'description': 'Represents the properties of a Processor attached to this System', 'total_cores': 16, 'total_threads': 32, 'processor_type': 'CPU', 'model': 'Intel(R) Xeon(R) Silver 4314 CPU @ 2.40GHz', 'status': {'health': 'OK', 'state': 'Enabled'}, 'manufacturer': 'Intel'}}}, 'network': {'1': {'oslogicalnetwork.2': {'description': 'eno8303', 'name': 'eno8303', 'speed_mbps': 0, 'status': {'health': 'OK', 'state': 'Enabled'}}}}, 'memory': {'1': {'dimm.socket.a1': {'description': 'DIMM A1', 'memory_device_type': 'DDR4', 'capacity_mi_b': 16384, 'status': {'health': 'OK', 'state': 'Enabled'}}}}, 'power': {'1': {'0': {'name': 'PS1 Status', 'model': 'PWR SPLY,800W,RDNT,LTON', 'manufacturer': 'DELL', 'status': {'health': 'OK', 'state': 'Enabled'}}, '1': {'name': 'PS2 Status', 'model': 'PWR SPLY,800W,RDNT,LTON', 'manufacturer': 'DELL', 'status': {'health': 'OK', 'state': 'Enabled'}}}}, 'fans': {'1': {'0': {'name': 'System Board Fan1A', 'physical_context': 'SystemBoard', 'status': {'health': 'OK', 'state': 'Enabled'}}}}}, 'firmwares': {'installed-28897-6.10.30.20__usc.embedded.1:lc.embedded.1': {'name': 'Lifecycle Controller', 'description': 'Represents Firmware Inventory', 'release_date': '00:00:00Z', 'version': '6.10.30.20', 'updateable': True, 'status': {'health': 'OK', 'state': 'Enabled'}}}}} diff --git a/src/pybind/mgr/cephadm/tests/test_node_proxy.py b/src/pybind/mgr/cephadm/tests/test_node_proxy.py index b19bb5dbc50..48c881dda95 100644 --- a/src/pybind/mgr/cephadm/tests/test_node_proxy.py +++ b/src/pybind/mgr/cephadm/tests/test_node_proxy.py @@ -109,12 +109,12 @@ class TestNodeProxyEndpoint(helper.CPWebCase): calls = [call('HARDWARE_STORAGE', count=2, - detail=['disk.bay.0:enclosure.internal.0-1:raid.integrated.1-1 is critical: Enabled', - 'disk.bay.9:enclosure.internal.0-1 is critical: Enabled'], + detail=['[1]: disk.bay.0:enclosure.internal.0-1:raid.integrated.1-1 is critical: Enabled', + '[1]: disk.bay.9:enclosure.internal.0-1 is critical: Enabled'], summary='2 storage members are not ok'), call('HARDWARE_MEMORY', count=1, - detail=['dimm.socket.a1 is critical: Enabled'], + detail=['[1]: dimm.socket.a1 is critical: Enabled'], summary='1 memory member is not ok')] assert TestNodeProxyEndpoint.mgr.set_health_warning.mock_calls == calls diff --git a/src/pybind/mgr/orchestrator/module.py b/src/pybind/mgr/orchestrator/module.py index 4c08ace4dbd..4969e1f5eb7 100644 --- a/src/pybind/mgr/orchestrator/module.py +++ b/src/pybind/mgr/orchestrator/module.py @@ -516,16 +516,16 @@ class OrchestratorCli(OrchestratorClientMixin, MgrModule, :param hostname: hostname """ table_heading_mapping = { - 'summary': ['HOST', 'STORAGE', 'CPU', 'NET', 'MEMORY', 'POWER', 'FANS'], + 'summary': ['HOST', 'SN', 'STORAGE', 'CPU', 'NET', 'MEMORY', 'POWER', 'FANS'], 'fullreport': [], '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'] + 'memory': ['HOST', 'SYS_ID', 'NAME', 'STATUS', 'STATE'], + 'storage': ['HOST', 'SYS_ID', 'NAME', 'MODEL', 'SIZE', 'PROTOCOL', 'SN', 'STATUS', 'STATE'], + 'processors': ['HOST', 'SYS_ID', 'NAME', 'MODEL', 'CORES', 'THREADS', 'STATUS', 'STATE'], + 'network': ['HOST', 'SYS_ID', 'NAME', 'SPEED', 'STATUS', 'STATE'], + 'power': ['HOST', 'CHASSIS_ID', 'ID', 'NAME', 'MODEL', 'MANUFACTURER', 'STATUS', 'STATE'], + 'fans': ['HOST', 'CHASSIS_ID', 'ID', 'NAME', 'STATUS', 'STATE'] } if category not in table_heading_mapping.keys(): @@ -542,21 +542,23 @@ class OrchestratorCli(OrchestratorClientMixin, MgrModule, 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']]) + row = [k, v['sn']] + row.extend([v['status'][key] for key in ['storage', 'processors', + 'network', 'memory', + 'power', 'fans']]) table.add_row(row) output = table.get_string() elif category == 'fullreport': if hostname is None: - output = "Missing host name" + output = 'Missing host name' elif format != Format.json: - output = "fullreport only supports json output" + output = 'fullreport only supports json output' else: completion = self.node_proxy_fullreport(hostname=hostname) fullreport: Dict[str, Any] = raise_if_exception(completion) output = json.dumps(fullreport) elif category == 'firmwares': - output = "Missing host name" if hostname is None else self._firmwares_table(hostname, table, format) + 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: @@ -572,7 +574,11 @@ class OrchestratorCli(OrchestratorClientMixin, MgrModule, 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'])) + try: + status = v['status']['health'] + except (KeyError, TypeError): + status = 'N/A' + table.add_row((host, k, v['name'], v['release_date'], v['version'], status)) return table.get_string() def _criticals_table(self, hostname: Optional[str], table: PrettyTable, format: Format) -> str: @@ -604,20 +610,21 @@ class OrchestratorCli(OrchestratorClientMixin, MgrModule, } 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]) + for host in data.keys(): + for sys_id, details in data[host].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, sys_id,) + (k,) + tuple(row)) else: - row.append('') - if category in ('power', 'fans', 'processors'): - table.add_row((host,) + (k,) + tuple(row)) - else: - table.add_row((host,) + tuple(row)) + table.add_row((host, sys_id,) + tuple(row)) return table.get_string() @@ -643,7 +650,7 @@ class OrchestratorCli(OrchestratorClientMixin, MgrModule, data = raise_if_exception(completion) output: str = '' if action == self.HardwareLightAction.get: - status = 'on' if data["LocationIndicatorActive"] else 'off' + status = 'on' if data['LocationIndicatorActive'] else 'off' if light_type == self.HardwareLightType.device: output = f'ident LED for {device} on {hostname} is: {status}' else: |