def discover_log_services(plugin_object, event_type, system_manager_id): # try to discover log service redfish_url = None system_manager_data = plugin_object.rf.get(system_manager_id) log_services = None log_services_link = grab(system_manager_data, "LogServices/@odata.id", separator="/") if log_services_link is not None: log_services = plugin_object.rf.get(log_services_link) if grab(log_services, "Members") is not None and len(log_services.get("Members")) > 0: for log_service in log_services.get("Members"): log_service_data = plugin_object.rf.get(log_service.get("@odata.id")) # check if "Name" contains "System" or "Manager" if log_service_data.get("Name") is not None and \ event_type.lower() in log_service_data.get("Name").lower(): if log_service_data.get("Entries") is not None: redfish_url = log_service_data.get("Entries").get("@odata.id") break return redfish_url
def determine_vendor(self): vendor_string = "" if self.connection.root.get("Oem"): if len(self.connection.root.get("Oem")) > 0: vendor_string = list(self.connection.root.get("Oem"))[0] self.vendor_dict_key = vendor_string if vendor_string in ["Hpe", "Hp"]: self.vendor_data = VendorHPEData() manager_data = grab(self.connection.root, f"Oem.{vendor_string}.Manager.0") if manager_data is not None: self.vendor_data.ilo_hostname = manager_data.get("HostName") self.vendor_data.ilo_version = manager_data.get("ManagerType") self.vendor_data.ilo_firmware_version = manager_data.get("ManagerFirmwareVersion") if self.vendor_data.ilo_version.lower() == "ilo 5": self.vendor_data.view_supported = True if vendor_string in ["Lenovo"]: self.vendor_data = VendorLenovoData() if vendor_string in ["Dell"]: self.vendor_data = VendorDellData() if vendor_string in ["Huawei"]: self.vendor_data = VendorHuaweiData() if vendor_string in ["ts_fujitsu"]: self.vendor_data = VendorFujitsuData() # Cisco does not provide a OEM property in root object if "CIMC" in str(self.get_system_properties("managers")): self.vendor_data = VendorCiscoData() self.vendor_dict_key = self.vendor_data.name if self.vendor_data is None: self.vendor_data = VendorGeneric() if vendor_string is not None and len(vendor_string) > 0: self.vendor_data.name = vendor_string self.vendor = self.vendor_data.name return
def get_error(redfish_data, redfish_url): return_data = None if isinstance(redfish_data, dict) and redfish_data.get("error"): error = grab(redfish_data, "error/@Message.ExtendedInfo/0", separator="/") return_data = "got '%s/%s' for API path '%s'" % ( error.get("MessageId"), error.get("Message"), redfish_url) return return_data
def get_interface_ip_addresses(interface_data, protocol_type): list_of_addresses = list() ip_addresses = grab(interface_data, protocol_type) # Cisco if isinstance(ip_addresses, dict): if ip_addresses.get("Address") is not None: list_of_addresses.append(ip_addresses.get("Address")) if isinstance(ip_addresses, list): for ip_address in ip_addresses: if ip_address.get("Address") is not None: list_of_addresses.append(ip_address.get("Address")) list_of_addresses = list(set(list_of_addresses)) return [address for address in list_of_addresses if address not in ['', '::', '0.0.0.0']]
def get_single_chassi_temp(plugin_object, redfish_url): plugin_object.set_current_command("Temp") chassi_id = redfish_url.rstrip("/").split("/")[-1] redfish_url = f"{redfish_url}/Thermal" thermal_data = plugin_object.rf.get_view(redfish_url) if thermal_data.get("error"): plugin_object.add_data_retrieval_error(Temperature, thermal_data, redfish_url) return default_text = "" temp_num = 0 if "Temperatures" in thermal_data: for temp in thermal_data.get("Temperatures"): status_data = get_status_data(grab(temp, "Status")) status = status_data.get("Health") state = status_data.get("State") name = temp.get("Name") member_id = grab(temp, "MemberId") if member_id is None: member_id = name temp_inventory = Temperature( name=name, id=member_id, health_status=status, operation_status=state, physical_context=temp.get("PhysicalContext"), min_reading=temp.get("MinReadingRangeTemp"), max_reading=temp.get("MaxReadingRangeTemp"), lower_threshold_non_critical=None if temp.get("LowerThresholdNonCritical") == "N/A" else temp.get("LowerThresholdNonCritical"), lower_threshold_critical=None if temp.get("LowerThresholdCritical") == "N/A" else temp.get("LowerThresholdCritical"), lower_threshold_fatal=None if temp.get("LowerThresholdFatal") == "N/A" else temp.get("LowerThresholdFatal"), upper_threshold_non_critical=None if temp.get("UpperThresholdNonCritical") == "N/A" else temp.get("UpperThresholdNonCritical"), upper_threshold_critical=None if temp.get("UpperThresholdCritical") == "N/A" else temp.get("UpperThresholdCritical"), upper_threshold_fatal=None if temp.get("UpperThresholdFatal") == "N/A" else temp.get("UpperThresholdFatal"), chassi_ids=chassi_id) if plugin_object.cli_args.verbose: temp_inventory.source_data = temp temp_inventory.reading_unit = "Celsius" if temp.get("ReadingCelsius") is not None: temp_inventory.reading = temp.get("ReadingCelsius") elif temp.get("ReadingFahrenheit") is not None: temp_inventory.reading = temp.get("ReadingFahrenheit") temp_inventory.reading_unit = "Fahrenheit" else: temp_inventory.reading = 0 # add relations temp_inventory.add_relation( plugin_object.rf.get_system_properties(), temp.get("Links")) temp_inventory.add_relation( plugin_object.rf.get_system_properties(), temp.get("RelatedItem")) plugin_object.inventory.add(temp_inventory) if state in ["Absent", "Disabled", "UnavailableOffline"]: continue if status is None: status = "OK" if state == "Enabled" else state current_temp = temp_inventory.reading critical_temp = temp_inventory.upper_threshold_critical warning_temp = temp_inventory.upper_threshold_non_critical temp_num += 1 if str(warning_temp) in ["0", "N/A"]: warning_temp = None if warning_temp is not None and float(current_temp) >= float( warning_temp): status = "WARNING" if str(critical_temp) in ["0", "N/A"]: critical_temp = None if critical_temp is not None and float(current_temp) >= float( critical_temp): status = "CRITICAL" critical_temp_text = "N/A" if critical_temp is not None: critical_temp_text = "%.1f" % float(critical_temp) status_text = f"Temp sensor {temp_inventory.name} status is: " \ f"{status} (%.1f °C) (max: {critical_temp_text} °C)" % current_temp plugin_object.add_output_data( "CRITICAL" if status not in ["OK", "WARNING"] else status, status_text, location=f"Chassi {chassi_id}") plugin_object.add_perf_data(f"temp_{temp_inventory.name}", float(current_temp), warning=warning_temp, critical=critical_temp, location=f"Chassi {chassi_id}") default_text = f"All temp sensors ({temp_num}) are in good condition" else: default_text = "no temp sensors detected" plugin_object.inventory.add_issue( Temperature, f"No temp sensor data returned for API URL '{redfish_url}'") plugin_object.add_output_data("OK", default_text, summary=True, location=f"Chassi {chassi_id}") return
def get_event_log_huawei(plugin_object, event_type, system_manager_id): num_entry = 0 data_now = datetime.datetime.now() date_warning = None date_critical = None log_entries = list() if event_type == "System": redfish_url = f"{system_manager_id}/LogServices/Log1/Entries" log_entries = plugin_object.rf.get(redfish_url).get("Members") else: manager_data = plugin_object.rf.get(system_manager_id) if manager_data.get("LogServices") is None or len(manager_data.get("LogServices")) == 0: plugin_object.add_output_data("UNKNOWN", f"No 'LogServices' found for redfish URL '{system_manager_id}'", summary=not plugin_object.cli_args.detailed) return log_services_data = plugin_object.rf.get(grab(manager_data, "LogServices/@odata.id", separator="/")) or dict() # this should loop over following LogServices # https://device_ip/redfish/v1/Managers/1/LogServices/OperateLog/Entries # https://device_ip/redfish/v1/Managers/1/LogServices/RunLog/Entries # https://device_ip/redfish/v1/Managers/1/LogServices/SecurityLog/Entries for manager_log_service in log_services_data.get("Members") or list(): log_entries.extend(plugin_object.rf.get(manager_log_service.get("@odata.id") + "/Entries").get("Members")) if plugin_object.cli_args.warning: date_warning = data_now - datetime.timedelta(days=int(plugin_object.cli_args.warning)) if plugin_object.cli_args.critical: date_critical = data_now - datetime.timedelta(days=int(plugin_object.cli_args.critical)) if event_type == "Manager": log_entries = sorted(log_entries, key=lambda i: i['Created'], reverse=True) for log_entry in log_entries: if log_entry.get("Id") is None: event_entry = plugin_object.rf.get(log_entry.get("@odata.id")) else: event_entry = log_entry num_entry += 1 """ It is not really clear what a "Asserted" and a "Deasserted" event looks like. We could assume that an "Asserted" event contains a "MessageId" and a "Deasserted" event doesn't. And the Only relation between these events is the exact same "Message" text. The "EventID" isn't really helpful either. And a clearing (Deasserted) of an alarm doesn't seem to work reliably either. It is also not possible to mark an event as "repaired" in iBMC. Due to all the above stated issues we implement a simple critical and warnings days logic as with HP Manager event logs. Otherwise uncleared events will alarm forever. """ severity = event_entry.get("Severity") message = event_entry.get("Message") date = event_entry.get("Created") entry_date = get_log_entry_time(date) log_name = event_entry.get("Name") source = "" status = "OK" if severity is not None: severity = severity.upper() else: severity = "OK" # get log source information if event_type == "System": log_name = "%s/%s" % (event_entry.get("EntryType"), event_entry.get("EventType")) source = "[%s]" % grab(event_entry, f"Oem.{plugin_object.rf.vendor_dict_key}.Level") elif log_name == "Operate Log": oem_data = grab(event_entry, f"Oem.{plugin_object.rf.vendor_dict_key}") if oem_data is not None: source = "[%s/%s/%s]" % \ (oem_data.get("Interface"), oem_data.get("User"), oem_data.get("Address")) elif log_name == "Run Log": alert_level = grab(event_entry, f"Oem.{plugin_object.rf.vendor_dict_key}.Level") source = f"[{alert_level}]" if alert_level == "WARN": severity = "WARNING" if alert_level == "CRIT": severity = "CRITICAL" elif log_name == "Security Log": oem_data = grab(event_entry, f"Oem.{plugin_object.rf.vendor_dict_key}") if oem_data is not None: source = "%s/%s" % (oem_data.get("Host"), oem_data.get("Interface")) # check for WARNING and CRITICAL if date_critical is not None: if entry_date > date_critical.astimezone(entry_date.tzinfo) and severity != "OK": status = "CRITICAL" if severity not in list(plugin_status_types.keys()) else severity if date_warning is not None: if entry_date > date_warning.astimezone(entry_date.tzinfo) and status != "CRITICAL" and severity != "OK": status = "WARNING" if severity not in list(plugin_status_types.keys()) else severity plugin_object.add_log_output_data(status, f"{date}: {log_name}: {source}: {message}") # obey max results returned if plugin_object.cli_args.max is not None and num_entry >= plugin_object.cli_args.max: return return
def get_single_system_info(plugin_object, redfish_url): system_response = plugin_object.rf.get(redfish_url) system_id = redfish_url.rstrip("/").split("/")[-1] if system_response is None: plugin_object.inventory.add_issue(System, f"No system information data returned for API URL '{redfish_url}'") return elif system_response.get("error"): plugin_object.add_data_retrieval_error(System, system_response, redfish_url) return # get model data model = system_response.get("Model") # Huawei system if plugin_object.rf.vendor == "Huawei": huawei_model = grab(system_response, f"Oem.{plugin_object.rf.vendor_dict_key}.ProductName") if huawei_model is not None: model = huawei_model # get memory size mem_size = grab(system_response, "MemorySummary.TotalSystemMemoryGiB") # Dell system # just WHY? if plugin_object.rf.vendor == "Dell" and mem_size is not None and int(mem_size) % 16 != 0: mem_size = round(mem_size * 1024 ** 3 / 1000 ** 3) status_data = get_status_data(system_response.get("Status")) system_inventory = System( id=system_response.get("Id"), name=system_response.get("Name"), manufacturer=system_response.get("Manufacturer"), serial=system_response.get("SerialNumber"), health_status=status_data.get("Health"), operation_status=status_data.get("State"), power_state=system_response.get("PowerState"), bios_version=system_response.get("BiosVersion"), host_name=system_response.get("HostName"), indicator_led=system_response.get("IndicatorLED"), cpu_num=grab(system_response, "ProcessorSummary.Count"), part_number=system_response.get("PartNumber"), mem_size=mem_size, model=model, type=system_response.get("SystemType") ) if plugin_object.cli_args.verbose: system_inventory.source_data = system_response # add relations system_inventory.add_relation(plugin_object.rf.get_system_properties(), system_response.get("Links")) plugin_object.inventory.add(system_inventory) host_name = "NOT SET" if system_inventory.host_name is not None and len(system_inventory.host_name) > 0: host_name = system_inventory.host_name status_text = f"INFO: {system_inventory.manufacturer} {system_inventory.model} " \ f"(CPU: {system_inventory.cpu_num}, MEM: {system_inventory.mem_size}GB) - " \ f"BIOS: {system_inventory.bios_version} - " \ f"Serial: {system_inventory.serial} - " \ f"Power: {system_inventory.power_state} - Name: {host_name}" system_health_print_status = \ "CRITICAL" if system_inventory.health_status not in ["OK", "WARNING"] else system_inventory.health_status # add DellSensorCollection if present dell_sensors = list() if plugin_object.rf.vendor == "Dell": dell_empty_slots = list() dell_slot_collection = \ grab(system_response, f"Links.Oem.{plugin_object.rf.vendor_dict_key}.DellSlotCollection") # collect info about empty slots if dell_slot_collection is not None and dell_slot_collection.get("@odata.id") is not None: collection_response = plugin_object.rf.get(dell_slot_collection.get("@odata.id")) if collection_response is not None and ( collection_response.get("Members") is None or len(collection_response.get("Members")) > 0): for dell_slot in collection_response.get("Members"): if dell_slot.get("EmptySlot") is True: dell_empty_slots.append(dell_slot.get("Id")) dell_sensor_collection = \ grab(system_response, f"Links.Oem.{plugin_object.rf.vendor_dict_key}.DellSensorCollection") if dell_sensor_collection is not None and dell_sensor_collection.get("@odata.id") is not None: collection_response = plugin_object.rf.get(dell_sensor_collection.get("@odata.id")) num_members = 0 if collection_response is not None and ( collection_response.get("Members") is None or len(collection_response.get("Members")) > 0): for dell_sensor in collection_response.get("Members"): # skip if sensor slot is empty if any(x.startswith(dell_sensor.get("Id")) for x in dell_empty_slots): continue # skip unknown DIMM and CPU status for systems without DELL slot collection # CPU Status as name if dell_slot_collection is None or \ ("Status" in dell_sensor.get('ElementName') and "CPU" in dell_sensor.get('ElementName')): if dell_sensor.get('CurrentState') == dell_sensor.get('HealthState') and \ dell_sensor.get('HealthState').upper() == "UNKNOWN": continue num_members += 1 this_sensor_status = "OK" if dell_sensor.get('EnabledState') == "Enabled": if "WARNING" in dell_sensor.get('HealthState').upper(): this_sensor_status = "WARNING" elif dell_sensor.get('HealthState') != "OK": this_sensor_status = "CRITICAL" dell_sensors.append({this_sensor_status: 'Sensor "%s": %s (%s/%s)' % ( dell_sensor.get('ElementName'), dell_sensor.get('HealthState'), dell_sensor.get('EnabledState'), dell_sensor.get('CurrentState') )}) # get the most severe state from system and sensors if len(dell_sensors) > 0: dell_sensor_states = [k for d in dell_sensors for k in d] system_health_print_status = \ plugin_object.return_highest_status(dell_sensor_states + [system_health_print_status]) if plugin_object.cli_args.detailed is False: dell_sensor_text = list() for status_type_name, _ in sorted(plugin_status_types.items(), key=lambda item: item[1], reverse=True): state_count = dell_sensor_states.count(status_type_name) if state_count == 1: dell_sensor_text.append(f"{state_count} health sensor in '{status_type_name}' state") elif state_count > 1: dell_sensor_text.append(f"{state_count} health sensors are in '{status_type_name}' state") status_text += " - " + ", ".join(dell_sensor_text) plugin_object.add_output_data(system_health_print_status, status_text, summary=True, location=f"System {system_id}") for dell_sensor in dell_sensors: for status, sensor in dell_sensor.items(): plugin_object.add_output_data(status, sensor, location=f"System {system_id}") # add ILO data if plugin_object.rf.vendor == "HPE": plugin_object.add_output_data("OK", "%s - FW: %s" % (plugin_object.rf.vendor_data.ilo_version, plugin_object.rf.vendor_data.ilo_firmware_version), location=f"System {system_id}") # add SDCard status if plugin_object.rf.vendor == "Fujitsu": sd_card = plugin_object.rf.get(redfish_url + "/Oem/ts_fujitsu/SDCard") if sd_card.get("Inserted") is True and sd_card.get("Mounted") is True: sd_card_status = sd_card.get("Status") sd_card_capacity = sd_card.get("CapacityMB") sd_card_free_space = sd_card.get("FreeSpaceMB") status_text = f"SDCard Capacity {sd_card_capacity}MB and {sd_card_free_space}MB free space left." plugin_object.add_output_data("CRITICAL" if sd_card_status not in ["OK", "WARNING"] else sd_card_status, status_text, location=f"System {system_id}") return
def get_firmware_info_generic(plugin_object): if plugin_object.rf.connection.root.get("UpdateService") is None: plugin_object.add_output_data("UNKNOWN", "URL '/redfish/v1/UpdateService' unavailable. " "Unable to retrieve firmware information.", summary=not plugin_object.cli_args.detailed) return redfish_url = f"/redfish/v1/UpdateService/FirmwareInventory{plugin_object.rf.vendor_data.expand_string}" firmware_response = plugin_object.rf.get(redfish_url) # older Cisco CIMC versions reported Firmware inventory in a different fashion if plugin_object.rf.vendor == "Cisco": if firmware_response.get("@odata.id") is None: redfish_url = f"/redfish/v1/UpdateService/{plugin_object.rf.vendor_data.expand_string}" firmware_response = plugin_object.rf.get(redfish_url) if firmware_response.get("FirmwareInventory") is not None: firmware_response["Members"] = firmware_response.get("FirmwareInventory") for firmware_member in firmware_response.get("Members"): if firmware_member.get("@odata.type"): firmware_entry = firmware_member else: firmware_entry = plugin_object.rf.get(firmware_member.get("@odata.id")) # get name and id component_name = firmware_entry.get("Name") component_id = firmware_entry.get("Id") if component_id == component_name and firmware_entry.get("SoftwareId") is not None: component_name = firmware_entry.get("SoftwareId") if component_id is None: component_id = component_name # get firmware version component_version = firmware_entry.get("Version") if component_version is not None: component_version = component_version.strip().replace("\n", "") if grab(firmware_entry, f"Oem.{plugin_object.rf.vendor_dict_key}.FirmwareBuild") is not None: component_version = f"{component_version} %s" % \ grab(firmware_entry, f"Oem.{plugin_object.rf.vendor_dict_key}.FirmwareBuild") # get location component_location = grab(firmware_entry, f"Oem.{plugin_object.rf.vendor_dict_key}.PositionId") if plugin_object.rf.vendor == "HPE": component_location = grab(firmware_entry, f"Oem.{plugin_object.rf.vendor_dict_key}.DeviceContext") if component_location is None and firmware_entry.get("SoftwareId") is not None: component_location = firmware_entry.get("SoftwareId") # get status status_data = get_status_data(firmware_entry.get("Status")) firmware_inventory = Firmware( id=component_id, name=component_name, health_status=status_data.get("Health"), operation_status=status_data.get("State"), version=component_version, location=component_location, updateable=firmware_entry.get("Updateable") ) if plugin_object.cli_args.verbose: firmware_inventory.source_data = firmware_entry plugin_object.inventory.add(firmware_inventory) return
def get_event_log_generic(plugin_object, event_type, redfish_path): num_entry = 0 data_now = datetime.datetime.now() date_warning = None date_critical = None max_entries = None # define locations for known vendors if plugin_object.rf.vendor == "Dell": log_service_data = plugin_object.rf.get(redfish_path) if grab(log_service_data, "Entries") is not None: redfish_path = log_service_data.get("Entries").get("@odata.id") if plugin_object.cli_args.warning: date_warning = data_now - datetime.timedelta(days=int(plugin_object.cli_args.warning)) if plugin_object.cli_args.critical: date_critical = data_now - datetime.timedelta(days=int(plugin_object.cli_args.critical)) # on dell systems max entries need to be limited during request if plugin_object.rf.vendor == "Dell": max_entries = plugin_object.cli_args.max event_entries = plugin_object.rf.get(redfish_path, max_members=max_entries).get("Members") if len(event_entries) == 0: plugin_object.add_output_data("OK", f"No {event_type} log entries found in '{redfish_path}'.", summary=not plugin_object.cli_args.detailed) return assoc_id_status = dict() processed_ids = list() # reverse list from newest to oldest entry if plugin_object.rf.vendor == "Lenovo": event_entries.reverse() for event_entry_item in event_entries: if event_entry_item.get("Id") is not None: event_entry = event_entry_item else: event_entry = plugin_object.rf.get(event_entry_item.get("@odata.id")) if event_entry_item.get("Id") in processed_ids: continue message = event_entry.get("Message") if message is not None: message = message.strip().strip("\n").strip() num_entry += 1 severity = event_entry.get("Severity") if severity is not None: severity = severity.upper() # CISCO WHY? if severity in ["NORMAL", "INFORMATIONAL"]: severity = "OK" date = event_entry.get("Created", "1970-01-01T00:00:00-00:00") status = "OK" # keep track of message IDs # newer message can clear a status for older messages if event_type == "System": # get log entry id to associate older log entries assoc_id = event_entry.get("SensorNumber") # found an old message that has been cleared if assoc_id is not None and assoc_id_status.get(assoc_id) == "cleared" and severity != "OK": message += " (severity '%s' cleared)" % severity severity = "OK" # Fujitsu uncleared messages elif plugin_object.rf.vendor == "Fujitsu" and event_entry.get("MessageId") == "0x180055": message += " (severity '%s' (will be) cleared due to lack of clear event)" % severity elif severity is not None: if severity == "WARNING" and date_warning is None: status = severity elif severity != "OK" and date_critical is None: status = "CRITICAL" # keep track of messages that clear an older message if event_entry.get("SensorNumber") is not None and severity == "OK": assoc_id_status[assoc_id] = "cleared" if (date_critical is not None or date_warning is not None) and severity is not None: entry_date = get_log_entry_time(date) if entry_date is not None and date_critical is not None: if entry_date > date_critical.astimezone(entry_date.tzinfo) and severity != "OK": status = "CRITICAL" if entry_date is not None and date_warning is not None: if entry_date > date_warning.astimezone( entry_date.tzinfo) and status != "CRITICAL" and severity != "OK": status = "WARNING" plugin_object.add_log_output_data(status, "%s: %s" % (date, message)) processed_ids.append(event_entry_item.get("Id")) # obey max results returned if plugin_object.cli_args.max is not None and num_entry >= plugin_object.cli_args.max: return return
def get_bmc_info_generic(plugin_object, redfish_url): """ Possible Info to add * NTP Status * NTP servers configured * BMC accounts * BIOS settings (maybe, varies a lot between vendors) """ view_response = plugin_object.rf.get_view(f"{redfish_url}{plugin_object.rf.vendor_data.expand_string}") if view_response.get("error"): plugin_object.add_data_retrieval_error(Manager, view_response, redfish_url) return # HPE iLO 5 view if view_response.get("ILO"): manager_response = view_response.get("ILO")[0] else: manager_response = view_response # get model bmc_model = manager_response.get("Model") bmc_fw_version = manager_response.get("FirmwareVersion") if plugin_object.rf.vendor == "HPE": bmc_model = " ".join(bmc_fw_version.split(" ")[0:2]) if plugin_object.rf.vendor == "Dell": if bmc_model == "13G Monolithic": bmc_model = "iDRAC 8" if bmc_model in ["14G Monolithic", "15G Monolithic"]: bmc_model = "iDRAC 9" # some Cisco Systems have a second manager with no attributes which needs to be skipped if plugin_object.rf.vendor == "Cisco": if manager_response.get("Status") is None: return status_text = f"BMC: {bmc_model} (Firmware: {bmc_fw_version})" # get status data status_data = get_status_data(manager_response.get("Status")) manager_inventory = Manager( id=manager_response.get("Id"), type=manager_response.get("ManagerType"), name=manager_response.get("Name"), health_status=status_data.get("Health"), operation_status=status_data.get("State"), model=bmc_model, firmware=bmc_fw_version ) if plugin_object.cli_args.verbose: manager_inventory.source_data = manager_response # add relations manager_inventory.add_relation(plugin_object.rf.get_system_properties(), manager_response.get("Links")) plugin_object.inventory.add(manager_inventory) # workaround for older ILO versions if manager_inventory.health_status is not None: bmc_status = manager_inventory.health_status elif manager_inventory.operation_status == "Enabled": bmc_status = "OK" else: bmc_status = "UNKNOWN" # BMC Network interfaces manager_nic_response = None manager_nic_member = None if plugin_object.rf.vendor == "HPE" and view_response.get("ILOInterfaces") is not None: manager_nic_response = {"Members": view_response.get("ILOInterfaces")} else: manager_nics_link = grab(manager_response, "EthernetInterfaces/@odata.id", separator="/") if manager_nics_link is not None: redfish_url = f"{manager_nics_link}{plugin_object.rf.vendor_data.expand_string}" manager_nic_response = plugin_object.rf.get(redfish_url) if manager_nic_response.get("error"): plugin_object.add_data_retrieval_error(NetworkPort, manager_nic_response, redfish_url) if manager_nic_response is not None: if manager_nic_response.get("Members") is None or len(manager_nic_response.get("Members")) == 0: status_text = f"{status_text} but no information about the BMC network interfaces found" plugin_object.inventory.add_issue(NetworkPort, "No information about the BMC network interfaces found") else: # if args.detailed is False: status_text = f"{status_text} and all nics are in 'OK' state." for manager_nic_member in manager_nic_response.get("Members"): if manager_nic_member.get("@odata.context"): manager_nic = manager_nic_member else: manager_nic = plugin_object.rf.get(manager_nic_member.get("@odata.id")) if manager_nic.get("error"): plugin_object.add_data_retrieval_error(NetworkPort, manager_nic, manager_nic_member.get("@odata.id")) continue status_data = get_status_data(manager_nic.get("Status")) if plugin_object.rf.vendor == "Dell": interface_id = manager_nic.get("Id") else: interface_id = "{}:{}".format(manager_inventory.id, manager_nic.get("Id")) vlan_id = grab(manager_nic, "VLAN.VLANId") if vlan_id is None: vlan_id = grab(manager_nic, "VLANId") vlan_enabled = grab(manager_nic, "VLAN.VLANEnable") if vlan_enabled is None: vlan_enabled = grab(manager_nic, "VLANEnable") network_inventory = NetworkPort( id=interface_id, name=manager_nic.get("Name"), health_status=status_data.get("Health"), operation_status=status_data.get("State"), current_speed=manager_nic.get("SpeedMbps"), autoneg=manager_nic.get("AutoNeg"), full_duplex=manager_nic.get("FullDuplex"), hostname=manager_nic.get("HostName"), addresses=format_interface_addresses(manager_nic.get("PermanentMACAddress")), manager_ids=manager_inventory.id, system_ids=manager_inventory.system_ids, chassi_ids=manager_inventory.chassi_ids, ipv4_addresses=get_interface_ip_addresses(manager_nic, "IPv4Addresses"), ipv6_addresses=get_interface_ip_addresses(manager_nic, "IPv6Addresses"), link_type="Ethernet", link_status=f"{manager_nic.get('LinkStatus') or ''}".replace("Link", ""), vlan_id=vlan_id, vlan_enabled=vlan_enabled, ) if plugin_object.cli_args.verbose: network_inventory.source_data = manager_nic plugin_object.inventory.add(network_inventory) # if we are connected wie via interface IP address then we can assume the link is up if network_inventory.link_status is None: for address in network_inventory.ipv4_addresses + network_inventory.ipv6_addresses: if address in plugin_object.cli_args.host: network_inventory.link_status = "Up" if plugin_object.rf.vendor == "Cisco" and manager_nic.get("InterfaceEnabled") is True: network_inventory.operation_status = "Enabled" # Huawei is completely missing any status information if plugin_object.rf.vendor == "Huawei" and network_inventory.operation_status is None: network_inventory.operation_status = "Enabled" if network_inventory.health_status: nic_status = network_inventory.health_status elif network_inventory.operation_status == "Enabled": nic_status = "OK" else: nic_status = "UNKNOWN" if network_inventory.operation_status in ["Disabled", None]: continue host_name = network_inventory.hostname or "no hostname set" ip_addresses_string = None ip_addresses = [*network_inventory.ipv4_addresses, *network_inventory.ipv6_addresses] if len(ip_addresses) > 0: ip_addresses_string = "/".join(ip_addresses) duplex = autoneg = None if network_inventory.full_duplex is not None: duplex = "full" if network_inventory.full_duplex is True else "half" if nic_status == "OK" and duplex == "half" and network_inventory.current_speed is not None: nic_status = "WARNING" duplex += f" ({nic_status})" if network_inventory.autoneg is not None: autoneg = "on" if network_inventory.autoneg is True else "off" nic_status_text = f"NIC {network_inventory.id} '{host_name}' (IPs: {ip_addresses_string}) " nic_status_text += f"(speed: {network_inventory.current_speed}, " \ f"autoneg: {autoneg}, duplex: {duplex}) status: {nic_status}" plugin_object.add_output_data("CRITICAL" if nic_status not in ["OK", "WARNING"] else nic_status, nic_status_text, location=f"Manager {manager_inventory.id}") # get vendor information vendor_data = grab(manager_response, f"Oem.{plugin_object.rf.vendor_dict_key}") # get license information bmc_licenses = list() if plugin_object.rf.vendor == "HPE": ilo_license_string = grab(vendor_data, "License.LicenseString") ilo_license_key = grab(vendor_data, "License.LicenseKey") bmc_licenses.append(f"{ilo_license_string} ({ilo_license_key})") elif plugin_object.rf.vendor == "Lenovo": fod_link = grab(vendor_data, "FoD/@odata.id", separator="/") if fod_link is not None: fod_url = f"{fod_link}/Keys{plugin_object.rf.vendor_data.expand_string}" fod_data = plugin_object.rf.get(fod_url) if fod_data.get("error"): plugin_object.add_data_retrieval_error(Manager, fod_data, fod_url) for fod_member in fod_data.get("Members", list()): if manager_nic_member is not None and manager_nic_member.get("@odata.context"): licenses_data = fod_member else: licenses_data = plugin_object.rf.get(fod_member.get("@odata.id")) lic_status = licenses_data.get("Status") # valid lic_expire_date = licenses_data.get("Expires") # NO CONSTRAINTS lic_description = licenses_data.get("Description") license_string = f"{lic_description}" if lic_expire_date != "NO CONSTRAINTS": license_string += " (expires: {lic_expire_date}" license_string += f" Status: {lic_status}" bmc_licenses.append(license_string) elif plugin_object.rf.vendor == "Fujitsu": # get configuration irmc_configuration_link = grab(vendor_data, f"iRMCConfiguration/@odata.id", separator="/") irmc_configuration = None if irmc_configuration_link is not None: irmc_configuration = plugin_object.rf.get(irmc_configuration_link) if irmc_configuration.get("error"): plugin_object.add_data_retrieval_error(Manager, irmc_configuration, irmc_configuration_link) license_information = None license_information_link = grab(irmc_configuration, f"Licenses/@odata.id", separator="/") if license_information_link is not None: license_information = plugin_object.rf.get(license_information_link) if license_information.get("error"): plugin_object.add_data_retrieval_error(Manager, license_information, license_information_link) if license_information is not None and license_information.get("*****@*****.**") > 0: for bmc_license in license_information.get("Keys"): bmc_licenses.append("%s (%s)" % (bmc_license.get("Name"), bmc_license.get("Type"))) elif plugin_object.rf.vendor == "Huawei": ibmc_license_link = vendor_data.get("LicenseService") if ibmc_license_link is not None and len(ibmc_license_link) > 0: ibmc_lic = plugin_object.rf.get(ibmc_license_link.get("@odata.id")) if ibmc_lic.get("error"): plugin_object.add_data_retrieval_error(Manager, ibmc_lic, ibmc_license_link.get("@odata.id")) bmc_licenses.append("%s (%s)" % (ibmc_lic.get("InstalledStatus"), ibmc_lic.get("LicenseClass"))) manager_inventory.licenses = bmc_licenses for bmc_license in bmc_licenses: plugin_object.add_output_data("OK", f"BMC License: {bmc_license}", location=f"Manager {manager_inventory.id}") # HP ILO specific stuff if plugin_object.rf.vendor == "HPE": # iLO Self Test for self_test in vendor_data.get("iLOSelfTestResults"): self_test_status = self_test.get("Status") if self_test_status in ["Informational", None]: continue self_test_status = self_test_status.upper() self_test_name = self_test.get("SelfTestName") self_test_notes = self_test.get("Notes") if self_test_notes is not None and len(self_test_notes) != 0: self_test_notes = self_test_notes.strip() self_test_status_text = f"BMC SelfTest {self_test_name} ({self_test_notes}) status: {self_test_status}" else: self_test_status_text = f"BMC SelfTest {self_test_name} status: {self_test_status}" plugin_object.add_output_data("CRITICAL" if self_test_status not in ["OK", "WARNING"] else self_test_status, self_test_status_text, location=f"Manager {manager_inventory.id}") # Lenovo specific stuff if plugin_object.rf.vendor == "Lenovo": redfish_chassi_url = grab(manager_response, "Links/ManagerForChassis/0/@odata.id", separator="/") chassi_response = None if redfish_chassi_url is not None: chassi_response = plugin_object.rf.get(redfish_chassi_url) if chassi_response.get("error"): plugin_object.add_data_retrieval_error(Manager, chassi_response, redfish_chassi_url) located_data = grab(chassi_response, f"Oem.{plugin_object.rf.vendor_dict_key}.LocatedIn") if located_data is not None: descriptive_name = located_data.get("DescriptiveName") rack = located_data.get("Rack") system_name_string = f"System name: {descriptive_name} ({rack})" if plugin_object.cli_args.detailed: plugin_object.add_output_data("OK", f"BMC {system_name_string}", location=f"Manager {manager_inventory.id}") else: status_text += f" {system_name_string}" # get running firmware information from Fujitsu server if plugin_object.rf.vendor == "Fujitsu": for bmc_firmware in get_firmware_info_fujitsu(plugin_object, redfish_url, True): plugin_object.add_output_data("OK", "BMC Firmware: %s: %s" % (bmc_firmware.get("name"), bmc_firmware.get("version")), location=f"Manager {manager_inventory.id}") # get Huawei Server location data if plugin_object.rf.vendor == "Huawei": ibmc_location = vendor_data.get("DeviceLocation") if ibmc_location is not None and len(ibmc_location) > 0: location_string = f"Location: {ibmc_location}" if plugin_object.cli_args.detailed: plugin_object.add_output_data("OK", f"BMC {location_string}", location=f"Manager {manager_inventory.id}") else: status_text += f" {location_string}" plugin_object.add_output_data("CRITICAL" if bmc_status not in ["OK", "WARNING"] else bmc_status, status_text, summary=True, location=f"Manager {manager_inventory.id}") return
def get_event_log_hpe(plugin_object, event_type, redfish_path): limit_of_returned_items = plugin_object.cli_args.max forced_limit = False data_now = datetime.datetime.now() date_warning = None date_critical = None if plugin_object.rf.vendor_data.ilo_version.lower() != "ilo 5": ilo4_limit = 30 if plugin_object.cli_args.max: limit_of_returned_items = min(plugin_object.cli_args.max, ilo4_limit) if plugin_object.cli_args.max > ilo4_limit: forced_limit = True else: forced_limit = True limit_of_returned_items = ilo4_limit if event_type == "Manager": if plugin_object.cli_args.warning: date_warning = data_now - datetime.timedelta(days=int(plugin_object.cli_args.warning)) if plugin_object.cli_args.critical: date_critical = data_now - datetime.timedelta(days=int(plugin_object.cli_args.critical)) event_entries = plugin_object.rf.get(redfish_path).get("Members") if len(event_entries) == 0: plugin_object.add_output_data("OK", f"No {event_type} log entries found.", summary=not plugin_object.cli_args.detailed) return # reverse list from newest to oldest entry event_entries.reverse() num_entry = 0 for event_entry_item in event_entries: if event_entry_item.get("@odata.context"): event_entry = event_entry_item else: event_entry = plugin_object.rf.get(event_entry_item.get("@odata.id")) num_entry += 1 message = event_entry.get("Message") severity = event_entry.get("Severity") if severity is not None: severity = severity.upper() date = event_entry.get("Created") or "1970-01-01T00:00:00Z" entry_date = get_log_entry_time(date) repaired = grab(event_entry, f"Oem.{plugin_object.rf.vendor_dict_key}.Repaired") or False status = "OK" if event_type == "System": if severity == "WARNING" and repaired is False: status = "WARNING" elif severity != "OK" and repaired is False: status = "CRITICAL" else: if plugin_object.cli_args.critical and date_critical is not None: if entry_date > date_critical.astimezone(entry_date.tzinfo) and severity != "OK": status = "CRITICAL" if plugin_object.cli_args.warning and date_warning is not None: if entry_date > date_warning.astimezone(entry_date.tzinfo) \ and status != "CRITICAL" and severity != "OK": status = "WARNING" plugin_object.add_log_output_data(status, "%s: %s" % (date, message)) # obey max results returned if limit_of_returned_items is not None and num_entry >= limit_of_returned_items: if forced_limit: plugin_object.add_log_output_data("OK", f"This is an {plugin_object.rf.vendor_data.ilo_version}, " f"limited {event_type} log results to " f"{limit_of_returned_items} entries") return return
def get_system_nics(plugin_object, redfish_url): def get_network_port(port_data=None, network_function_id=None, return_data=False): # could be # * a string # * a dict with just the link # * a dict with full data port_response = None redfish_path = None if isinstance(port_data, dict): if port_data.get("Id") is not None: port_response = port_data else: redfish_path = port_data.get("@odata.id") elif isinstance(port_data, str): redfish_path = port_data # query data if port_response is None and redfish_path is not None: port_response = plugin_object.rf.get_view(f"{redfish_path}{plugin_object.rf.vendor_data.expand_string}") if port_response is None: return NetworkPort() # get health status status_data = get_status_data(port_response.get("Status")) # get Link speed current_speed = \ port_response.get("CurrentLinkSpeedMbps") or \ grab(port_response, "SupportedLinkCapabilities.0.LinkSpeedMbps") or \ grab(port_response, "SupportedLinkCapabilities.LinkSpeedMbps") if isinstance(current_speed, str): current_speed = current_speed.replace("Gbps", "000") if str(current_speed) == "-": current_speed = None # get port number if port_response.get("PhysicalPortNumber"): nic_port_name = "Port " + port_response.get("PhysicalPortNumber") else: nic_port_name = port_response.get("Name") if plugin_object.rf.vendor == "Cisco" and network_function_id is not None: port_id = f"{network_function_id}.{port_response.get('Id')}" else: port_id = port_response.get('Id') if plugin_object.rf.vendor != "Dell": port_id = f"{adapter_id}.{port_id}" # check if port has already be added if port_id in [p.id for p in plugin_object.inventory.get(NetworkPort)]: print(f"ALREADY in INVENTORY: {port_id}") return network_port_inventory = NetworkPort( id=port_id, name=port_response.get("Name"), port_name=nic_port_name, health_status=status_data.get("Health"), operation_status=status_data.get("State"), addresses=format_interface_addresses(grab(port_response, "AssociatedNetworkAddresses")), link_type=port_response.get("ActiveLinkTechnology"), autoneg=grab(port_response, "SupportedLinkCapabilities.0.AutoSpeedNegotiation"), current_speed=current_speed, capable_speed=grab(port_response, "SupportedLinkCapabilities.0.CapableLinkSpeedMbps.0"), link_status=f"{port_response.get('LinkStatus') or ''}".replace("Link", ""), system_ids=system_id ) network_port_inventory.add_relation(plugin_object.rf.get_system_properties(), port_response.get("Links")) network_port_inventory.add_relation(plugin_object.rf.get_system_properties(), port_response.get("RelatedItem")) plugin_object.inventory.add(network_port_inventory) if plugin_object.cli_args.verbose: network_port_inventory.source_data = {"port": port_response} if return_data is True: return network_port_inventory return def get_network_function(function_data=None): # could be # * a string # * a dict with just the link # * a dict with full data function_response = None redfish_path = None if isinstance(function_data, dict): if function_data.get("Id") is not None: function_response = function_data else: redfish_path = function_data.get("@odata.id") elif isinstance(function_data, str): redfish_path = function_data # query data if function_response is None and redfish_path is not None: function_response = plugin_object.rf.get_view(f"{redfish_path}{plugin_object.rf.vendor_data.expand_string}") port_inventory = None if function_response is not None: physical_port_path = grab(function_response, "Links.PhysicalPortAssignment") or \ grab(function_response, "PhysicalPortAssignment") if physical_port_path is None: return network_function_id = function_response.get("Id") port_inventory = get_network_port(physical_port_path, network_function_id, True) if plugin_object.cli_args.verbose: source_data = getattr(port_inventory, "source_data") source_data["function"] = function_response port_inventory.update("source_data", source_data) port_inventory.add_relation(plugin_object.rf.get_system_properties(), function_response.get("Links")) port_inventory.add_relation(plugin_object.rf.get_system_properties(), function_response.get("RelatedItem")) # get health status status_data = get_status_data(function_response.get("Status")) if port_inventory.health_status is None: port_inventory.health_status = status_data.get("Health") if port_inventory.operation_status is None: port_inventory.operation_status = status_data.get("State") # get and sanitize MAC and WWPN addresses port_inventory.update("addresses", format_interface_addresses(grab(function_response, "Ethernet.PermanentMACAddress")) + format_interface_addresses(grab(function_response, "Ethernet.MACAddress")) + format_interface_addresses(grab(function_response, "FibreChannel.PermanentWWPN")) + format_interface_addresses(grab(function_response, "FibreChannel.WWPN")), append=True) # set VLAN settings port_inventory.vlan_id = grab(function_response, "Ethernet.VLAN.VLANId") port_inventory.vlan_enabled = grab(function_response, "Ethernet.VLAN.VLANEnable") # get IP addresses vendor_data = grab(function_response, f"Oem.{plugin_object.rf.vendor_dict_key}") if vendor_data is not None: port_inventory.ipv4_addresses = get_interface_ip_addresses(vendor_data, "IPv4Addresses") port_inventory.ipv6_addresses = get_interface_ip_addresses(vendor_data, "IPv6Addresses") # set link type port_inventory.update("link_type", function_response.get("NetDevFuncType")) if plugin_object.rf.vendor == "Cisco": port_inventory.update("os_name", function_response.get("Name")) if plugin_object.rf.vendor == "Dell": duplex_setting = \ grab(function_response, f"Oem.{plugin_object.rf.vendor_dict_key}.DellNIC.LinkDuplex") or "" if "full" in duplex_setting.lower(): port_inventory.update("full_duplex", True) elif "half" in duplex_setting.lower(): port_inventory.update("full_duplex", False) port_inventory.update("name", grab(function_response, f"Oem.{plugin_object.rf.vendor_dict_key}.DellNIC.DeviceDescription")) return port_inventory plugin_object.set_current_command("NICs") system_id = redfish_url.rstrip("/").split("/")[-1] if plugin_object.rf.vendor == "HPE": system_response = plugin_object.rf.get(redfish_url) ethernet_interfaces_path = grab(system_response, f"Oem/{plugin_object.rf.vendor_dict_key}/Links/EthernetInterfaces/@odata.id", separator="/") network_adapter_path = grab(system_response, f"Oem/{plugin_object.rf.vendor_dict_key}/Links/NetworkAdapters/@odata.id", separator="/") else: ethernet_interfaces_path = f"{redfish_url}/EthernetInterfaces" network_adapter_path = f"{redfish_url}/NetworkInterfaces" network_adapter_response = \ plugin_object.rf.get_view(f"{network_adapter_path}{plugin_object.rf.vendor_data.expand_string}") # HPE specific if network_adapter_response.get("NetworkAdapters") is not None: network_adapter_members = network_adapter_response.get("NetworkAdapters") else: network_adapter_members = network_adapter_response.get("Members") if network_adapter_members and len(network_adapter_members) > 0: for adapter in network_adapter_members: if adapter.get("Id") is not None: nic_member = adapter else: nic_member = plugin_object.rf.get(adapter.get("@odata.id")) adapter_path = grab(nic_member, "Links/NetworkAdapter/@odata.id", separator="/") or \ grab(nic_member, "Links.NetworkAdapter.0") # HPE systems num_ports = 0 network_ports = None network_functions = None if adapter_path is None: status_data = get_status_data(nic_member.get("Status")) adapter_id = nic_member.get("Id") manufacturer = None name = nic_member.get("Name") model = nic_member.get("Model") part_number = nic_member.get("PartNumber") serial = nic_member.get("SerialNumber") firmware = grab(nic_member, "Firmware.Current.VersionString") source_data = nic_member num_ports = len(nic_member.get("PhysicalPorts") or list()) else: adapter_response = plugin_object.rf.get(adapter_path) source_data = adapter_response status_data = get_status_data(adapter_response.get("Status")) adapter_id = adapter_response.get("Id") manufacturer = adapter_response.get("Manufacturer") name = adapter_response.get("Name") model = adapter_response.get("Model") part_number = adapter_response.get("PartNumber") serial = adapter_response.get("SerialNumber") firmware = grab(adapter_response, "Firmware.Current.VersionString") adapter_controllers = adapter_response.get("Controllers") or list() if isinstance(adapter_controllers, dict): adapter_controllers = [adapter_controllers] for controller in adapter_controllers: firmware = grab(controller, "FirmwarePackageVersion") network_ports = grab(controller, "Links.NetworkPorts") or \ grab(controller, "Link.NetworkPorts") network_functions = grab(controller, "Links.NetworkDeviceFunctions") or \ grab(controller, "Link.NetworkDeviceFunctions") num_ports = len(network_ports) adapter_inventory = NetworkAdapter( id=adapter_id, name=name, health_status=status_data.get("Health"), operation_status=status_data.get("State"), model=model, manufacturer=manufacturer, num_ports=num_ports, firmware=firmware, part_number=part_number, serial=serial, system_ids=system_id ) discovered_network_ports = 0 for network_function in network_functions or list(): port_inventory_data = get_network_function(network_function) if port_inventory_data is not None: adapter_inventory.update("port_ids", port_inventory_data.id, True) port_inventory_data.update("adapter_id", adapter_inventory.id) discovered_network_ports += 1 if discovered_network_ports == 0: for network_port in network_ports or list(): port_inventory_data = get_network_port(network_port, return_data=True) if port_inventory_data is not None: adapter_inventory.update("port_ids", port_inventory_data.id, True) port_inventory_data.update("adapter_id", adapter_inventory.id) # special case for HPE if plugin_object.rf.vendor == "HPE" and len(nic_member.get("PhysicalPorts") or list()) > 0: num_port = 0 for network_port in nic_member.get("PhysicalPorts") or list(): num_port += 1 port_id = f"{adapter_inventory.id}.{num_port}" status_data = get_status_data(network_port.get("Status")) network_port_inventory = NetworkPort( id=port_id, adapter_id=adapter_inventory.id, os_name=network_port.get("Name"), port_name=num_port, health_status=status_data.get("Health"), operation_status=status_data.get("State"), addresses=format_interface_addresses(grab(network_port, "MacAddress")), ipv4_addresses=get_interface_ip_addresses(network_port, "IPv4Addresses"), ipv6_addresses=get_interface_ip_addresses(network_port, "IPv6Addresses"), full_duplex=grab(network_port, "FullDuplex"), current_speed=grab(network_port, "SpeedMbps"), link_status=f"{network_port.get('LinkStatus') or ''}".replace("Link", ""), system_ids=system_id ) adapter_inventory.update("port_ids", port_id, True) plugin_object.inventory.add(network_port_inventory) if plugin_object.cli_args.verbose: network_port_inventory.source_data = {"port": network_port} if plugin_object.cli_args.verbose: adapter_inventory.source_data = source_data plugin_object.inventory.add(adapter_inventory) if len(plugin_object.inventory.get(NetworkPort)) == 0: ethernet_interface_response = \ plugin_object.rf.get_view(f"{ethernet_interfaces_path}{plugin_object.rf.vendor_data.expand_string}") # HPE specific if ethernet_interface_response.get("EthernetInterfaces") is not None: ethernet_interface_members = ethernet_interface_response.get("EthernetInterfaces") else: ethernet_interface_members = ethernet_interface_response.get("Members") if ethernet_interface_members and len(ethernet_interface_members) > 0: for interface in ethernet_interface_members: if interface.get("Id") is not None: interface_member = interface else: interface_member = plugin_object.rf.get(interface.get("@odata.id")) if interface_member.get("Id"): # get health status status_data = get_status_data(interface_member.get("Status")) addresses = interface_member.get("PermanentMACAddress") or interface_member.get("MACAddress") port_inventory = NetworkPort( id=interface_member.get("Id"), name=interface_member.get("Name"), health_status=status_data.get("Health"), operation_status=status_data.get("State"), link_status=interface_member.get("LinkStatus"), addresses=format_interface_addresses(addresses), current_speed=interface_member.get("SpeedMbps"), system_ids=system_id ) if plugin_object.cli_args.verbose: port_inventory.source_data = interface_member # add relations port_inventory.add_relation(plugin_object.rf.get_system_properties(), interface_member.get("Links")) port_inventory.add_relation(plugin_object.rf.get_system_properties(), interface_member.get("RelatedItem")) plugin_object.inventory.add(port_inventory) def add_port_status(port_inventory_item): plugin_status = port_status = port_inventory_item.health_status if port_status is None: port_status = port_inventory_item.operation_status if plugin_status is None and port_status == "Enabled": plugin_status = "OK" if plugin_status is None: plugin_status = "OK" ip_addresses_string = None ip_addresses = [*port_inventory_item.ipv4_addresses, *port_inventory_item.ipv6_addresses] if len(ip_addresses) > 0: ip_addresses_string = "/".join(ip_addresses) duplex = autoneg = None if port_inventory_item.full_duplex is not None: duplex = "full" if port_inventory_item.full_duplex is True else "half" if port_inventory_item.autoneg is not None: autoneg = "on" if port_inventory_item.autoneg is True else "off" status_text = f"Port {port_inventory_item.id} " if port_inventory_item.os_name is not None: status_text += f"(OS name: {port_inventory_item.os_name}) " if ip_addresses_string is not None: status_text += f"(IPs: {ip_addresses_string}) " status_text += f"(type: {port_inventory_item.link_type}, " \ f"speed: {port_inventory_item.current_speed}, " \ f"autoneg: {autoneg}, duplex: {duplex}) " if port_status is not None: status_text += f"status: {port_status}, " status_text += f"link: {port_inventory_item.link_status}" plugin_object.add_output_data("CRITICAL" if plugin_status not in ["OK", "WARNING"] else plugin_status, status_text) adapter_inventory = plugin_object.inventory.get(NetworkAdapter) port_inventory = plugin_object.inventory.get(NetworkPort) num_adapters = len(adapter_inventory) num_ports = len(port_inventory) for network_adapter in adapter_inventory: plugin_status = adapter_status = network_adapter.health_status if adapter_status is None: adapter_status = network_adapter.operation_status if plugin_status is None and adapter_status == "Enabled": plugin_status = "OK" if plugin_status is None: plugin_status = "OK" adapter_name = network_adapter.model \ if len(network_adapter.model or '') > len(network_adapter.name or '') else network_adapter.name if plugin_object.rf.vendor in ["Huawei", "Cisco", "Dell"] and \ not all(v is None for v in [network_adapter.model, network_adapter.manufacturer]): adapter_name = f"{network_adapter.manufacturer} {network_adapter.model}" status_text = f"Adapter {adapter_name} (FW: {network_adapter.firmware}) status: {adapter_status}" plugin_object.add_output_data("CRITICAL" if plugin_status not in ["OK", "WARNING"] else plugin_status, status_text) for network_port in port_inventory: if str(network_port.adapter_id) == str(network_adapter.id): add_port_status(network_port) for network_port in port_inventory: if network_port.adapter_id is None: add_port_status(network_port) if num_ports == 0: plugin_object.add_output_data("UNKNOWN", f"No network adapter or interface data " f"returned for API URL '{network_adapter_path}'") plugin_object.add_output_data("OK", f"All network adapter ({num_adapters}) and " f"ports ({num_ports}) are in good condition", summary=True) return
def get_firmware_info_fujitsu(plugin_object, system_id, bmc_only=False): # there is room for improvement # list of dicts: keys: {name, version, location} firmware_entries = list() # get iRMC firmware manager_ids = plugin_object.rf.get_system_properties("managers") if manager_ids is not None and len(manager_ids) > 0: manager_response = plugin_object.rf.get(manager_ids[0]) # get configuration irmc_configuration_link = grab(manager_response, f"Oem/{plugin_object.rf.vendor_dict_key}/iRMCConfiguration/@odata.id", separator="/") irmc_configuration = None if irmc_configuration_link is not None: irmc_configuration = plugin_object.rf.get(irmc_configuration_link) irmc_firmware_information = None firmware_information_link = grab(irmc_configuration, f"FWUpdate/@odata.id", separator="/") if firmware_information_link is not None: irmc_firmware_information = plugin_object.rf.get(firmware_information_link) if irmc_firmware_information is not None: for bmc_fw_bank in ["iRMCFwImageHigh", "iRMCFwImageLow"]: fw_info = irmc_firmware_information.get(bmc_fw_bank) if fw_info is not None: firmware_entries.append( {"id": bmc_fw_bank, "name": "%s iRMC" % fw_info.get("FirmwareRunningState"), "version": "%s, Booter %s, SDDR: %s/%s (%s)" % ( fw_info.get("FirmwareVersion"), fw_info.get("BooterVersion"), fw_info.get("SDRRVersion"), fw_info.get("SDRRId"), fw_info.get("FirmwareBuildDate") ), "location": "System Board" } ) # special case: # Firmware information was requested from bmc check. # So we just return the bmc firmware list if bmc_only is True: return firmware_entries # get power supply firmware chassi_ids = plugin_object.rf.get_system_properties("chassis") if chassi_ids is not None and len(chassi_ids) > 0: for chassi_id in chassi_ids: power_data = plugin_object.rf.get(f"{chassi_id}/Power") if power_data.get("PowerSupplies") is not None and len(power_data.get("PowerSupplies")) > 0: for ps_data in power_data.get("PowerSupplies"): ps_manufacturer = ps_data.get("Manufacturer") ps_location = ps_data.get("Name") ps_model = ps_data.get("Model") ps_fw_version = ps_data.get("FirmwareVersion") firmware_entries.append({ "id": f"{ps_location}", "name": f"Power Supply {ps_manufacturer} {ps_model}", "version": f"{ps_fw_version}", "location": f"{ps_location}" }) # get hard drive firmware redfish_url = f"{system_id}/Storage" + "%s" % plugin_object.rf.vendor_data.expand_string storage_response = plugin_object.rf.get(redfish_url) for storage_member in storage_response.get("Members"): if storage_member.get("@odata.context"): controller_response = storage_member else: controller_response = plugin_object.rf.get(storage_member.get("@odata.id")) for controller_drive in controller_response.get("Drives"): drive_response = plugin_object.rf.get(controller_drive.get("@odata.id")) if drive_response.get("Name") is not None: drive_name = drive_response.get("Name") drive_firmware = drive_response.get("Revision") drive_slot = grab(drive_response, f"Oem.{plugin_object.rf.vendor_dict_key}.SlotNumber") drive_storage_controller = controller_response.get("Id") firmware_entries.append({ "id": f"Drive:{drive_storage_controller}:{drive_slot}", "name": f"Drive {drive_name}", "version": f"{drive_firmware}", "location": f"{drive_storage_controller}:{drive_slot}" }) # get other firmware redfish_url = f"{system_id}/Oem/%s/FirmwareInventory/" % plugin_object.rf.vendor_dict_key system_id_num = system_id.rstrip("/").split("/")[-1] firmware_response = plugin_object.rf.get(redfish_url) # get BIOS if firmware_response.get("SystemBIOS"): firmware_entries.append({ "id": f"System:{system_id_num}", "name": "SystemBIOS", "version": "%s" % firmware_response.get("SystemBIOS"), "location": "System Board" }) # get other components for key, value in firmware_response.items(): if key.startswith("@"): continue if isinstance(value, dict) and value.get("@odata.id") is not None: component_type = value.get("@odata.id").rstrip("/").split("/")[-1] component_fw_data = plugin_object.rf.get(value.get("@odata.id")) if component_fw_data.get("Ports") is not None and len(component_fw_data.get("Ports")) > 0: component_id = 0 for component_entry in component_fw_data.get("Ports"): component_id += 1 component_name = component_entry.get("AdapterName") component_location = component_entry.get("ModuleName") component_bios_version = component_entry.get("BiosVersion") component_fw_version = component_entry.get("FirmwareVersion") component_slot = component_entry.get("SlotId") component_port = component_entry.get("PortId") firmware_entries.append({ "id": f"{component_type}_Port_{component_id}", "name": f"{component_name}", "version": f"{component_fw_version} (BIOS: {component_bios_version})", "location": f"{component_location} {component_slot}/{component_port}" }) if component_fw_data.get("Adapters") is not None and len(component_fw_data.get("Adapters")) > 0: component_id = 0 for component_entry in component_fw_data.get("Adapters"): component_id += 1 component_name = component_entry.get("ModuleName") component_pci_segment = component_entry.get("PciSegment") component_bios_version = component_entry.get("BiosVersion") component_fw_version = component_entry.get("FirmwareVersion") firmware_entries.append({ "id": f"{component_type}_Adapter_{component_id}", "name": f"{component_name} controller", "version": f"{component_fw_version} (BIOS: {component_bios_version})", "location": f"{system_id_num}:{component_pci_segment}" }) # add firmware entry to inventory for fw_entry in firmware_entries: firmware_inventory = Firmware(**fw_entry) if plugin_object.cli_args.verbose: firmware_inventory.source_data = fw_entry plugin_object.inventory.add(firmware_inventory) return
def get_firmware_info_generic(plugin_object): if plugin_object.rf.connection.root.get("UpdateService") is None: plugin_object.inventory.add_issue( Firmware, "URL '/redfish/v1/UpdateService' unavailable. " "Unable to retrieve firmware information.") return redfish_url = f"/redfish/v1/UpdateService/FirmwareInventory{plugin_object.rf.vendor_data.expand_string}" firmware_response = plugin_object.rf.get(redfish_url) if firmware_response.get("error"): plugin_object.add_data_retrieval_error(Firmware, firmware_response, redfish_url) # older Cisco CIMC versions reported Firmware inventory in a different fashion if plugin_object.rf.vendor == "Cisco": if firmware_response.get("@odata.id") is None: redfish_url = f"/redfish/v1/UpdateService/{plugin_object.rf.vendor_data.expand_string}" firmware_response = plugin_object.rf.get(redfish_url) if firmware_response.get("error"): plugin_object.add_data_retrieval_error(Firmware, firmware_response, redfish_url) if firmware_response.get("FirmwareInventory") is not None: firmware_response["Members"] = firmware_response.get( "FirmwareInventory") for firmware_member in firmware_response.get("Members"): if firmware_member.get("@odata.type"): firmware_entry = firmware_member else: firmware_entry = plugin_object.rf.get( firmware_member.get("@odata.id")) if firmware_entry.get("error"): plugin_object.add_data_retrieval_error( Firmware, firmware_entry, firmware_member.get("@odata.id")) continue # get name and id component_name = f"{firmware_entry.get('Name')}" component_id = firmware_entry.get("Id") if component_id == component_name and firmware_entry.get( "SoftwareId") is not None: component_name = firmware_entry.get("SoftwareId") if component_id is None: component_id = component_name # on Dell system skip power supplies and disk and collect them separately # only one of the disk and power supply is reported not all of them if plugin_object.rf.vendor == "Dell" and component_name is not None: if "power supply" in component_name.lower(): continue if "disk " in component_name.lower(): continue if component_name.lower().startswith("firmware:"): component_name = component_name[9:] # get firmware version component_version = firmware_entry.get("Version") if component_version is not None: component_version = component_version.strip().replace("\n", "") if grab(firmware_entry, f"Oem.{plugin_object.rf.vendor_dict_key}.FirmwareBuild" ) is not None: component_version = f"{component_version} %s" % \ grab(firmware_entry, f"Oem.{plugin_object.rf.vendor_dict_key}.FirmwareBuild") # get location component_location = grab( firmware_entry, f"Oem.{plugin_object.rf.vendor_dict_key}.PositionId") if plugin_object.rf.vendor == "HPE": component_location = grab( firmware_entry, f"Oem.{plugin_object.rf.vendor_dict_key}.DeviceContext") if component_location is None and firmware_entry.get( "SoftwareId") is not None: component_location = firmware_entry.get("SoftwareId") # get status status_data = get_status_data(firmware_entry.get("Status")) firmware_inventory = Firmware( id=component_id, name=component_name, health_status=status_data.get("Health"), operation_status=status_data.get("State"), version=component_version, location=component_location, updateable=firmware_entry.get("Updateable")) if plugin_object.cli_args.verbose: firmware_inventory.source_data = firmware_entry plugin_object.inventory.add(firmware_inventory) if plugin_object.rf.vendor in ["Dell", "Cisco", "Lenovo"]: get_drives = True get_controllers = False get_power = True plugin_object.in_firmware_collection_mode(True) if any(x in plugin_object.cli_args.requested_query for x in ['storage', 'all']) is False: get_storage(plugin_object) if any(x in plugin_object.cli_args.requested_query for x in ['power', 'all']) is False: get_chassi_data(plugin_object, PowerSupply) plugin_object.in_firmware_collection_mode(False) # vendor specific conditions if plugin_object.rf.vendor == "Cisco": get_controllers = True if plugin_object.rf.vendor == "Lenovo": for fw_object in plugin_object.inventory.get(Firmware): if fw_object.name.lower().startswith("disk"): get_drives = False if fw_object.name.lower().startswith("power"): get_power = False fw_id = len(plugin_object.inventory.get(Firmware)) - 1 if get_drives is True: for drive in plugin_object.inventory.get(PhysicalDrive): fw_id += 1 firmware_inventory = Firmware(id=fw_id, name=f"Drive {drive.name}", version=drive.firmware, location=drive.location) if plugin_object.cli_args.verbose: firmware_inventory.source_data = drive.source_data plugin_object.inventory.add(firmware_inventory) if get_controllers is True: for storage_controller in plugin_object.inventory.get( StorageController): fw_id += 1 if storage_controller.firmware is None: continue firmware_inventory = Firmware( id=fw_id, name=f"Storage Controller {storage_controller.name}", version=storage_controller.firmware, location=storage_controller.location) if plugin_object.cli_args.verbose: firmware_inventory.source_data = storage_controller.source_data plugin_object.inventory.add(firmware_inventory) for storage_enclosure in plugin_object.inventory.get(StorageEnclosure): fw_id += 1 if storage_enclosure.firmware is None: continue firmware_inventory = Firmware(id=fw_id, name="Storage Enclosure", version=storage_enclosure.firmware, location=storage_enclosure.bay) if plugin_object.cli_args.verbose: firmware_inventory.source_data = storage_enclosure.source_data plugin_object.inventory.add(firmware_inventory) if get_power is True: for power_supply in plugin_object.inventory.get(PowerSupply): fw_id += 1 if power_supply.firmware is None: continue firmware_inventory = Firmware( id=fw_id, name=f"Power Supply {power_supply.model}", version=power_supply.firmware, location=f"Slot {power_supply.bay}") if plugin_object.cli_args.verbose: firmware_inventory.source_data = power_supply.source_data plugin_object.inventory.add(firmware_inventory) return
def get_single_system_info(plugin_object, redfish_url): system_response = plugin_object.rf.get(redfish_url) if system_response is None: plugin_object.add_output_data( "UNKNOWN", f"No system information data returned for API URL '{redfish_url}'") return # get model data model = system_response.get("Model") # Huawei system if plugin_object.rf.vendor == "Huawei": huawei_model = grab( system_response, f"Oem.{plugin_object.rf.vendor_dict_key}.ProductName") if huawei_model is not None: model = huawei_model # get memory size mem_size = grab(system_response, "MemorySummary.TotalSystemMemoryGiB") # Dell system # just WHY? if plugin_object.rf.vendor == "Dell" and mem_size is not None and int( mem_size) % 1024 != 0: mem_size = round(mem_size * 1024**3 / 1000**3) status_data = get_status_data(system_response.get("Status")) system_inventory = System( id=system_response.get("Id"), name=system_response.get("Name"), manufacturer=system_response.get("Manufacturer"), serial=system_response.get("SerialNumber"), health_status=status_data.get("Health"), operation_status=status_data.get("State"), power_state=system_response.get("PowerState"), bios_version=system_response.get("BiosVersion"), host_name=system_response.get("HostName"), indicator_led=system_response.get("IndicatorLED"), cpu_num=grab(system_response, "ProcessorSummary.Count"), part_number=system_response.get("PartNumber"), mem_size=mem_size, model=model, type=system_response.get("SystemType")) if plugin_object.cli_args.verbose: system_inventory.source_data = system_response # add relations system_inventory.add_relation(plugin_object.rf.get_system_properties(), system_response.get("Links")) plugin_object.inventory.add(system_inventory) host_name = "NOT SET" if system_inventory.host_name is not None and len( system_inventory.host_name) > 0: host_name = system_inventory.host_name status_text = f"Type: {system_inventory.manufacturer} {system_inventory.model} " \ f"(CPU: {system_inventory.cpu_num}, MEM: {system_inventory.mem_size}GB) - " \ f"BIOS: {system_inventory.bios_version} - " \ f"Serial: {system_inventory.serial} - " \ f"Power: {system_inventory.power_state} - Name: {host_name}" system_health_print_status = \ "CRITICAL" if system_inventory.health_status not in ["OK", "WARNING"] else system_inventory.health_status plugin_object.add_output_data(system_health_print_status, status_text, summary=not plugin_object.cli_args.detailed) # add DellSensorCollection if present if plugin_object.rf.vendor == "Dell": dell_empty_slots = list() dell_slot_collection = \ grab(system_response, f"Links.Oem.{plugin_object.rf.vendor_dict_key}.DellSlotCollection") # collect info about empty slots if dell_slot_collection is not None and dell_slot_collection.get( "@odata.id") is not None: collection_response = plugin_object.rf.get( dell_slot_collection.get("@odata.id")) if collection_response is not None and ( collection_response.get("Members") is None or len(collection_response.get("Members")) > 0): for dell_slot in collection_response.get("Members"): if dell_slot.get("EmptySlot") is True: dell_empty_slots.append(dell_slot.get("Id")) dell_sensor_collection = \ grab(system_response, f"Links.Oem.{plugin_object.rf.vendor_dict_key}.DellSensorCollection") if dell_sensor_collection is not None and dell_sensor_collection.get( "@odata.id") is not None: collection_response = plugin_object.rf.get( dell_sensor_collection.get("@odata.id")) num_members = 0 if collection_response is not None and ( collection_response.get("Members") is None or len(collection_response.get("Members")) > 0): for dell_sensor in collection_response.get("Members"): # skip if sensor slot is empty if any( x.startswith(dell_sensor.get("Id")) for x in dell_empty_slots): continue num_members += 1 this_sensor_status = "OK" if dell_sensor.get('EnabledState') == "Enabled": if "Warning" in dell_sensor.get('HealthState'): this_sensor_status = "WARNING" elif dell_sensor.get('HealthState') != "OK": this_sensor_status = "CRITICAL" plugin_object.add_output_data( this_sensor_status, 'Sensor "%s": %s (%s/%s)' % (dell_sensor.get('ElementName'), dell_sensor.get('HealthState'), dell_sensor.get('EnabledState'), dell_sensor.get('CurrentState'))) if plugin_object.cli_args.detailed is False: plugin_object.add_output_data( system_health_print_status, f"{status_text} - {num_members} health sensors are in 'OK' state", summary=True) if plugin_object.cli_args.detailed is True: # add ILO data if plugin_object.rf.vendor == "HPE": plugin_object.add_output_data( "OK", "%s - FW: %s" % (plugin_object.rf.vendor_data.ilo_version, plugin_object.rf.vendor_data.ilo_firmware_version)) # add SDCard status if plugin_object.rf.vendor == "Fujitsu": sd_card = plugin_object.rf.get(redfish_url + "/Oem/ts_fujitsu/SDCard") if sd_card.get("Inserted") is True and sd_card.get( "Mounted") is True: sd_card_status = sd_card.get("Status") sd_card_capacity = sd_card.get("CapacityMB") sd_card_free_space = sd_card.get("FreeSpaceMB") status_text = f"SDCard Capacity {sd_card_capacity}MB and {sd_card_free_space}MB free space left." plugin_object.add_output_data( "CRITICAL" if sd_card_status not in ["OK", "WARNING"] else sd_card_status, status_text) return
def get_firmware_info_fujitsu(plugin_object, system_id, bmc_only=False): # there is room for improvement # list of dicts: keys: {name, version, location} firmware_entries = list() # get iRMC firmware manager_ids = plugin_object.rf.get_system_properties("managers") if manager_ids is not None and len(manager_ids) > 0: manager_response = plugin_object.rf.get(manager_ids[0]) if manager_response.get("error"): plugin_object.add_data_retrieval_error(Firmware, manager_response, manager_ids[0]) return # get configuration irmc_configuration_link = grab( manager_response, f"Oem/{plugin_object.rf.vendor_dict_key}/iRMCConfiguration/@odata.id", separator="/") irmc_configuration = None if irmc_configuration_link is not None: irmc_configuration = plugin_object.rf.get(irmc_configuration_link) if irmc_configuration.get("error"): plugin_object.add_data_retrieval_error( Firmware, irmc_configuration, irmc_configuration_link) irmc_firmware_information = None firmware_information_link = grab(irmc_configuration, f"FWUpdate/@odata.id", separator="/") if firmware_information_link is not None: irmc_firmware_information = plugin_object.rf.get( firmware_information_link) if irmc_firmware_information.get("error"): plugin_object.add_data_retrieval_error( Firmware, irmc_firmware_information, irmc_configuration_link) if irmc_firmware_information is not None: for bmc_fw_bank in ["iRMCFwImageHigh", "iRMCFwImageLow"]: fw_info = irmc_firmware_information.get(bmc_fw_bank) if fw_info is not None: firmware_entries.append({ "id": bmc_fw_bank, "name": "%s iRMC" % fw_info.get("FirmwareRunningState"), "version": "%s, Booter %s, SDDR: %s/%s (%s)" % (fw_info.get("FirmwareVersion"), fw_info.get("BooterVersion"), fw_info.get("SDRRVersion"), fw_info.get("SDRRId"), fw_info.get("FirmwareBuildDate")), "location": "System Board" }) # special case: # Firmware information was requested from bmc check. # So we just return the bmc firmware list if bmc_only is True: return firmware_entries # get power supply and storage firmware plugin_object.in_firmware_collection_mode(True) if any(x in plugin_object.cli_args.requested_query for x in ['power', 'all']) is False: get_chassi_data(plugin_object, PowerSupply) if any(x in plugin_object.cli_args.requested_query for x in ['storage', 'all']) is False: get_storage(plugin_object) plugin_object.in_firmware_collection_mode(False) for power_supply in plugin_object.inventory.get(PowerSupply): firmware_entries.append({ "id": f"{power_supply.name}", "name": f"Power Supply {power_supply.vendor} {power_supply.model}", "version": f"{power_supply.firmware}", "location": f"{power_supply.name}" }) for drive in plugin_object.inventory.get(PhysicalDrive): firmware_entries.append({ "id": f"Drive:{drive.id}", "name": f"Drive {drive.name}", "version": f"{drive.firmware}", "location": f"Slot {drive.bay}" }) # get other firmware redfish_url = f"{system_id}/Oem/%s/FirmwareInventory/" % plugin_object.rf.vendor_dict_key system_id_num = system_id.rstrip("/").split("/")[-1] firmware_response = plugin_object.rf.get(redfish_url) if firmware_response.get("error"): plugin_object.add_data_retrieval_error(Firmware, firmware_response, redfish_url) # get BIOS if firmware_response.get("SystemBIOS"): firmware_entries.append({ "id": f"System:{system_id_num}", "name": "SystemBIOS", "version": "%s" % firmware_response.get("SystemBIOS"), "location": "System Board" }) # get other components for key, value in firmware_response.items(): if key.startswith("@"): continue if isinstance(value, dict) and value.get("@odata.id") is not None: component_type = value.get("@odata.id").rstrip("/").split("/")[-1] component_fw_data = plugin_object.rf.get(value.get("@odata.id")) if component_fw_data.get("error"): plugin_object.add_data_retrieval_error(Firmware, component_fw_data, value.get("@odata.id")) component_id = 0 for component_entry in component_fw_data.get("Ports", list()): component_id += 1 component_name = component_entry.get("AdapterName") component_location = component_entry.get("ModuleName") component_bios_version = component_entry.get("BiosVersion") component_fw_version = component_entry.get("FirmwareVersion") component_slot = component_entry.get("SlotId") component_port = component_entry.get("PortId") firmware_entries.append({ "id": f"{component_type}_Port_{component_id}", "name": f"{component_name}", "version": f"{component_fw_version} (BIOS: {component_bios_version})", "location": f"{component_location} {component_slot}/{component_port}" }) component_id = 0 for component_entry in component_fw_data.get("Adapters", list()): component_id += 1 component_name = component_entry.get("ModuleName") component_pci_segment = component_entry.get("PciSegment") component_bios_version = component_entry.get("BiosVersion") component_fw_version = component_entry.get("FirmwareVersion") firmware_entries.append({ "id": f"{component_type}_Adapter_{component_id}", "name": f"{component_name} controller", "version": f"{component_fw_version} (BIOS: {component_bios_version})", "location": f"{system_id_num}:{component_pci_segment}" }) # add firmware entry to inventory for fw_entry in firmware_entries: firmware_inventory = Firmware(**fw_entry) if plugin_object.cli_args.verbose: firmware_inventory.source_data = fw_entry plugin_object.inventory.add(firmware_inventory) return
def get_single_system_procs(plugin_object, redfish_url): plugin_object.set_current_command("Procs") systems_response = plugin_object.rf.get(redfish_url) if systems_response.get("ProcessorSummary"): proc_status = get_status_data( grab(systems_response, "ProcessorSummary.Status")) # DELL is HealthRollUp not HealthRollup # Fujitsu is just Health an not HealthRollup health = proc_status.get("HealthRollup") or proc_status.get("Health") proc_count = grab(systems_response, "ProcessorSummary.Count") proc_count_text = "" if proc_count is not None: proc_count_text = f"({proc_count}) " if health == "OK" and plugin_object.cli_args.detailed is False and plugin_object.cli_args.inventory is False: plugin_object.add_output_data( "OK", f"All processors {proc_count_text}are in good condition", summary=True) return system_response_proc_key = "Processors" if systems_response.get(system_response_proc_key) is None: issue_text = f"Returned data from API URL '{redfish_url}' has no attribute '{system_response_proc_key}'" plugin_object.inventory.add_issue(Processor, issue_text) plugin_object.add_output_data("UNKNOWN", issue_text) return processors_link = grab(systems_response, f"{system_response_proc_key}/@odata.id", separator="/") processors_response = plugin_object.rf.get_view( f"{processors_link}{plugin_object.rf.vendor_data.expand_string}") if processors_response.get( "Members") is not None or processors_response.get( system_response_proc_key) is not None: num_procs = 0 for proc in processors_response.get( "Members") or processors_response.get( system_response_proc_key) or list(): if proc.get("@odata.context"): proc_response = proc else: proc_response = plugin_object.rf.get(proc.get("@odata.id")) if proc_response.get("Id"): status_data = get_status_data(proc_response.get("Status")) model = proc_response.get("Model") vendor_data = grab(proc_response, f"Oem.{plugin_object.rf.vendor_dict_key}") if plugin_object.rf.vendor == "Dell" and grab( vendor_data, "DellProcessor") is not None: vendor_data = grab(vendor_data, "DellProcessor") # get current/regular speed current_speed = grab(vendor_data, "CurrentClockSpeedMHz") or grab(vendor_data, "RatedSpeedMHz") or \ grab(vendor_data, "FrequencyMHz") # try to extract speed from model if current_speed is None # Intel XEON CPUs if current_speed is None and model is not None and "GHz" in model: model_speed = model.split("@")[-1].strip().replace( "GHz", "") try: current_speed = int(float(model_speed) * 1000) except Exception: pass # get cache information level_1_cache_kib = grab(vendor_data, "L1CacheKiB") level_2_cache_kib = grab(vendor_data, "L2CacheKiB") level_3_cache_kib = grab(vendor_data, "L3CacheKiB") if plugin_object.rf.vendor == "Dell": level_1_cache_kib = grab(vendor_data, "Cache1InstalledSizeKB") level_2_cache_kib = grab(vendor_data, "Cache2InstalledSizeKB") level_3_cache_kib = grab(vendor_data, "Cache3InstalledSizeKB") # HPE Lenovo vendor_cache_data = grab(vendor_data, "Cache") or grab( vendor_data, "CacheInfo") if vendor_cache_data is not None: for cpu_cache in vendor_cache_data: # HPE Lenovo cache_size = cpu_cache.get( "InstalledSizeKB") or cpu_cache.get( "InstalledSizeKByte") cache_level = cpu_cache.get("Name") or cpu_cache.get( "CacheLevel") if cache_size is None or cache_level is None: continue if "L1" in cache_level: level_1_cache_kib = cache_size * 1000 / 1024 if "L2" in cache_level: level_2_cache_kib = cache_size * 1000 / 1024 if "L3" in cache_level: level_3_cache_kib = cache_size * 1000 / 1024 proc_inventory = Processor( name=proc_response.get("Name"), id=proc_response.get("Id"), model=model, socket=proc_response.get("Socket"), health_status=status_data.get("Health"), operation_status=status_data.get("State"), cores=proc_response.get("TotalCores"), threads=proc_response.get("TotalThreads"), current_speed=current_speed, max_speed=proc_response.get("MaxSpeedMHz"), manufacturer=proc_response.get("Manufacturer"), instruction_set=proc_response.get("InstructionSet"), architecture=proc_response.get("ProcessorArchitecture"), serial=grab( proc_response, f"Oem.{plugin_object.rf.vendor_dict_key}.SerialNumber" ), system_ids=systems_response.get("Id"), L1_cache_kib=level_1_cache_kib, L2_cache_kib=level_2_cache_kib, L3_cache_kib=level_3_cache_kib) if plugin_object.cli_args.verbose: proc_inventory.source_data = proc_response plugin_object.inventory.add(proc_inventory) if proc_inventory.operation_status == "Absent": continue num_procs += 1 status_text = f"Processor {proc_inventory.socket} ({proc_inventory.model}) status is: " \ f"{proc_inventory.health_status}" plugin_object.add_output_data( "CRITICAL" if proc_inventory.health_status not in ["OK", "WARNING"] else proc_inventory.health_status, status_text) else: plugin_object.add_output_data( "UNKNOWN", "No processor data returned for API URL '%s'" % proc_response.get("@odata.id")) if num_procs == 0: issue_text = f"Returned data from API URL '{processors_link}' contains no processor information" plugin_object.inventory.add_issue(Processor, issue_text) plugin_object.add_output_data( "UNKNOWN", issue_text, summary=not plugin_object.cli_args.detailed) elif plugin_object.cli_args.detailed is False: plugin_object.add_output_data( "OK", "All processors (%d) are in good condition" % num_procs, summary=True) else: plugin_object.add_output_data( "UNKNOWN", f"No processor data returned for API URL '{redfish_url}'") return
def get_single_chassi_power(plugin_object, redfish_url): plugin_object.set_current_command("Power") chassi_id = redfish_url.rstrip("/").split("/")[-1] redfish_url = f"{redfish_url}/Power" power_data = plugin_object.rf.get_view(redfish_url) if power_data.get("error"): plugin_object.add_data_retrieval_error(PowerSupply, power_data, redfish_url) return power_supplies = power_data.get("PowerSupplies", list()) fujitsu_power_sensors = None if plugin_object.rf.vendor == "Fujitsu": fujitsu_power_sensors = grab( power_data, f"Oem.{plugin_object.rf.vendor_dict_key}.ChassisPowerSensors") ps_num = 0 ps_absent = 0 if len(power_supplies) > 0: for ps in power_supplies: ps_num += 1 status_data = get_status_data(grab(ps, "Status")) health = status_data.get("Health") operational_status = status_data.get("State") part_number = ps.get("PartNumber") model = ps.get("Model") or part_number last_power_output = ps.get("LastPowerOutputWatts") or ps.get( "PowerOutputWatts") capacity_in_watt = ps.get("PowerCapacityWatts") bay = None oem_data = grab(ps, f"Oem.{plugin_object.rf.vendor_dict_key}") if oem_data is not None: if plugin_object.rf.vendor == "HPE": bay = grab(oem_data, "BayNumber") ps_hp_status = grab(oem_data, "PowerSupplyStatus.State") if ps_hp_status is not None and ps_hp_status == "Unknown": health = "CRITICAL" elif plugin_object.rf.vendor == "Lenovo": bay = grab(oem_data, "Location.Info") if last_power_output is None and grab( oem_data, "PowerOutputWatts") is not None: last_power_output = grab(oem_data, "PowerOutputWatts") if bay is None: bay = ps_num if capacity_in_watt is None: capacity_in_watt = grab(ps, "InputRanges.0.OutputWattage") # special Fujitsu case if fujitsu_power_sensors is not None and last_power_output is None: for fujitsu_power_sensor in fujitsu_power_sensors: if fujitsu_power_sensor.get("Designation") == ps.get( "Name"): last_power_output = fujitsu_power_sensor.get( "CurrentPowerConsumptionW") ps_inventory = PowerSupply( id=grab(ps, "MemberId") or ps_num, name=ps.get("Name"), model=model, bay=bay, health_status=health, operation_status=operational_status, last_power_output=last_power_output, serial=ps.get("SerialNumber"), type=ps.get("PowerSupplyType"), capacity_in_watt=capacity_in_watt, firmware=ps.get("FirmwareVersion"), vendor=ps.get("Manufacturer"), input_voltage=ps.get("LineInputVoltage"), part_number=ps.get("SparePartNumber") or ps.get("PartNumber"), chassi_ids=chassi_id) if plugin_object.cli_args.verbose: ps_inventory.source_data = ps plugin_object.inventory.add(ps_inventory) printed_status = health printed_model = "" if operational_status == "Absent": printed_status = operational_status health = "OK" ps_absent += 1 if health is None and operational_status == "Enabled": printed_status = operational_status health = "OK" if model is not None: printed_model = "(%s) " % model.strip() status_text = "Power supply {bay} {model}status is: {status}".format( bay=str(bay), model=printed_model, status=printed_status) plugin_object.add_output_data( "CRITICAL" if health not in ["OK", "WARNING"] else health, status_text, location=f"Chassi {chassi_id}") if last_power_output is not None: plugin_object.add_perf_data(f"ps_{bay}", int(last_power_output), location=f"Chassi {chassi_id}") default_text = "All power supplies (%d) are in good condition" % ( ps_num - ps_absent) else: default_text = "No power supplies detected" plugin_object.inventory.add_issue( PowerSupply, f"No power supply data returned for API URL '{redfish_url}'") # get PowerRedundancy status power_redundancies = power_data.get("PowerRedundancy") or power_data.get( "Redundancy") if power_redundancies: pr_status_summary_text = "" pr_num = 0 for power_redundancy in power_redundancies: pr_status = power_redundancy.get("Status") if pr_status is not None: status = pr_status.get("Health") state = pr_status.get("State") if status is not None: pr_num += 1 status = status.upper() status_text = f"Power redundancy {pr_num} status is: {state}" pr_status_summary_text += f" {status_text}" plugin_object.add_output_data( "CRITICAL" if status not in ["OK", "WARNING"] else status, status_text, location=f"Chassi {chassi_id}") if len(pr_status_summary_text) != 0: default_text += f" and{pr_status_summary_text}" # get Voltages status voltages = power_data.get("Voltages") if voltages is not None: voltages_num = 0 for voltage in voltages: voltage_status = voltage.get("Status") if voltage_status is not None: status = voltage_status.get("Health") state = voltage_status.get("State") reading = voltage.get("ReadingVolts") name = voltage.get("Name") if status is not None: voltages_num += 1 status = status.upper() status_text = f"Voltage {name} (status: {status}/{state}): {reading}V" plugin_object.add_output_data( "CRITICAL" if status not in ["OK", "WARNING"] else status, status_text, location=f"Chassi {chassi_id}") if reading is not None and name is not None: try: plugin_object.add_perf_data( f"voltage_{name}", float(reading), location=f"Chassi {chassi_id}") except Exception: pass if voltages_num > 0: default_text += f" and {voltages_num} Voltages are OK" plugin_object.add_output_data("OK", default_text, summary=True, location=f"Chassi {chassi_id}") return
def get_network_function(function_data=None): # could be # * a string # * a dict with just the link # * a dict with full data function_response = None redfish_path = None if isinstance(function_data, dict): if function_data.get("Id") is not None: function_response = function_data else: redfish_path = function_data.get("@odata.id") elif isinstance(function_data, str): redfish_path = function_data # query data if function_response is None and redfish_path is not None: function_response = plugin_object.rf.get_view(f"{redfish_path}{plugin_object.rf.vendor_data.expand_string}") port_inventory = None if function_response is not None: physical_port_path = grab(function_response, "Links.PhysicalPortAssignment") or \ grab(function_response, "PhysicalPortAssignment") if physical_port_path is None: return network_function_id = function_response.get("Id") port_inventory = get_network_port(physical_port_path, network_function_id, True) if plugin_object.cli_args.verbose: source_data = getattr(port_inventory, "source_data") source_data["function"] = function_response port_inventory.update("source_data", source_data) port_inventory.add_relation(plugin_object.rf.get_system_properties(), function_response.get("Links")) port_inventory.add_relation(plugin_object.rf.get_system_properties(), function_response.get("RelatedItem")) # get health status status_data = get_status_data(function_response.get("Status")) if port_inventory.health_status is None: port_inventory.health_status = status_data.get("Health") if port_inventory.operation_status is None: port_inventory.operation_status = status_data.get("State") # get and sanitize MAC and WWPN addresses port_inventory.update("addresses", format_interface_addresses(grab(function_response, "Ethernet.PermanentMACAddress")) + format_interface_addresses(grab(function_response, "Ethernet.MACAddress")) + format_interface_addresses(grab(function_response, "FibreChannel.PermanentWWPN")) + format_interface_addresses(grab(function_response, "FibreChannel.WWPN")), append=True) # set VLAN settings port_inventory.vlan_id = grab(function_response, "Ethernet.VLAN.VLANId") port_inventory.vlan_enabled = grab(function_response, "Ethernet.VLAN.VLANEnable") # get IP addresses vendor_data = grab(function_response, f"Oem.{plugin_object.rf.vendor_dict_key}") if vendor_data is not None: port_inventory.ipv4_addresses = get_interface_ip_addresses(vendor_data, "IPv4Addresses") port_inventory.ipv6_addresses = get_interface_ip_addresses(vendor_data, "IPv6Addresses") # set link type port_inventory.update("link_type", function_response.get("NetDevFuncType")) if plugin_object.rf.vendor == "Cisco": port_inventory.update("os_name", function_response.get("Name")) if plugin_object.rf.vendor == "Dell": duplex_setting = \ grab(function_response, f"Oem.{plugin_object.rf.vendor_dict_key}.DellNIC.LinkDuplex") or "" if "full" in duplex_setting.lower(): port_inventory.update("full_duplex", True) elif "half" in duplex_setting.lower(): port_inventory.update("full_duplex", False) port_inventory.update("name", grab(function_response, f"Oem.{plugin_object.rf.vendor_dict_key}.DellNIC.DeviceDescription")) return port_inventory
def get_single_system_mem(plugin_object, redfish_url): plugin_object.set_current_command("Mem") systems_response = plugin_object.rf.get(redfish_url) if systems_response.get("MemorySummary"): memory_status = get_status_data( grab(systems_response, "MemorySummary.Status")) # DELL is HealthRollUp not HealthRollup # Fujitsu is just Health an not HealthRollup health = memory_status.get("HealthRollup") or memory_status.get( "Health") if health == "OK" and plugin_object.cli_args.detailed is False and plugin_object.cli_args.inventory is False: total_mem = grab(systems_response, "MemorySummary.TotalSystemMemoryGiB") or 0 if plugin_object.rf.vendor == "Dell" and total_mem % 1024 != 0: total_mem = total_mem * 1024**3 / 1000**3 plugin_object.add_output_data( "OK", "All memory modules (Total %dGB) are in good condition" % total_mem, summary=True) return system_response_memory_key = "Memory" if grab( systems_response, f"Oem.{plugin_object.rf.vendor_dict_key}.Links.{system_response_memory_key}" ): memory_path_dict = grab( systems_response, f"Oem.{plugin_object.rf.vendor_dict_key}.Links") else: memory_path_dict = systems_response if memory_path_dict.get(system_response_memory_key) is None: issue_text = f"Returned data from API URL '{redfish_url}' has no attribute '{system_response_memory_key}'" plugin_object.inventory.add_issue(Memory, issue_text) plugin_object.add_output_data("UNKNOWN", issue_text) return redfish_url = memory_path_dict.get(system_response_memory_key).get( "@odata.id") + "%s" % plugin_object.rf.vendor_data.expand_string memory_response = plugin_object.rf.get_view(redfish_url) num_dimms = 0 size_sum = 0 if memory_response.get("Members") or memory_response.get( system_response_memory_key): for mem_module in memory_response.get( "Members") or memory_response.get(system_response_memory_key): if mem_module.get("@odata.context"): mem_module_response = mem_module else: mem_module_response = plugin_object.rf.get( mem_module.get("@odata.id")) if mem_module_response.get("Id"): # get size module_size = mem_module_response.get( "SizeMB") or mem_module_response.get("CapacityMiB") or 0 module_size = int(module_size) # DELL fix for iDRAC 8 if plugin_object.rf.vendor == "Dell" and module_size % 1024 != 0: module_size = round(module_size * 1024**2 / 1000**2) # get name module_name = mem_module_response.get( "SocketLocator") or mem_module_response.get( "DeviceLocator") or mem_module_response.get("Name") if module_name is None: module_name = "UnknownNameLocation" # get status status_data = get_status_data( mem_module_response.get("Status")) if plugin_object.rf.vendor == "HPE" and grab( mem_module_response, f"Oem.{plugin_object.rf.vendor_dict_key}.DIMMStatus"): status_data["State"] = grab( mem_module_response, f"Oem.{plugin_object.rf.vendor_dict_key}.DIMMStatus") elif mem_module_response.get("DIMMStatus"): status_data["State"] = mem_module_response.get( "DIMMStatus") mem_inventory = Memory( name=module_name, id=mem_module_response.get("Id"), health_status=status_data.get("Health"), operation_status=status_data.get("State"), size_in_mb=module_size, manufacturer=mem_module_response.get("Manufacturer"), serial=mem_module_response.get("SerialNumber"), socket=grab(mem_module_response, "MemoryLocation.Socket"), slot=grab(mem_module_response, "MemoryLocation.Slot"), channel=grab(mem_module_response, "MemoryLocation.Channel"), speed=mem_module_response.get("OperatingSpeedMhz"), part_number=mem_module_response.get("PartNumber"), type=mem_module_response.get("MemoryDeviceType") or mem_module_response.get("MemoryType"), base_type=mem_module_response.get("BaseModuleType"), system_ids=systems_response.get("Id")) if plugin_object.cli_args.verbose: mem_inventory.source_data = mem_module_response plugin_object.inventory.add(mem_inventory) if mem_inventory.operation_status in ["Absent", "NotPresent"]: continue num_dimms += 1 size_sum += module_size if mem_inventory.operation_status in ["GoodInUse", "Operable"]: plugin_status = "OK" status_text = mem_inventory.operation_status else: plugin_status = mem_inventory.health_status status_text = plugin_status status_text = f"Memory module {mem_inventory.name} (%.1fGB) status is: {status_text}" % ( mem_inventory.size_in_mb / 1024) plugin_object.add_output_data( "CRITICAL" if plugin_status not in ["OK", "WARNING"] else plugin_status, status_text) else: plugin_object.add_output_data( "UNKNOWN", "No memory data returned for API URL '%s'" % mem_module.get("@odata.id")) if num_dimms == 0: plugin_object.add_output_data( "UNKNOWN", f"No memory data returned for API URL '{redfish_url}'") else: plugin_object.add_output_data( "OK", f"All {num_dimms} memory modules (Total %.1fGB) are in good condition" % (size_sum / 1024), summary=True) return
def determine_vendor(self): vendor_string = "" if self.connection.root.get("Oem"): if len(self.connection.root.get("Oem")) > 0: vendor_string = list(self.connection.root.get("Oem"))[0] self.vendor_dict_key = vendor_string if vendor_string == "" and self.connection.root.get( "Vendor") is not None: vendor_string = self.connection.root.get("Vendor") self.vendor_dict_key = vendor_string if vendor_string in ["Hpe", "Hp"]: self.vendor_data = VendorHPEData() manager_data = grab(self.connection.root, f"Oem.{vendor_string}.Manager.0") if manager_data is not None: self.vendor_data.ilo_version = manager_data.get("ManagerType") if self.vendor_data.ilo_version is None: # Fix for iLO 5 version >2.3.0 self.vendor_data.ilo_version = \ grab(self.connection.root, f"Oem.{vendor_string}.Moniker.PRODGEN") self.vendor_data.ilo_firmware_version = manager_data.get( "ManagerFirmwareVersion") if self.vendor_data.ilo_firmware_version is None: # Fix for iLO 5 version >2.3.0 self.vendor_data.ilo_firmware_version = grab( manager_data, "Languages.0.Version") if self.vendor_data.ilo_version is None: self.exit_on_error( "Cannot determine HPE iLO version information.") if self.vendor_data.ilo_version.lower() == "ilo 5": self.vendor_data.view_supported = True if vendor_string in ["Lenovo"]: self.vendor_data = VendorLenovoData() if vendor_string in ["Dell"]: self.vendor_data = VendorDellData() if vendor_string in ["Huawei"]: self.vendor_data = VendorHuaweiData() if vendor_string in ["ts_fujitsu"]: self.vendor_data = VendorFujitsuData() # Cisco does not provide a OEM property in root object if "CIMC" in str(self.get_system_properties("managers")): self.vendor_data = VendorCiscoData() self.vendor_dict_key = self.vendor_data.name if self.vendor_data is None: self.vendor_data = VendorGeneric() if vendor_string is not None and len(vendor_string) > 0: self.vendor_data.name = vendor_string self.vendor = self.vendor_data.name return
def get_single_system_info(plugin_object, redfish_url): system_response = plugin_object.rf.get(redfish_url) if system_response is None: plugin_object.add_output_data( "UNKNOWN", f"No system information data returned for API URL '{redfish_url}'") return # get model data model = system_response.get("Model") # Huawei system if plugin_object.rf.vendor == "Huawei": model = grab(system_response, f"Oem.{plugin_object.rf.vendor_dict_key}.ProductName") # get memory size mem_size = grab(system_response, "MemorySummary.TotalSystemMemoryGiB") # Dell system # just WHY? if plugin_object.rf.vendor == "Dell" and mem_size is not None and int( mem_size) % 1024 != 0: mem_size = round(mem_size * 1024**3 / 1000**3) status_data = get_status_data(system_response.get("Status")) system_inventory = System( id=system_response.get("Id"), name=system_response.get("Name"), manufacturer=system_response.get("Manufacturer"), serial=system_response.get("SerialNumber"), health_status=status_data.get("Health"), operation_status=status_data.get("State"), power_state=system_response.get("PowerState"), bios_version=system_response.get("BiosVersion"), host_name=system_response.get("HostName"), indicator_led=system_response.get("IndicatorLED"), cpu_num=grab(system_response, "ProcessorSummary.Count"), part_number=system_response.get("PartNumber"), mem_size=mem_size, model=model, type=system_response.get("SystemType")) if plugin_object.cli_args.verbose: system_inventory.source_data = system_response # add relations system_inventory.add_relation(plugin_object.rf.get_system_properties(), system_response.get("Links")) plugin_object.inventory.add(system_inventory) host_name = "NOT SET" if system_inventory.host_name is not None and len( system_inventory.host_name) > 0: host_name = system_inventory.host_name status_text = f"Type: {system_inventory.manufacturer} {system_inventory.model} " \ f"(CPU: {system_inventory.cpu_num}, MEM: {system_inventory.mem_size}GB) - " \ f"BIOS: {system_inventory.bios_version} - " \ f"Serial: {system_inventory.serial} - " \ f"Power: {system_inventory.power_state} - Name: {host_name}" plugin_object.add_output_data( "CRITICAL" if system_inventory.health_status not in ["OK", "WARNING"] else system_inventory.health_status, status_text, summary=not plugin_object.cli_args.detailed) if plugin_object.cli_args.detailed is True: # add ILO data if plugin_object.rf.vendor == "HPE": plugin_object.add_output_data( "OK", "%s - FW: %s" % (plugin_object.rf.vendor_data.ilo_version, plugin_object.rf.vendor_data.ilo_firmware_version)) # add SDCard status if plugin_object.rf.vendor == "Fujitsu": sd_card = plugin_object.rf.get(redfish_url + "/Oem/ts_fujitsu/SDCard") if sd_card.get("Inserted") is True: sd_card_status = sd_card.get("Status") sd_card_capacity = sd_card.get("CapacityMB") sd_card_free_space = sd_card.get("FreeSpaceMB") status_text = f"SDCard Capacity {sd_card_capacity}MB and {sd_card_free_space}MB free space left." plugin_object.add_output_data( "CRITICAL" if sd_card_status not in ["OK", "WARNING"] else sd_card_status, status_text) return
def get_network_port(port_data=None, network_function_id=None, return_data=False): # could be # * a string # * a dict with just the link # * a dict with full data port_response = None redfish_path = None if isinstance(port_data, dict): if port_data.get("Id") is not None: port_response = port_data else: redfish_path = port_data.get("@odata.id") elif isinstance(port_data, str): redfish_path = port_data # query data if port_response is None and redfish_path is not None: port_response = plugin_object.rf.get_view(f"{redfish_path}{plugin_object.rf.vendor_data.expand_string}") if port_response is None: return NetworkPort() # get health status status_data = get_status_data(port_response.get("Status")) # get Link speed current_speed = \ port_response.get("CurrentLinkSpeedMbps") or \ grab(port_response, "SupportedLinkCapabilities.0.LinkSpeedMbps") or \ grab(port_response, "SupportedLinkCapabilities.LinkSpeedMbps") if isinstance(current_speed, str): current_speed = current_speed.replace("Gbps", "000") if str(current_speed) == "-": current_speed = None # get port number if port_response.get("PhysicalPortNumber"): nic_port_name = "Port " + port_response.get("PhysicalPortNumber") else: nic_port_name = port_response.get("Name") if plugin_object.rf.vendor == "Cisco" and network_function_id is not None: port_id = f"{network_function_id}.{port_response.get('Id')}" else: port_id = port_response.get('Id') if plugin_object.rf.vendor != "Dell": port_id = f"{adapter_id}.{port_id}" # check if port has already be added if port_id in [p.id for p in plugin_object.inventory.get(NetworkPort)]: print(f"ALREADY in INVENTORY: {port_id}") return network_port_inventory = NetworkPort( id=port_id, name=port_response.get("Name"), port_name=nic_port_name, health_status=status_data.get("Health"), operation_status=status_data.get("State"), addresses=format_interface_addresses(grab(port_response, "AssociatedNetworkAddresses")), link_type=port_response.get("ActiveLinkTechnology"), autoneg=grab(port_response, "SupportedLinkCapabilities.0.AutoSpeedNegotiation"), current_speed=current_speed, capable_speed=grab(port_response, "SupportedLinkCapabilities.0.CapableLinkSpeedMbps.0"), link_status=f"{port_response.get('LinkStatus') or ''}".replace("Link", ""), system_ids=system_id ) network_port_inventory.add_relation(plugin_object.rf.get_system_properties(), port_response.get("Links")) network_port_inventory.add_relation(plugin_object.rf.get_system_properties(), port_response.get("RelatedItem")) plugin_object.inventory.add(network_port_inventory) if plugin_object.cli_args.verbose: network_port_inventory.source_data = {"port": port_response} if return_data is True: return network_port_inventory return
def get_single_chassi_fan(plugin_object, redfish_url): plugin_object.set_current_command("Fan") chassi_id = redfish_url.rstrip("/").split("/")[-1] redfish_url = f"{redfish_url}/Thermal" thermal_data = plugin_object.rf.get_view(redfish_url) default_text = "" fan_num = 0 if "Fans" in thermal_data: for fan in thermal_data.get("Fans"): status_data = get_status_data(grab(fan, "Status")) member_id = grab(fan, "MemberId") name = fan.get("FanName") or fan.get("Name") if member_id is None: member_id = name # This helps on systems where the same MemberId could be assigned to multiple instances if grab(fan, "SensorNumber") is not None: member_id = f"{member_id}.{grab(fan, 'SensorNumber')}" physical_context = fan.get("PhysicalContext") oem_data = grab(fan, f"Oem.{plugin_object.rf.vendor_dict_key}") if physical_context is None: physical_context = grab(oem_data, "Location") or grab( oem_data, "Position") fan_inventory = Fan( id=member_id, name=name, health_status=status_data.get("Health"), operation_status=status_data.get("State"), physical_context=physical_context, min_reading=fan.get("MinReadingRange"), max_reading=fan.get("MaxReadingRange"), lower_threshold_non_critical=fan.get( "LowerThresholdNonCritical"), lower_threshold_critical=fan.get("LowerThresholdCritical"), lower_threshold_fatal=fan.get("LowerThresholdFatal"), upper_threshold_non_critical=fan.get( "UpperThresholdNonCritical"), upper_threshold_critical=fan.get("UpperThresholdCritical"), upper_threshold_fatal=fan.get("UpperThresholdFatal"), location=grab( fan, f"Oem.{plugin_object.rf.vendor_dict_key}.Location.Info"), chassi_ids=chassi_id) if plugin_object.cli_args.verbose: fan_inventory.source_data = fan text_units = "" fan_status = fan_inventory.health_status # add relations fan_inventory.add_relation( plugin_object.rf.get_system_properties(), fan.get("Links")) fan_inventory.add_relation( plugin_object.rf.get_system_properties(), fan.get("RelatedItem")) perf_units = "" # DELL, Fujitsu, Huawei if fan.get("ReadingRPM") is not None or fan.get( "ReadingUnits") == "RPM": fan_inventory.reading = fan.get("ReadingRPM") or fan.get( "Reading") fan_inventory.reading_unit = "RPM" text_units = " RPM" # HP, Lenovo else: fan_inventory.reading = fan.get("Reading") fan_inventory.reading_unit = fan.get("ReadingUnits") if fan_inventory.reading_unit == "Percent": text_units = "%" perf_units = "%" text_speed = f" ({fan_inventory.reading}{text_units})" plugin_object.inventory.add(fan_inventory) if fan_inventory.operation_status == "Absent": continue if fan_inventory.health_status is None: fan_status = "OK" if fan_inventory.operation_status == "Enabled" else fan_inventory.operation_status fan_num += 1 status_text = f"Fan '{fan_inventory.name}'{text_speed} status is: {fan_status}" plugin_object.add_output_data( "CRITICAL" if fan_status not in ["OK", "WARNING"] else fan_status, status_text) if fan_inventory.reading is not None: plugin_object.add_perf_data( f"Fan_{fan_inventory.name}", int(fan_inventory.reading), perf_uom=perf_units, warning=plugin_object.cli_args.warning, critical=plugin_object.cli_args.critical) default_text = f"All fans ({fan_num}) are in good condition" else: plugin_object.add_output_data( "UNKNOWN", f"No thermal data returned for API URL '{redfish_url}'") # get FanRedundancy status fan_redundancies = plugin_object.rf.get_view(redfish_url).get( "FanRedundancy") if fan_redundancies is None: fan_redundancies = plugin_object.rf.get_view(redfish_url).get( "Redundancy") if fan_redundancies: status_text = "" for fan_redundancy in fan_redundancies: fr_status = get_status_data(fan_redundancy.get("Status")) status = fr_status.get("Health") if status is not None: status_text = "fan redundancy status is: %s" % fr_status.get( "State") plugin_object.add_output_data( "CRITICAL" if status not in ["OK", "WARNING"] else status, status_text[0].upper() + status_text[1:]) if len(status_text) != 0: default_text += f" and {status_text}" plugin_object.add_output_data("OK", default_text, summary=True) return plugin_object