blob: 22e58f71e6d4888a45e43dbc8babcc218ecbffd5 [file] [log] [blame] [edit]
#!/usr/bin/env python3
"""Tool to visualize PLDM PDR's"""
import argparse
import hashlib
import json
import os
import shlex
import shutil
import sys
from datetime import datetime
from graphviz import Digraph
from tabulate import tabulate
def prepare_summary_report(state_sensor_pdr, state_effecter_pdr):
"""This function is responsible to parse the state sensor pdr
and the state effecter pdr dictionaries and creating the
summary table.
Parameters:
state_sensor_pdr: list of state sensor pdrs
state_effecter_pdr: list of state effecter pdrs
"""
summary_table = []
headers = ["sensor_id", "entity_type", "state_set", "states"]
summary_table.append(headers)
for value in state_sensor_pdr.values():
summary_record = []
sensor_possible_states = ""
for sensor_state in value["possibleStates[0]"]:
sensor_possible_states += sensor_state + "\n"
summary_record.extend(
[
value["sensorID"],
value["entityType"],
value["stateSetID[0]"],
sensor_possible_states,
]
)
summary_table.append(summary_record)
print("Created at : ", datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
print(tabulate(summary_table, tablefmt="fancy_grid", headers="firstrow"))
summary_table = []
headers = ["effecter_id", "entity_type", "state_set", "states"]
summary_table.append(headers)
for value in state_effecter_pdr.values():
summary_record = []
effecter_possible_states = ""
for state in value["possibleStates[0]"]:
effecter_possible_states += state + "\n"
summary_record.extend(
[
value["effecterID"],
value["entityType"],
value["stateSetID[0]"],
effecter_possible_states,
]
)
summary_table.append(summary_record)
print(tabulate(summary_table, tablefmt="fancy_grid", headers="firstrow"))
def draw_entity_associations(pdr, counter):
"""This function is responsible to create a picture that captures
the entity association hierarchy based on the entity association
PDR's received from the BMC.
Parameters:
pdr: list of entity association PDR's
counter: variable to capture the count of PDR's to unflatten
the tree
"""
dot = Digraph(
"entity_hierarchy",
node_attr={"color": "lightblue1", "style": "filled"},
)
dot.attr(
label=r"\n\nEntity Relation Diagram < "
+ str(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
+ ">\n"
)
dot.attr(fontsize="20")
edge_list = []
for value in pdr.values():
parentnode = "{}, {}, {}".format(str(value["containerEntityContainerID"]),
str(value["containerEntityType"]),
str(value["containerEntityInstanceNumber"]))
dot.node(
hashlib.md5(
(
parentnode + str(value["containerEntityContainerID"])
).encode()
).hexdigest(),
parentnode,
)
for i in range(1, value["containedEntityCount"] + 1):
childnode = "{}, {}, {}".format(str(value[f"containedEntityContainerID[{i}]"]),
str(value[f"containedEntityType[{i}]"]),
str(value[f"containedEntityInstanceNumber[{i}]"]))
cid = str(value[f"containedEntityContainerID[{i}]"])
dot.node(
hashlib.md5((childnode + cid).encode()).hexdigest(), childnode
)
if [
hashlib.md5(
(
parentnode + str(value["containerEntityContainerID"])
).encode()
).hexdigest(),
hashlib.md5((childnode + cid).encode()).hexdigest(),
] not in edge_list:
edge_list.append(
[
hashlib.md5(
(
parentnode
+ str(value["containerEntityContainerID"])
).encode()
).hexdigest(),
hashlib.md5((childnode + cid).encode()).hexdigest(),
]
)
dot.edge(
hashlib.md5(
(
parentnode
+ str(value["containerEntityContainerID"])
).encode()
).hexdigest(),
hashlib.md5((childnode + cid).encode()).hexdigest(),
)
unflattentree = dot.unflatten(stagger=(round(counter / 3)))
unflattentree.render(
filename="entity_association_"
+ str(datetime.now().strftime("%Y-%m-%d_%H-%M-%S")),
view=False,
cleanup=True,
format="pdf",
)
def fetch_pdrs_from_file(filename):
entity_association_pdr = {}
state_sensor_pdr = {}
state_effecter_pdr = {}
state_effecter_pdr = {}
numeric_pdr = {}
fru_record_set_pdr = {}
tl_pdr = {}
for pdr in json.load(open(filename)):
handle_number = pdr["recordHandle"]
if pdr["PDRType"] == "Entity Association PDR":
entity_association_pdr[handle_number] = pdr
if pdr["PDRType"] == "State Sensor PDR":
state_sensor_pdr[handle_number] = pdr
if pdr["PDRType"] == "State Effecter PDR":
state_effecter_pdr[handle_number] = pdr
if pdr["PDRType"] == "FRU Record Set PDR":
fru_record_set_pdr[handle_number] = pdr
if pdr["PDRType"] == "Terminus Locator PDR":
tl_pdr[handle_number] = pdr
if pdr["PDRType"] == "Numeric Effecter PDR":
numeric_pdr[handle_number] = pdr
total_pdrs = (
len(entity_association_pdr.keys())
+ len(tl_pdr.keys())
+ len(state_effecter_pdr.keys())
+ len(numeric_pdr.keys())
+ len(state_sensor_pdr.keys())
+ len(fru_record_set_pdr.keys())
)
print("\nSuccessfully fetched " + str(total_pdrs) + " PDR's")
print("Number of FRU Record PDR's : ", len(fru_record_set_pdr.keys()))
print("Number of TerminusLocator PDR's : ", len(tl_pdr.keys()))
print("Number of State Sensor PDR's : ", len(state_sensor_pdr.keys()))
print("Number of State Effecter PDR's : ", len(state_effecter_pdr.keys()))
print("Number of Numeric Effecter PDR's : ", len(numeric_pdr.keys()))
print(
"Number of Entity Association PDR's : ",
len(entity_association_pdr.keys()),
)
return (
entity_association_pdr,
state_sensor_pdr,
state_effecter_pdr,
len(fru_record_set_pdr.keys()),
)
def main():
"""Create a summary table capturing the information of all the PDR's
from the BMC & also create a diagram that captures the entity
association hierarchy."""
parser = argparse.ArgumentParser(prog="pldm_visualise_pdrs_fromfile.py")
parser.add_argument("--file", type=str, help="filename which contains 'getpdr -a' data")
args = parser.parse_args()
if args.file:
(
association_pdr,
state_sensor_pdr,
state_effecter_pdr,
counter,
) = fetch_pdrs_from_file(args.file)
draw_entity_associations(association_pdr, counter)
prepare_summary_report(state_sensor_pdr, state_effecter_pdr)
if __name__ == "__main__":
main()