1#!/usr/bin/env python3
2
3r"""
4PEL functions.
5"""
6
7import json
8import os
9import sys
10from datetime import datetime
11
12import bmc_ssh_utils as bsu
13import func_args as fa
14
15base_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
16sys.path.append(base_path + "/data/")
17
18import pel_variables  # NOQA
19
20
21class peltool_exception(Exception):
22    r"""
23    Base class for peltool related exceptions.
24    """
25
26    def __init__(self, message):
27        self.message = message
28        super().__init__(self.message)
29
30
31def peltool(option_string, parse_json=True, **bsu_options):
32    r"""
33    Run peltool on the BMC with the caller's option string and return the result.
34
35    Example:
36
37    ${pel_results}=  Peltool  -l
38    Rprint Vars  pel_results
39
40    pel_results:
41      [0x50000031]:
42        [CompID]:                       0x1000
43        [PLID]:                         0x50000031
44        [Subsystem]:                    BMC Firmware
45        [Message]:                      An application had an internal failure
46        [SRC]:                          BD8D1002
47        [Commit Time]:                  02/25/2020  04:51:31
48        [Sev]:                          Unrecoverable Error
49        [CreatorID]:                    BMC
50
51    Description of argument(s):
52    option_string                   A string of options which are to be processed by the peltool command.
53    parse_json                      Indicates that the raw JSON data should parsed into a list of
54                                    dictionaries.
55    bsu_options                     Options to be passed directly to bmc_execute_command. See its prolog for
56                                    details.
57    """
58
59    bsu_options = fa.args_to_objects(bsu_options)
60    out_buf, stderr, rc = bsu.bmc_execute_command(
61        "peltool " + option_string, **bsu_options
62    )
63    if parse_json:
64        try:
65            return json.loads(out_buf)
66        except ValueError:
67            return {}
68    return out_buf
69
70
71def get_pel_data_from_bmc(
72    include_hidden_pels=False, include_informational_pels=False
73):
74    r"""
75    Returns PEL data from BMC else throws exception.
76
77    Description of arguments:
78    include_hidden_pels           True/False (default: False).
79                                  Set True to get hidden PELs else False.
80    include_informational_pels    True/False (default: False).
81                                  Set True to get informational PELs else False.
82    """
83    try:
84        pel_cmd = " -l"
85        if include_hidden_pels:
86            pel_cmd = pel_cmd + " -h"
87        if include_informational_pels:
88            pel_cmd = pel_cmd + " -f"
89        pel_data = peltool(pel_cmd)
90        if not pel_data:
91            print("No PEL data present in BMC ...")
92    except Exception as e:
93        raise peltool_exception("Failed to get PEL data from BMC : " + str(e))
94    return pel_data
95
96
97def verify_no_pel_exists_on_bmc():
98    r"""
99    Verify that no PEL exists in BMC. Raise an exception if it does.
100    """
101
102    try:
103        pel_data = get_pel_data_from_bmc()
104
105        if len(pel_data) == 0:
106            return True
107        else:
108            print("PEL data present. \n", pel_data)
109            raise peltool_exception("PEL data present in BMC")
110    except Exception as e:
111        raise peltool_exception("Failed to get PEL data from BMC : " + str(e))
112
113
114def compare_pel_and_redfish_event_log(pel_record, event_record):
115    r"""
116    Compare PEL log attributes like "SRC", "Created at" with Redfish
117    event log attributes like "EventId", "Created".
118    Return False if they do not match.
119
120    Description of arguments:
121    pel_record     PEL record.
122    event_record   Redfish event which is equivalent of PEL record.
123    """
124
125    try:
126        # Below is format of PEL record / event record and following
127        # i.e. "SRC", "Created at" from
128        # PEL record is compared with "EventId", "Created" from event record.
129
130        # PEL Log attributes
131        # SRC        : XXXXXXXX
132        # Created at : 11/14/2022 12:38:04
133
134        # Event log attributes
135        # EventId : XXXXXXXX XXXXXXXX XXXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX
136
137        # Created : 2022-11-14T12:38:04+00:00
138
139        print("\nPEL records : {0}".format(pel_record))
140        print("\nEvent records : {0}".format(event_record))
141
142        pel_src = pel_record["pel_data"]["SRC"]
143        pel_created_time = pel_record["pel_detail_data"]["Private Header"][
144            "Created at"
145        ]
146
147        event_ids = (event_record["EventId"]).split(" ")
148
149        event_time_format = (event_record["Created"]).split("T")
150        event_date = (event_time_format[0]).split("-")
151        event_date = datetime(
152            int(event_date[0]), int(event_date[1]), int(event_date[2])
153        )
154        event_date = event_date.strftime("%m/%d/%Y")
155        event_sub_time_format = (event_time_format[1]).split("+")
156        event_date_time = event_date + " " + event_sub_time_format[0]
157
158        event_created_time = event_date_time.replace("-", "/")
159
160        print(
161            "\nPEL SRC : {0} | PEL Created Time : {1}".format(
162                pel_src, pel_created_time
163            )
164        )
165        print(
166            "\nError event ID : {0} | Error Log Created Time : {1}".format(
167                event_ids[0], event_created_time
168            )
169        )
170
171        if pel_src == event_ids[0] and pel_created_time == event_created_time:
172            print(
173                "\nPEL SRC and created date time match with "
174                "event ID, created time"
175            )
176        else:
177            raise peltool_exception(
178                "\nPEL SRC and created date time did not "
179                "match with event ID, created time"
180            )
181    except Exception as e:
182        raise peltool_exception(
183            "Exception occurred during PEL and Event log "
184            "comparison for SRC or event ID and created "
185            "time : "
186            + str(e)
187        )
188
189
190def fetch_all_pel_ids_for_src(src_id, severity, include_hidden_pels=False):
191    r"""
192    Fetch all PEL IDs for the input SRC ID based on the severity type
193    in the list format.
194
195    Description of arguments:
196    src_id                SRC ID (e.g. BCXXYYYY).
197    severity              PEL severity (e.g. "Predictive Error"
198                                             "Recovered Error").
199    include_hidden_pels   True/False (default: False).
200                          Set True to get hidden PELs else False.
201    """
202
203    try:
204        src_pel_ids = []
205        pel_data = get_pel_data_from_bmc(include_hidden_pels)
206        pel_id_list = pel_data.keys()
207        for pel_id in pel_id_list:
208            # Check if required SRC ID with severity is present
209            if (pel_data[pel_id]["SRC"] == src_id) and (
210                pel_data[pel_id]["Sev"] == severity
211            ):
212                src_pel_ids.append(pel_id)
213
214        if not src_pel_ids:
215            raise peltool_exception(
216                src_id + " with severity " + severity + " not present"
217            )
218    except Exception as e:
219        raise peltool_exception(
220            "Failed to fetch PEL ID for required SRC : " + str(e)
221        )
222    return src_pel_ids
223
224
225def fetch_all_src(include_hidden_pels=False):
226    r"""
227    Fetch all SRC IDs from peltool in the list format.
228
229    include_hidden_pels       True/False (default: False).
230                              Set True to get hidden PELs else False.
231    """
232    try:
233        src_id = []
234        pel_data = get_pel_data_from_bmc(include_hidden_pels)
235        if pel_data:
236            pel_id_list = pel_data.keys()
237            for pel_id in pel_id_list:
238                src_id.append(pel_data[pel_id]["SRC"])
239        print("SRC IDs: " + str(src_id))
240    except Exception as e:
241        raise peltool_exception("Failed to fetch all SRCs : " + str(e))
242    return src_id
243
244
245def check_for_unexpected_src(
246    unexpected_src_list=[], include_hidden_pels=False
247):
248    r"""
249    From the given unexpected SRC list, check if any unexpected SRC created
250    on the BMC. Returns 0 if no SRC found else throws exception.
251
252    Description of arguments:
253    unexpected_src_list       Give unexpected SRCs in the list format.
254                              e.g.: ["BBXXYYYY", "AAXXYYYY"].
255
256    include_hidden_pels       True/False (default: False).
257                              Set True to get hidden PELs else False.
258    """
259    try:
260        unexpected_src_count = 0
261        if not unexpected_src_list:
262            print("Unexpected SRC list is empty.")
263        src_data = fetch_all_src(include_hidden_pels)
264        for src in unexpected_src_list:
265            if src in src_data:
266                print("Found an unexpected SRC : " + src)
267                unexpected_src_count = unexpected_src_count + 1
268        if unexpected_src_count >= 1:
269            raise peltool_exception("Unexpected SRC found.")
270
271    except Exception as e:
272        raise peltool_exception(
273            "Failed to verify unexpected SRC list : " + str(e)
274        )
275    return unexpected_src_count
276
277
278def filter_unexpected_srcs(expected_srcs=None):
279    r"""
280    Return list of SRCs found in BMC after filtering expected SRCs.
281    If expected_srcs is None then all SRCs found in system are returned.
282
283    Description of arguments:
284    expected_srcs       List of expected SRCs. E.g. ["BBXXYYYY", "AAXXYYYY"].
285    """
286
287    srcs_found = fetch_all_src()
288    if not expected_srcs:
289        expected_srcs = []
290    print(expected_srcs)
291    return list(set(srcs_found) - set(expected_srcs))
292
293
294def get_bmc_event_log_id_for_pel(pel_id):
295    r"""
296    Return BMC event log ID for the given PEL ID.
297
298    Description of arguments:
299    pel_id       PEL ID. E.g. 0x50000021.
300    """
301
302    pel_data = peltool("-i " + pel_id)
303    print(pel_data)
304    bmc_id_for_pel = pel_data["Private Header"]["BMC Event Log Id"]
305    return bmc_id_for_pel
306