blob: 3c735efa9f81e9c74a8198ecc14eb24755840f6c [file] [log] [blame]
Justin Thalerb8807ce2018-05-25 19:16:20 -05001#!/usr/bin/python3
Justin Thalere412dc22018-01-12 16:28:24 -06002"""
3 Copyright 2017 IBM Corporation
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004
Justin Thalere412dc22018-01-12 16:28:24 -06005 Licensed under the Apache License, Version 2.0 (the "License");
6 you may not use this file except in compliance with the License.
7 You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16"""
Justin Thalerf9aee3e2017-12-05 12:11:09 -060017import argparse
18import requests
19import getpass
20import json
21import os
22import urllib3
23import time, datetime
Justin Thalerf9aee3e2017-12-05 12:11:09 -060024import binascii
25import subprocess
26import platform
27import zipfile
Justin Thaler22b1bb52018-03-15 13:31:32 -050028import tarfile
29import tempfile
30import hashlib
Justin Thalera6b5df72018-07-16 11:10:07 -050031import re
Justin Thaler24d4efa2018-11-08 22:48:10 -060032import uuid
Justin Thalerf9aee3e2017-12-05 12:11:09 -060033
Justin Thalerf9aee3e2017-12-05 12:11:09 -060034def hilight(textToColor, color, bold):
Justin Thalere412dc22018-01-12 16:28:24 -060035 """
36 Used to add highlights to various text for displaying in a terminal
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -060037
Justin Thalere412dc22018-01-12 16:28:24 -060038 @param textToColor: string, the text to be colored
39 @param color: string, used to color the text red or green
40 @param bold: boolean, used to bold the textToColor
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -060041 @return: Buffered reader containing the modified string.
42 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -060043 if(sys.platform.__contains__("win")):
44 if(color == "red"):
45 os.system('color 04')
46 elif(color == "green"):
47 os.system('color 02')
48 else:
49 os.system('color') #reset to default
50 return textToColor
51 else:
52 attr = []
53 if(color == "red"):
54 attr.append('31')
55 elif(color == "green"):
56 attr.append('32')
57 else:
58 attr.append('0')
59 if bold:
60 attr.append('1')
61 else:
62 attr.append('0')
63 return '\x1b[%sm%s\x1b[0m' % (';'.join(attr),textToColor)
64
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -060065
Justin Thalerf9aee3e2017-12-05 12:11:09 -060066def connectionErrHandler(jsonFormat, errorStr, err):
Justin Thalere412dc22018-01-12 16:28:24 -060067 """
68 Error handler various connection errors to bmcs
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -060069
70 @param jsonFormat: boolean, used to output in json format with an error code.
Justin Thalere412dc22018-01-12 16:28:24 -060071 @param errorStr: string, used to color the text red or green
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -060072 @param err: string, the text from the exception
73 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -060074 if errorStr == "Timeout":
75 if not jsonFormat:
76 return("FQPSPIN0000M: Connection timed out. Ensure you have network connectivity to the bmc")
77 else:
Justin Thaler115bca72018-05-25 19:29:08 -050078 conerror = {}
79 conerror['CommonEventID'] = 'FQPSPIN0000M'
80 conerror['sensor']="N/A"
81 conerror['state']="N/A"
82 conerror['additionalDetails'] = "N/A"
83 conerror['Message']="Connection timed out. Ensure you have network connectivity to the BMC"
84 conerror['LengthyDescription'] = "While trying to establish a connection with the specified BMC, the BMC failed to respond in adequate time. Verify the BMC is functioning properly, and the network connectivity to the BMC is stable."
85 conerror['Serviceable']="Yes"
86 conerror['CallHomeCandidate']= "No"
87 conerror['Severity'] = "Critical"
88 conerror['EventType'] = "Communication Failure/Timeout"
89 conerror['VMMigrationFlag'] = "Yes"
90 conerror["AffectedSubsystem"] = "Interconnect (Networking)"
91 conerror["timestamp"] = str(int(time.time()))
92 conerror["UserAction"] = "Verify network connectivity between the two systems and the bmc is functional."
93 eventdict = {}
94 eventdict['event0'] = conerror
95 eventdict['numAlerts'] = '1'
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -060096
Justin Thaler115bca72018-05-25 19:29:08 -050097 errorMessageStr = errorMessageStr = json.dumps(eventdict, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False)
Justin Thalerf9aee3e2017-12-05 12:11:09 -060098 return(errorMessageStr)
99 elif errorStr == "ConnectionError":
100 if not jsonFormat:
101 return("FQPSPIN0001M: " + str(err))
102 else:
Justin Thaler115bca72018-05-25 19:29:08 -0500103 conerror = {}
104 conerror['CommonEventID'] = 'FQPSPIN0001M'
105 conerror['sensor']="N/A"
106 conerror['state']="N/A"
107 conerror['additionalDetails'] = str(err)
108 conerror['Message']="Connection Error. View additional details for more information"
109 conerror['LengthyDescription'] = "A connection error to the specified BMC occurred and additional details are provided. Review these details to resolve the issue."
110 conerror['Serviceable']="Yes"
111 conerror['CallHomeCandidate']= "No"
112 conerror['Severity'] = "Critical"
113 conerror['EventType'] = "Communication Failure/Timeout"
114 conerror['VMMigrationFlag'] = "Yes"
115 conerror["AffectedSubsystem"] = "Interconnect (Networking)"
116 conerror["timestamp"] = str(int(time.time()))
117 conerror["UserAction"] = "Correct the issue highlighted in additional details and try again"
118 eventdict = {}
119 eventdict['event0'] = conerror
120 eventdict['numAlerts'] = '1'
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600121
Justin Thaler115bca72018-05-25 19:29:08 -0500122 errorMessageStr = json.dumps(eventdict, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600123 return(errorMessageStr)
Justin Thaler115bca72018-05-25 19:29:08 -0500124
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600125 else:
126 return("Unknown Error: "+ str(err))
127
Justin Thalere412dc22018-01-12 16:28:24 -0600128
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600129def setColWidth(keylist, numCols, dictForOutput, colNames):
Justin Thalere412dc22018-01-12 16:28:24 -0600130 """
131 Sets the output width of the columns to display
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600132
133 @param keylist: list, list of strings representing the keys for the dictForOutput
Justin Thalere412dc22018-01-12 16:28:24 -0600134 @param numcols: the total number of columns in the final output
135 @param dictForOutput: dictionary, contains the information to print to the screen
136 @param colNames: list, The strings to use for the column headings, in order of the keylist
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600137 @return: A list of the column widths for each respective column.
Justin Thalere412dc22018-01-12 16:28:24 -0600138 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600139 colWidths = []
140 for x in range(0, numCols):
141 colWidths.append(0)
142 for key in dictForOutput:
143 for x in range(0, numCols):
144 colWidths[x] = max(colWidths[x], len(str(dictForOutput[key][keylist[x]])))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600145
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600146 for x in range(0, numCols):
147 colWidths[x] = max(colWidths[x], len(colNames[x])) +2
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600148
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600149 return colWidths
150
151def loadPolicyTable(pathToPolicyTable):
Justin Thalere412dc22018-01-12 16:28:24 -0600152 """
153 loads a json based policy table into a dictionary
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600154
Justin Thalere412dc22018-01-12 16:28:24 -0600155 @param value: boolean, the value to convert
156 @return: A string of "Yes" or "No"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600157 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600158 policyTable = {}
159 if(os.path.exists(pathToPolicyTable)):
160 with open(pathToPolicyTable, 'r') as stream:
161 try:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600162 contents =json.load(stream)
163 policyTable = contents['events']
Justin Thalere412dc22018-01-12 16:28:24 -0600164 except Exception as err:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600165 print(err)
166 return policyTable
167
Justin Thalere412dc22018-01-12 16:28:24 -0600168
169def boolToString(value):
170 """
171 converts a boolean value to a human readable string value
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600172
Justin Thalere412dc22018-01-12 16:28:24 -0600173 @param value: boolean, the value to convert
174 @return: A string of "Yes" or "No"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600175 """
Justin Thalere412dc22018-01-12 16:28:24 -0600176 if(value):
177 return "Yes"
178 else:
179 return "No"
180
Justin Thalera6b5df72018-07-16 11:10:07 -0500181def stringToInt(text):
182 """
183 returns an integer if the string can be converted, otherwise returns the string
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600184
Justin Thalera6b5df72018-07-16 11:10:07 -0500185 @param text: the string to try to convert to an integer
186 """
187 if text.isdigit():
188 return int(text)
189 else:
190 return text
Justin Thalere412dc22018-01-12 16:28:24 -0600191
Justin Thalera6b5df72018-07-16 11:10:07 -0500192def naturalSort(text):
193 """
194 provides a way to naturally sort a list
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600195
Justin Thalera6b5df72018-07-16 11:10:07 -0500196 @param text: the key to convert for sorting
197 @return list containing the broken up string parts by integers and strings
198 """
199 stringPartList = []
200 for c in re.split('(\d+)', text):
201 stringPartList.append(stringToInt(c))
202 return stringPartList
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600203
Justin Thalere412dc22018-01-12 16:28:24 -0600204def tableDisplay(keylist, colNames, output):
205 """
206 Logs into the BMC and creates a session
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600207
Justin Thalere412dc22018-01-12 16:28:24 -0600208 @param keylist: list, keys for the output dictionary, ordered by colNames
209 @param colNames: Names for the Table of the columns
210 @param output: The dictionary of data to display
211 @return: Session object
212 """
213 colWidth = setColWidth(keylist, len(colNames), output, colNames)
214 row = ""
215 outputText = ""
216 for i in range(len(colNames)):
217 if (i != 0): row = row + "| "
218 row = row + colNames[i].ljust(colWidth[i])
219 outputText += row + "\n"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600220
Justin Thalera6b5df72018-07-16 11:10:07 -0500221 output_keys = list(output.keys())
222 output_keys.sort(key=naturalSort)
223 for key in output_keys:
Justin Thalere412dc22018-01-12 16:28:24 -0600224 row = ""
Justin Thaler8fe0c732018-07-24 14:32:35 -0500225 for i in range(len(keylist)):
Justin Thalere412dc22018-01-12 16:28:24 -0600226 if (i != 0): row = row + "| "
227 row = row + output[key][keylist[i]].ljust(colWidth[i])
228 outputText += row + "\n"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600229
Justin Thalere412dc22018-01-12 16:28:24 -0600230 return outputText
231
Justin Thaler22b1bb52018-03-15 13:31:32 -0500232def checkFWactivation(host, args, session):
233 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600234 Checks the software inventory for an image that is being activated.
235
Justin Thaler22b1bb52018-03-15 13:31:32 -0500236 @return: True if an image is being activated, false is no activations are happening
237 """
238 url="https://"+host+"/xyz/openbmc_project/software/enumerate"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600239 httpHeader = {'Content-Type':'application/json'}
Justin Thaler22b1bb52018-03-15 13:31:32 -0500240 try:
241 resp = session.get(url, headers=httpHeader, verify=False, timeout=30)
242 except(requests.exceptions.Timeout):
243 print(connectionErrHandler(args.json, "Timeout", None))
244 return(True)
245 except(requests.exceptions.ConnectionError) as err:
246 print( connectionErrHandler(args.json, "ConnectionError", err))
247 return True
248 fwInfo = json.loads(resp.text)['data']
249 for key in fwInfo:
250 if 'Activation' in fwInfo[key]:
251 if 'Activating' in fwInfo[key]['Activation'] or 'Activating' in fwInfo[key]['RequestedActivation']:
252 return True
253 return False
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600254
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600255def login(host, username, pw,jsonFormat):
Justin Thalere412dc22018-01-12 16:28:24 -0600256 """
257 Logs into the BMC and creates a session
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600258
Justin Thalere412dc22018-01-12 16:28:24 -0600259 @param host: string, the hostname or IP address of the bmc to log into
260 @param username: The user name for the bmc to log into
261 @param pw: The password for the BMC to log into
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600262 @param jsonFormat: boolean, flag that will only allow relevant data from user command to be display. This function becomes silent when set to true.
Justin Thalere412dc22018-01-12 16:28:24 -0600263 @return: Session object
264 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600265 if(jsonFormat==False):
266 print("Attempting login...")
267 httpHeader = {'Content-Type':'application/json'}
268 mysess = requests.session()
269 try:
270 r = mysess.post('https://'+host+'/login', headers=httpHeader, json = {"data": [username, pw]}, verify=False, timeout=30)
271 loginMessage = json.loads(r.text)
272 if (loginMessage['status'] != "ok"):
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600273 print(loginMessage["data"]["description"].encode('utf-8'))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600274 sys.exit(1)
275# if(sys.version_info < (3,0)):
276# urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
277# if sys.version_info >= (3,0):
278# requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)
279 return mysess
280 except(requests.exceptions.Timeout):
Justin Thaler115bca72018-05-25 19:29:08 -0500281 return (connectionErrHandler(jsonFormat, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600282 except(requests.exceptions.ConnectionError) as err:
Justin Thaler115bca72018-05-25 19:29:08 -0500283 return (connectionErrHandler(jsonFormat, "ConnectionError", err))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600284
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600285
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600286def logout(host, username, pw, session, jsonFormat):
Justin Thalere412dc22018-01-12 16:28:24 -0600287 """
288 Logs out of the bmc and terminates the session
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600289
Justin Thalere412dc22018-01-12 16:28:24 -0600290 @param host: string, the hostname or IP address of the bmc to log out of
291 @param username: The user name for the bmc to log out of
292 @param pw: The password for the BMC to log out of
293 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600294 @param jsonFormat: boolean, flag that will only allow relevant data from user command to be display. This function becomes silent when set to true.
295 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600296 httpHeader = {'Content-Type':'application/json'}
Justin Thalere412dc22018-01-12 16:28:24 -0600297 try:
298 r = session.post('https://'+host+'/logout', headers=httpHeader,json = {"data": [username, pw]}, verify=False, timeout=10)
299 except(requests.exceptions.Timeout):
300 print(connectionErrHandler(jsonFormat, "Timeout", None))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600301
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600302 if(jsonFormat==False):
303 if('"message": "200 OK"' in r.text):
304 print('User ' +username + ' has been logged out')
305
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600306
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600307def fru(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -0600308 """
309 prints out the system inventory. deprecated see fruPrint and fruList
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600310
Justin Thalere412dc22018-01-12 16:28:24 -0600311 @param host: string, the hostname or IP address of the bmc
312 @param args: contains additional arguments used by the fru sub command
313 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600314 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
315 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600316 #url="https://"+host+"/org/openbmc/inventory/system/chassis/enumerate"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600317
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600318 #print(url)
319 #res = session.get(url, headers=httpHeader, verify=False)
320 #print(res.text)
321 #sample = res.text
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600322
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600323 #inv_list = json.loads(sample)["data"]
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600324
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600325 url="https://"+host+"/xyz/openbmc_project/inventory/enumerate"
326 httpHeader = {'Content-Type':'application/json'}
Justin Thalere412dc22018-01-12 16:28:24 -0600327 try:
328 res = session.get(url, headers=httpHeader, verify=False, timeout=40)
329 except(requests.exceptions.Timeout):
330 return(connectionErrHandler(args.json, "Timeout", None))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600331
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600332 sample = res.text
333# inv_list.update(json.loads(sample)["data"])
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600334#
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600335# #determine column width's
336# colNames = ["FRU Name", "FRU Type", "Has Fault", "Is FRU", "Present", "Version"]
337# colWidths = setColWidth(["FRU Name", "fru_type", "fault", "is_fru", "present", "version"], 6, inv_list, colNames)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600338#
339# print("FRU Name".ljust(colWidths[0])+ "FRU Type".ljust(colWidths[1]) + "Has Fault".ljust(colWidths[2]) + "Is FRU".ljust(colWidths[3])+
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600340# "Present".ljust(colWidths[4]) + "Version".ljust(colWidths[5]))
341# format the output
342# for key in sorted(inv_list.keys()):
343# keyParts = key.split("/")
344# isFRU = "True" if (inv_list[key]["is_fru"]==1) else "False"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600345#
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600346# fruEntry = (keyParts[len(keyParts) - 1].ljust(colWidths[0]) + inv_list[key]["fru_type"].ljust(colWidths[1])+
347# inv_list[key]["fault"].ljust(colWidths[2])+isFRU.ljust(colWidths[3])+
348# inv_list[key]["present"].ljust(colWidths[4])+ inv_list[key]["version"].ljust(colWidths[5]))
349# if(isTTY):
350# if(inv_list[key]["is_fru"] == 1):
351# color = "green"
352# bold = True
353# else:
354# color='black'
355# bold = False
356# fruEntry = hilight(fruEntry, color, bold)
357# print (fruEntry)
358 return sample
Justin Thalere412dc22018-01-12 16:28:24 -0600359
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600360def fruPrint(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -0600361 """
362 prints out all inventory
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600363
Justin Thalere412dc22018-01-12 16:28:24 -0600364 @param host: string, the hostname or IP address of the bmc
365 @param args: contains additional arguments used by the fru sub command
366 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600367 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
368 @return returns the total fru list.
369 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600370 url="https://"+host+"/xyz/openbmc_project/inventory/enumerate"
371 httpHeader = {'Content-Type':'application/json'}
Justin Thalere412dc22018-01-12 16:28:24 -0600372 try:
373 res = session.get(url, headers=httpHeader, verify=False, timeout=40)
374 except(requests.exceptions.Timeout):
375 return(connectionErrHandler(args.json, "Timeout", None))
376
377
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600378# print(res.text)
379 frulist = res.text
380 url="https://"+host+"/xyz/openbmc_project/software/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600381 try:
382 res = session.get(url, headers=httpHeader, verify=False, timeout=40)
383 except(requests.exceptions.Timeout):
384 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600385# print(res.text)
386 frulist = frulist +"\n" + res.text
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600387
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600388 return frulist
389
Justin Thalere412dc22018-01-12 16:28:24 -0600390
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600391def fruList(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -0600392 """
393 prints out all inventory or only a specific specified item
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600394
Justin Thalere412dc22018-01-12 16:28:24 -0600395 @param host: string, the hostname or IP address of the bmc
396 @param args: contains additional arguments used by the fru sub command
397 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600398 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
399 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600400 if(args.items==True):
401 return fruPrint(host, args, session)
402 else:
Justin Thalere412dc22018-01-12 16:28:24 -0600403 return fruPrint(host, args, session)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600404
405
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600406
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600407def fruStatus(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -0600408 """
409 prints out the status of all FRUs
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600410
Justin Thalere412dc22018-01-12 16:28:24 -0600411 @param host: string, the hostname or IP address of the bmc
412 @param args: contains additional arguments used by the fru sub command
413 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600414 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
415 """
Justin Thalere412dc22018-01-12 16:28:24 -0600416 url="https://"+host+"/xyz/openbmc_project/inventory/enumerate"
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600417 httpHeader = {'Content-Type':'application/json'}
Justin Thalere412dc22018-01-12 16:28:24 -0600418 try:
419 res = session.get(url, headers=httpHeader, verify=False)
420 except(requests.exceptions.Timeout):
421 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600422# print(res.text)
Justin Thalere412dc22018-01-12 16:28:24 -0600423 frulist = json.loads(res.text)['data']
424 frus = {}
425 for key in frulist:
426 component = frulist[key]
427 isFru = False
428 present = False
429 func = False
430 hasSels = False
431 keyPieces = key.split('/')
432 fruName = keyPieces[-1]
433 if 'core' in fruName: #associate cores to cpus
434 fruName = keyPieces[-2] + '-' + keyPieces[-1]
435 if 'Functional' in component:
436 if('Present' in component):
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600437
Justin Thalere412dc22018-01-12 16:28:24 -0600438 if 'FieldReplaceable' in component:
439 if component['FieldReplaceable'] == 1:
440 isFru = True
441 if "fan" in fruName:
442 isFru = True;
443 if component['Present'] == 1:
444 present = True
445 if component['Functional'] == 1:
446 func = True
447 if ((key + "/fault") in frulist):
448 hasSels = True;
449 if args.verbose:
450 if hasSels:
451 loglist = []
452 faults = frulist[key+"/fault"]['endpoints']
453 for item in faults:
454 loglist.append(item.split('/')[-1])
455 frus[fruName] = {"compName": fruName, "Functional": boolToString(func), "Present":boolToString(present), "IsFru": boolToString(isFru), "selList": ', '.join(loglist).strip() }
456 else:
457 frus[fruName] = {"compName": fruName, "Functional": boolToString(func), "Present":boolToString(present), "IsFru": boolToString(isFru), "selList": "None" }
458 else:
459 frus[fruName] = {"compName": fruName, "Functional": boolToString(func), "Present":boolToString(present), "IsFru": boolToString(isFru), "hasSEL": boolToString(hasSels) }
Justin Thalerfb9c81c2018-07-16 11:14:37 -0500460 elif "power_supply" in fruName or "powersupply" in fruName:
Justin Thalere412dc22018-01-12 16:28:24 -0600461 if component['Present'] ==1:
462 present = True
463 isFru = True
464 if ((key + "/fault") in frulist):
465 hasSels = True;
466 if args.verbose:
467 if hasSels:
468 loglist = []
469 faults = frulist[key+"/fault"]['endpoints']
Obihörnchenff8035f2018-12-05 21:07:37 +0100470 for item in faults:
471 loglist.append(item.split('/')[-1])
Justin Thalere412dc22018-01-12 16:28:24 -0600472 frus[fruName] = {"compName": fruName, "Functional": "No", "Present":boolToString(present), "IsFru": boolToString(isFru), "selList": ', '.join(loglist).strip() }
473 else:
474 frus[fruName] = {"compName": fruName, "Functional": "Yes", "Present":boolToString(present), "IsFru": boolToString(isFru), "selList": "None" }
475 else:
476 frus[fruName] = {"compName": fruName, "Functional": boolToString(not hasSels), "Present":boolToString(present), "IsFru": boolToString(isFru), "hasSEL": boolToString(hasSels) }
477 if not args.json:
478 if not args.verbose:
479 colNames = ["Component", "Is a FRU", "Present", "Functional", "Has Logs"]
480 keylist = ["compName", "IsFru", "Present", "Functional", "hasSEL"]
481 else:
482 colNames = ["Component", "Is a FRU", "Present", "Functional", "Assoc. Log Number(s)"]
483 keylist = ["compName", "IsFru", "Present", "Functional", "selList"]
484 return tableDisplay(keylist, colNames, frus)
485 else:
486 return str(json.dumps(frus, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600487
Justin Thalere412dc22018-01-12 16:28:24 -0600488def sensor(host, args, session):
489 """
490 prints out all sensors
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600491
Justin Thalere412dc22018-01-12 16:28:24 -0600492 @param host: string, the hostname or IP address of the bmc
493 @param args: contains additional arguments used by the sensor sub command
494 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600495 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
496 """
Justin Thalere412dc22018-01-12 16:28:24 -0600497 httpHeader = {'Content-Type':'application/json'}
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600498 url="https://"+host+"/xyz/openbmc_project/sensors/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600499 try:
500 res = session.get(url, headers=httpHeader, verify=False, timeout=30)
501 except(requests.exceptions.Timeout):
502 return(connectionErrHandler(args.json, "Timeout", None))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600503
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600504 #Get OCC status
505 url="https://"+host+"/org/open_power/control/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600506 try:
507 occres = session.get(url, headers=httpHeader, verify=False, timeout=30)
508 except(requests.exceptions.Timeout):
509 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600510 if not args.json:
511 colNames = ['sensor', 'type', 'units', 'value', 'target']
512 sensors = json.loads(res.text)["data"]
513 output = {}
514 for key in sensors:
515 senDict = {}
516 keyparts = key.split("/")
517 senDict['sensorName'] = keyparts[-1]
518 senDict['type'] = keyparts[-2]
Justin Thalere412dc22018-01-12 16:28:24 -0600519 try:
520 senDict['units'] = sensors[key]['Unit'].split('.')[-1]
521 except KeyError:
Justin Thaler22b1bb52018-03-15 13:31:32 -0500522 senDict['units'] = "N/A"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600523 if('Scale' in sensors[key]):
524 scale = 10 ** sensors[key]['Scale']
525 else:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600526 scale = 1
Justin Thaler22b1bb52018-03-15 13:31:32 -0500527 try:
528 senDict['value'] = str(sensors[key]['Value'] * scale)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600529 except KeyError:
Justin Thaler22b1bb52018-03-15 13:31:32 -0500530 if 'value' in sensors[key]:
531 senDict['value'] = sensors[key]['value']
532 else:
533 senDict['value'] = "N/A"
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600534 if 'Target' in sensors[key]:
535 senDict['target'] = str(sensors[key]['Target'])
536 else:
537 senDict['target'] = 'N/A'
538 output[senDict['sensorName']] = senDict
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600539
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600540 occstatus = json.loads(occres.text)["data"]
541 if '/org/open_power/control/occ0' in occstatus:
542 occ0 = occstatus["/org/open_power/control/occ0"]['OccActive']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600543 if occ0 == 1:
544 occ0 = 'Active'
545 else:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600546 occ0 = 'Inactive'
547 output['OCC0'] = {'sensorName':'OCC0', 'type': 'Discrete', 'units': 'N/A', 'value': occ0, 'target': 'Active'}
548 occ1 = occstatus["/org/open_power/control/occ1"]['OccActive']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600549 if occ1 == 1:
550 occ1 = 'Active'
551 else:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600552 occ1 = 'Inactive'
553 output['OCC1'] = {'sensorName':'OCC1', 'type': 'Discrete', 'units': 'N/A', 'value': occ0, 'target': 'Active'}
554 else:
555 output['OCC0'] = {'sensorName':'OCC0', 'type': 'Discrete', 'units': 'N/A', 'value': 'Inactive', 'target': 'Inactive'}
556 output['OCC1'] = {'sensorName':'OCC1', 'type': 'Discrete', 'units': 'N/A', 'value': 'Inactive', 'target': 'Inactive'}
557 keylist = ['sensorName', 'type', 'units', 'value', 'target']
Justin Thalere412dc22018-01-12 16:28:24 -0600558
559 return tableDisplay(keylist, colNames, output)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600560 else:
561 return res.text + occres.text
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600562
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600563def sel(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -0600564 """
565 prints out the bmc alerts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600566
Justin Thalere412dc22018-01-12 16:28:24 -0600567 @param host: string, the hostname or IP address of the bmc
568 @param args: contains additional arguments used by the sel sub command
569 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600570 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
571 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600572
573 url="https://"+host+"/xyz/openbmc_project/logging/entry/enumerate"
574 httpHeader = {'Content-Type':'application/json'}
Justin Thalere412dc22018-01-12 16:28:24 -0600575 try:
576 res = session.get(url, headers=httpHeader, verify=False, timeout=60)
577 except(requests.exceptions.Timeout):
578 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600579 return res.text
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600580
581
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600582def parseESEL(args, eselRAW):
Justin Thalere412dc22018-01-12 16:28:24 -0600583 """
584 parses the esel data and gets predetermined search terms
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600585
Justin Thalere412dc22018-01-12 16:28:24 -0600586 @param eselRAW: string, the raw esel string from the bmc
587 @return: A dictionary containing the quick snapshot data unless args.fullEsel is listed then a full PEL log is returned
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600588 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600589 eselParts = {}
590 esel_bin = binascii.unhexlify(''.join(eselRAW.split()[16:]))
591 #search terms contains the search term as the key and the return dictionary key as it's value
592 searchTerms = { 'Signature Description':'signatureDescription', 'devdesc':'devdesc',
Justin Thaler22b1bb52018-03-15 13:31:32 -0500593 'Callout type': 'calloutType', 'Procedure':'procedure', 'Sensor Type': 'sensorType'}
Justin Thaler24d4efa2018-11-08 22:48:10 -0600594 uniqueID = str(uuid.uuid4())
595 eselBinPath = tempfile.gettempdir() + os.sep + uniqueID + 'esel.bin'
Justin Thalercf1deae2018-05-25 19:35:21 -0500596 with open(eselBinPath, 'wb') as f:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600597 f.write(esel_bin)
598 errlPath = ""
599 #use the right errl file for the machine architecture
600 arch = platform.machine()
601 if(arch =='x86_64' or arch =='AMD64'):
602 if os.path.exists('/opt/ibm/ras/bin/x86_64/errl'):
603 errlPath = '/opt/ibm/ras/bin/x86_64/errl'
604 elif os.path.exists('errl/x86_64/errl'):
605 errlPath = 'errl/x86_64/errl'
606 else:
607 errlPath = 'x86_64/errl'
608 elif (platform.machine()=='ppc64le'):
609 if os.path.exists('/opt/ibm/ras/bin/ppc64le/errl'):
610 errlPath = '/opt/ibm/ras/bin/ppc64le/errl'
611 elif os.path.exists('errl/ppc64le/errl'):
612 errlPath = 'errl/ppc64le/errl'
613 else:
614 errlPath = 'ppc64le/errl'
615 else:
616 print("machine architecture not supported for parsing eSELs")
617 return eselParts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600618
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600619 if(os.path.exists(errlPath)):
Justin Thalercf1deae2018-05-25 19:35:21 -0500620 output= subprocess.check_output([errlPath, '-d', '--file='+eselBinPath]).decode('utf-8')
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600621# output = proc.communicate()[0]
622 lines = output.split('\n')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600623
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600624 if(hasattr(args, 'fullEsel')):
625 return output
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600626
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600627 for i in range(0, len(lines)):
628 lineParts = lines[i].split(':')
629 if(len(lineParts)>1): #ignore multi lines, output formatting lines, and other information
630 for term in searchTerms:
631 if(term in lineParts[0]):
632 temp = lines[i][lines[i].find(':')+1:].strip()[:-1].strip()
633 if lines[i+1].find(':') != -1:
634 if (len(lines[i+1].split(':')[0][1:].strip())==0):
635 while(len(lines[i][:lines[i].find(':')].strip())>2):
Justin Thaler43030422018-11-08 22:50:21 -0600636 #has multiple lines, process and update line counter
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600637 if((i+1) <= len(lines)):
638 i+=1
639 else:
640 i=i-1
641 break
Justin Thaler43030422018-11-08 22:50:21 -0600642 #Append the content from the next line removing the pretty display characters
643 #Finds the first colon then starts 2 characters after, then removes all whitespace
644 temp = temp + lines[i][lines[i].find(':')+2:].strip()[:-1].strip()[:-1].strip()
Justin Thaler22b1bb52018-03-15 13:31:32 -0500645 if(searchTerms[term] in eselParts):
646 eselParts[searchTerms[term]] = eselParts[searchTerms[term]] + ", " + temp
647 else:
648 eselParts[searchTerms[term]] = temp
Justin Thalercf1deae2018-05-25 19:35:21 -0500649 os.remove(eselBinPath)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600650 else:
651 print("errl file cannot be found")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600652
653 return eselParts
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600654
Justin Thalere412dc22018-01-12 16:28:24 -0600655
Matt Spinler02d0dff2018-08-29 13:19:25 -0500656def getESELSeverity(esel):
657 """
658 Finds the severity type in an eSEL from the User Header section.
659 @param esel - the eSEL data
660 @return severity - e.g. 'Critical'
661 """
662
663 # everything but 1 and 2 are Critical
664 # '1': 'recovered',
665 # '2': 'predictive',
666 # '4': 'unrecoverable',
667 # '5': 'critical',
668 # '6': 'diagnostic',
669 # '7': 'symptom'
670 severities = {
671 '1': 'Informational',
672 '2': 'Warning'
673 }
674
675 try:
676 headerPosition = esel.index('55 48') # 'UH'
677 # The severity is the last byte in the 8 byte section (a byte is ' bb')
678 severity = esel[headerPosition:headerPosition+32].split(' ')[-1]
679 type = severity[0]
680 except ValueError:
681 print("Could not find severity value in UH section in eSEL")
682 type = 'x';
683
684 return severities.get(type, 'Critical')
685
686
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600687def sortSELs(events):
Justin Thalere412dc22018-01-12 16:28:24 -0600688 """
689 sorts the sels by timestamp, then log entry number
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600690
Justin Thalere412dc22018-01-12 16:28:24 -0600691 @param events: Dictionary containing events
692 @return: list containing a list of the ordered log entries, and dictionary of keys
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600693 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600694 logNumList = []
695 timestampList = []
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600696 eventKeyDict = {}
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600697 eventsWithTimestamp = {}
698 logNum2events = {}
699 for key in events:
700 if key == 'numAlerts': continue
701 if 'callout' in key: continue
702 timestamp = (events[key]['timestamp'])
703 if timestamp not in timestampList:
704 eventsWithTimestamp[timestamp] = [events[key]['logNum']]
705 else:
706 eventsWithTimestamp[timestamp].append(events[key]['logNum'])
707 #map logNumbers to the event dictionary keys
708 eventKeyDict[str(events[key]['logNum'])] = key
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600709
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600710 timestampList = list(eventsWithTimestamp.keys())
711 timestampList.sort()
712 for ts in timestampList:
713 if len(eventsWithTimestamp[ts]) > 1:
714 tmplist = eventsWithTimestamp[ts]
715 tmplist.sort()
716 logNumList = logNumList + tmplist
717 else:
718 logNumList = logNumList + eventsWithTimestamp[ts]
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600719
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600720 return [logNumList, eventKeyDict]
721
Justin Thalere412dc22018-01-12 16:28:24 -0600722
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600723def parseAlerts(policyTable, selEntries, args):
Justin Thalere412dc22018-01-12 16:28:24 -0600724 """
725 parses alerts in the IBM CER format, using an IBM policy Table
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600726
Justin Thalere412dc22018-01-12 16:28:24 -0600727 @param policyTable: dictionary, the policy table entries
728 @param selEntries: dictionary, the alerts retrieved from the bmc
729 @return: A dictionary of the parsed entries, in chronological order
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600730 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600731 eventDict = {}
732 eventNum =""
733 count = 0
734 esel = ""
735 eselParts = {}
736 i2cdevice= ""
Matt Spinler02d0dff2018-08-29 13:19:25 -0500737 eselSeverity = None
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600738
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600739 'prepare and sort the event entries'
740 for key in selEntries:
741 if 'callout' not in key:
742 selEntries[key]['logNum'] = key.split('/')[-1]
743 selEntries[key]['timestamp'] = selEntries[key]['Timestamp']
744 sortedEntries = sortSELs(selEntries)
745 logNumList = sortedEntries[0]
746 eventKeyDict = sortedEntries[1]
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600747
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600748 for logNum in logNumList:
749 key = eventKeyDict[logNum]
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600750 hasEsel=False
751 i2creadFail = False
752 if 'callout' in key:
753 continue
754 else:
755 messageID = str(selEntries[key]['Message'])
756 addDataPiece = selEntries[key]['AdditionalData']
757 calloutIndex = 0
758 calloutFound = False
759 for i in range(len(addDataPiece)):
760 if("CALLOUT_INVENTORY_PATH" in addDataPiece[i]):
761 calloutIndex = i
762 calloutFound = True
763 fruCallout = str(addDataPiece[calloutIndex]).split('=')[1]
764 if("CALLOUT_DEVICE_PATH" in addDataPiece[i]):
765 i2creadFail = True
Matt Spinlerd178a472018-08-31 09:48:52 -0500766
767 fruCallout = str(addDataPiece[calloutIndex]).split('=')[1]
768
769 # Fall back to "I2C"/"FSI" if dev path isn't in policy table
770 if (messageID + '||' + fruCallout) not in policyTable:
771 i2cdevice = str(addDataPiece[i]).strip().split('=')[1]
772 i2cdevice = '/'.join(i2cdevice.split('/')[-4:])
773 if 'fsi' in str(addDataPiece[calloutIndex]).split('=')[1]:
774 fruCallout = 'FSI'
775 else:
776 fruCallout = 'I2C'
Justin Thalere34c43a2018-05-25 19:37:55 -0500777 calloutFound = True
778 if("CALLOUT_GPIO_NUM" in addDataPiece[i]):
779 if not calloutFound:
780 fruCallout = 'GPIO'
781 calloutFound = True
782 if("CALLOUT_IIC_BUS" in addDataPiece[i]):
783 if not calloutFound:
784 fruCallout = "I2C"
785 calloutFound = True
786 if("CALLOUT_IPMI_SENSOR_NUM" in addDataPiece[i]):
787 if not calloutFound:
788 fruCallout = "IPMI"
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600789 calloutFound = True
790 if("ESEL" in addDataPiece[i]):
791 esel = str(addDataPiece[i]).strip().split('=')[1]
Matt Spinler02d0dff2018-08-29 13:19:25 -0500792 eselSeverity = getESELSeverity(esel)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600793 if args.devdebug:
794 eselParts = parseESEL(args, esel)
795 hasEsel=True
796 if("GPU" in addDataPiece[i]):
797 fruCallout = '/xyz/openbmc_project/inventory/system/chassis/motherboard/gpu' + str(addDataPiece[i]).strip()[-1]
798 calloutFound = True
799 if("PROCEDURE" in addDataPiece[i]):
800 fruCallout = str(hex(int(str(addDataPiece[i]).split('=')[1])))[2:]
801 calloutFound = True
Justin Thalere412dc22018-01-12 16:28:24 -0600802 if("RAIL_NAME" in addDataPiece[i]):
803 calloutFound=True
804 fruCallout = str(addDataPiece[i]).split('=')[1].strip()
805 if("INPUT_NAME" in addDataPiece[i]):
806 calloutFound=True
807 fruCallout = str(addDataPiece[i]).split('=')[1].strip()
808 if("SENSOR_TYPE" in addDataPiece[i]):
809 calloutFound=True
810 fruCallout = str(addDataPiece[i]).split('=')[1].strip()
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600811
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600812 if(calloutFound):
Justin Thaler22b1bb52018-03-15 13:31:32 -0500813 if fruCallout != "":
814 policyKey = messageID +"||" + fruCallout
Matt Spinler02d0dff2018-08-29 13:19:25 -0500815
816 # Also use the severity for hostboot errors
817 if eselSeverity and messageID == 'org.open_power.Host.Error.Event':
818 policyKey += '||' + eselSeverity
819
820 # if not in the table, fall back to the original key
821 if policyKey not in policyTable:
822 policyKey = policyKey.replace('||'+eselSeverity, '')
823
Justin Thalere34c43a2018-05-25 19:37:55 -0500824 if policyKey not in policyTable:
825 policyKey = messageID
Justin Thaler22b1bb52018-03-15 13:31:32 -0500826 else:
827 policyKey = messageID
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600828 else:
829 policyKey = messageID
830 event = {}
831 eventNum = str(count)
832 if policyKey in policyTable:
833 for pkey in policyTable[policyKey]:
834 if(type(policyTable[policyKey][pkey])== bool):
835 event[pkey] = boolToString(policyTable[policyKey][pkey])
836 else:
837 if (i2creadFail and pkey == 'Message'):
838 event[pkey] = policyTable[policyKey][pkey] + ' ' +i2cdevice
839 else:
840 event[pkey] = policyTable[policyKey][pkey]
841 event['timestamp'] = selEntries[key]['Timestamp']
842 event['resolved'] = bool(selEntries[key]['Resolved'])
843 if(hasEsel):
844 if args.devdebug:
845 event['eselParts'] = eselParts
846 event['raweSEL'] = esel
847 event['logNum'] = key.split('/')[-1]
848 eventDict['event' + eventNum] = event
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600849
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600850 else:
851 severity = str(selEntries[key]['Severity']).split('.')[-1]
852 if severity == 'Error':
853 severity = 'Critical'
854 eventDict['event'+eventNum] = {}
855 eventDict['event' + eventNum]['error'] = "error: Not found in policy table: " + policyKey
856 eventDict['event' + eventNum]['timestamp'] = selEntries[key]['Timestamp']
857 eventDict['event' + eventNum]['Severity'] = severity
858 if(hasEsel):
859 if args.devdebug:
860 eventDict['event' +eventNum]['eselParts'] = eselParts
861 eventDict['event' +eventNum]['raweSEL'] = esel
862 eventDict['event' +eventNum]['logNum'] = key.split('/')[-1]
863 eventDict['event' +eventNum]['resolved'] = bool(selEntries[key]['Resolved'])
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600864 count += 1
865 return eventDict
866
867
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600868def selDisplay(events, args):
Justin Thalere412dc22018-01-12 16:28:24 -0600869 """
870 displays alerts in human readable format
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600871
Justin Thalere412dc22018-01-12 16:28:24 -0600872 @param events: Dictionary containing events
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600873 @return:
874 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600875 activeAlerts = []
876 historyAlerts = []
877 sortedEntries = sortSELs(events)
878 logNumList = sortedEntries[0]
879 eventKeyDict = sortedEntries[1]
880 keylist = ['Entry', 'ID', 'Timestamp', 'Serviceable', 'Severity','Message']
881 if(args.devdebug):
882 colNames = ['Entry', 'ID', 'Timestamp', 'Serviceable', 'Severity','Message', 'eSEL contents']
883 keylist.append('eSEL')
884 else:
885 colNames = ['Entry', 'ID', 'Timestamp', 'Serviceable', 'Severity', 'Message']
886 for log in logNumList:
887 selDict = {}
888 alert = events[eventKeyDict[str(log)]]
889 if('error' in alert):
890 selDict['Entry'] = alert['logNum']
891 selDict['ID'] = 'Unknown'
892 selDict['Timestamp'] = datetime.datetime.fromtimestamp(int(alert['timestamp']/1000)).strftime("%Y-%m-%d %H:%M:%S")
893 msg = alert['error']
894 polMsg = msg.split("policy table:")[0]
895 msg = msg.split("policy table:")[1]
896 msgPieces = msg.split("||")
897 err = msgPieces[0]
898 if(err.find("org.open_power.")!=-1):
899 err = err.split("org.open_power.")[1]
900 elif(err.find("xyz.openbmc_project.")!=-1):
901 err = err.split("xyz.openbmc_project.")[1]
902 else:
903 err = msgPieces[0]
904 callout = ""
905 if len(msgPieces) >1:
906 callout = msgPieces[1]
907 if(callout.find("/org/open_power/")!=-1):
908 callout = callout.split("/org/open_power/")[1]
909 elif(callout.find("/xyz/openbmc_project/")!=-1):
910 callout = callout.split("/xyz/openbmc_project/")[1]
911 else:
912 callout = msgPieces[1]
913 selDict['Message'] = polMsg +"policy table: "+ err + "||" + callout
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600914 selDict['Serviceable'] = 'Unknown'
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600915 selDict['Severity'] = alert['Severity']
916 else:
917 selDict['Entry'] = alert['logNum']
918 selDict['ID'] = alert['CommonEventID']
919 selDict['Timestamp'] = datetime.datetime.fromtimestamp(int(alert['timestamp']/1000)).strftime("%Y-%m-%d %H:%M:%S")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600920 selDict['Message'] = alert['Message']
921 selDict['Serviceable'] = alert['Serviceable']
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600922 selDict['Severity'] = alert['Severity']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600923
924
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600925 eselOrder = ['refCode','signatureDescription', 'eselType', 'devdesc', 'calloutType', 'procedure']
926 if ('eselParts' in alert and args.devdebug):
927 eselOutput = ""
928 for item in eselOrder:
929 if item in alert['eselParts']:
930 eselOutput = eselOutput + item + ": " + alert['eselParts'][item] + " | "
931 selDict['eSEL'] = eselOutput
932 else:
933 if args.devdebug:
934 selDict['eSEL'] = "None"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600935
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600936 if not alert['resolved']:
937 activeAlerts.append(selDict)
938 else:
939 historyAlerts.append(selDict)
940 mergedOutput = activeAlerts + historyAlerts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600941 colWidth = setColWidth(keylist, len(colNames), dict(enumerate(mergedOutput)), colNames)
942
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600943 output = ""
944 if(len(activeAlerts)>0):
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600945 row = ""
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600946 output +="----Active Alerts----\n"
947 for i in range(0, len(colNames)):
948 if i!=0: row =row + "| "
949 row = row + colNames[i].ljust(colWidth[i])
950 output += row + "\n"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600951
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600952 for i in range(0,len(activeAlerts)):
953 row = ""
954 for j in range(len(activeAlerts[i])):
955 if (j != 0): row = row + "| "
956 row = row + activeAlerts[i][keylist[j]].ljust(colWidth[j])
957 output += row + "\n"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600958
959 if(len(historyAlerts)>0):
960 row = ""
961 output+= "----Historical Alerts----\n"
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600962 for i in range(len(colNames)):
963 if i!=0: row =row + "| "
964 row = row + colNames[i].ljust(colWidth[i])
965 output += row + "\n"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600966
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600967 for i in range(0, len(historyAlerts)):
968 row = ""
969 for j in range(len(historyAlerts[i])):
970 if (j != 0): row = row + "| "
971 row = row + historyAlerts[i][keylist[j]].ljust(colWidth[j])
972 output += row + "\n"
973# print(events[eventKeyDict[str(log)]])
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600974 return output
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600975
Justin Thalere412dc22018-01-12 16:28:24 -0600976
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600977def selPrint(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -0600978 """
979 prints out all bmc alerts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600980
Justin Thalere412dc22018-01-12 16:28:24 -0600981 @param host: string, the hostname or IP address of the bmc
982 @param args: contains additional arguments used by the fru sub command
983 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600984 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
985 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600986 if(args.policyTableLoc is None):
987 if os.path.exists('policyTable.json'):
988 ptableLoc = "policyTable.json"
989 elif os.path.exists('/opt/ibm/ras/lib/policyTable.json'):
990 ptableLoc = '/opt/ibm/ras/lib/policyTable.json'
991 else:
992 ptableLoc = 'lib/policyTable.json'
993 else:
994 ptableLoc = args.policyTableLoc
995 policyTable = loadPolicyTable(ptableLoc)
996 rawselEntries = ""
997 if(hasattr(args, 'fileloc') and args.fileloc is not None):
998 if os.path.exists(args.fileloc):
999 with open(args.fileloc, 'r') as selFile:
1000 selLines = selFile.readlines()
1001 rawselEntries = ''.join(selLines)
1002 else:
1003 print("Error: File not found")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001004 sys.exit(1)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001005 else:
1006 rawselEntries = sel(host, args, session)
1007 loadFailed = False
1008 try:
1009 selEntries = json.loads(rawselEntries)
1010 except ValueError:
1011 loadFailed = True
1012 if loadFailed:
1013 cleanSels = json.dumps(rawselEntries).replace('\\n', '')
1014 #need to load json twice as original content was string escaped a second time
1015 selEntries = json.loads(json.loads(cleanSels))
1016 selEntries = selEntries['data']
Justin Thalere412dc22018-01-12 16:28:24 -06001017
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001018 if 'description' in selEntries:
1019 if(args.json):
1020 return("{\n\t\"numAlerts\": 0\n}")
1021 else:
1022 return("No log entries found")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001023
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001024 else:
1025 if(len(policyTable)>0):
1026 events = parseAlerts(policyTable, selEntries, args)
1027 if(args.json):
1028 events["numAlerts"] = len(events)
1029 retValue = str(json.dumps(events, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False))
1030 return retValue
1031 elif(hasattr(args, 'fullSel')):
1032 return events
1033 else:
1034 #get log numbers to order event entries sequentially
1035 return selDisplay(events, args)
1036 else:
1037 if(args.json):
1038 return selEntries
1039 else:
1040 print("error: Policy Table not found.")
1041 return selEntries
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001042
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001043def selList(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001044 """
1045 prints out all all bmc alerts, or only prints out the specified alerts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001046
Justin Thalere412dc22018-01-12 16:28:24 -06001047 @param host: string, the hostname or IP address of the bmc
1048 @param args: contains additional arguments used by the fru sub command
1049 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001050 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1051 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001052 return(sel(host, args, session))
1053
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001054
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001055def selClear(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001056 """
1057 clears all alerts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001058
Justin Thalere412dc22018-01-12 16:28:24 -06001059 @param host: string, the hostname or IP address of the bmc
1060 @param args: contains additional arguments used by the fru sub command
1061 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001062 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1063 """
Matt Spinler47b13e92019-01-04 14:58:53 -06001064 url="https://"+host+"/xyz/openbmc_project/logging/action/DeleteAll"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001065 httpHeader = {'Content-Type':'application/json'}
1066 data = "{\"data\": [] }"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001067
Justin Thalere412dc22018-01-12 16:28:24 -06001068 try:
1069 res = session.post(url, headers=httpHeader, data=data, verify=False, timeout=30)
1070 except(requests.exceptions.Timeout):
1071 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001072 if res.status_code == 200:
1073 return "The Alert Log has been cleared. Please allow a few minutes for the action to complete."
1074 else:
1075 print("Unable to clear the logs, trying to clear 1 at a time")
1076 sels = json.loads(sel(host, args, session))['data']
1077 for key in sels:
1078 if 'callout' not in key:
1079 logNum = key.split('/')[-1]
1080 url = "https://"+ host+ "/xyz/openbmc_project/logging/entry/"+logNum+"/action/Delete"
1081 try:
1082 session.post(url, headers=httpHeader, data=data, verify=False, timeout=30)
1083 except(requests.exceptions.Timeout):
1084 return connectionErrHandler(args.json, "Timeout", None)
1085 sys.exit(1)
1086 except(requests.exceptions.ConnectionError) as err:
1087 return connectionErrHandler(args.json, "ConnectionError", err)
1088 sys.exit(1)
1089 return ('Sel clearing complete')
1090
1091def selSetResolved(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001092 """
1093 sets a sel entry to resolved
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001094
Justin Thalere412dc22018-01-12 16:28:24 -06001095 @param host: string, the hostname or IP address of the bmc
1096 @param args: contains additional arguments used by the fru sub command
1097 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001098 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1099 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001100 url="https://"+host+"/xyz/openbmc_project/logging/entry/" + str(args.selNum) + "/attr/Resolved"
1101 httpHeader = {'Content-Type':'application/json'}
1102 data = "{\"data\": 1 }"
Justin Thalere412dc22018-01-12 16:28:24 -06001103 try:
1104 res = session.put(url, headers=httpHeader, data=data, verify=False, timeout=30)
1105 except(requests.exceptions.Timeout):
1106 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001107 if res.status_code == 200:
1108 return "Sel entry "+ str(args.selNum) +" is now set to resolved"
1109 else:
1110 return "Unable to set the alert to resolved"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001111
Justin Thalere412dc22018-01-12 16:28:24 -06001112def selResolveAll(host, args, session):
1113 """
1114 sets a sel entry to resolved
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001115
Justin Thalere412dc22018-01-12 16:28:24 -06001116 @param host: string, the hostname or IP address of the bmc
1117 @param args: contains additional arguments used by the fru sub command
1118 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001119 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1120 """
Justin Thalere412dc22018-01-12 16:28:24 -06001121 rawselEntries = sel(host, args, session)
1122 loadFailed = False
1123 try:
1124 selEntries = json.loads(rawselEntries)
1125 except ValueError:
1126 loadFailed = True
1127 if loadFailed:
1128 cleanSels = json.dumps(rawselEntries).replace('\\n', '')
1129 #need to load json twice as original content was string escaped a second time
1130 selEntries = json.loads(json.loads(cleanSels))
1131 selEntries = selEntries['data']
1132
1133 if 'description' in selEntries:
1134 if(args.json):
1135 return("{\n\t\"selsResolved\": 0\n}")
1136 else:
1137 return("No log entries found")
1138 else:
1139 d = vars(args)
1140 successlist = []
1141 failedlist = []
1142 for key in selEntries:
1143 if 'callout' not in key:
1144 d['selNum'] = key.split('/')[-1]
1145 resolved = selSetResolved(host,args,session)
1146 if 'Sel entry' in resolved:
1147 successlist.append(d['selNum'])
1148 else:
1149 failedlist.append(d['selNum'])
1150 output = ""
1151 successlist.sort()
1152 failedlist.sort()
1153 if len(successlist)>0:
1154 output = "Successfully resolved: " +', '.join(successlist) +"\n"
1155 if len(failedlist)>0:
1156 output += "Failed to resolve: " + ', '.join(failedlist) + "\n"
1157 return output
1158
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001159def chassisPower(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001160 """
1161 called by the chassis function. Controls the power state of the chassis, or gets the status
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001162
Justin Thalere412dc22018-01-12 16:28:24 -06001163 @param host: string, the hostname or IP address of the bmc
1164 @param args: contains additional arguments used by the fru sub command
1165 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001166 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1167 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001168 if(args.powcmd == 'on'):
Justin Thaler22b1bb52018-03-15 13:31:32 -05001169 if checkFWactivation(host, args, session):
1170 return ("Chassis Power control disabled during firmware activation")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001171 print("Attempting to Power on...:")
1172 url="https://"+host+"/xyz/openbmc_project/state/host0/attr/RequestedHostTransition"
1173 httpHeader = {'Content-Type':'application/json',}
1174 data = '{"data":"xyz.openbmc_project.State.Host.Transition.On"}'
Justin Thalere412dc22018-01-12 16:28:24 -06001175 try:
1176 res = session.put(url, headers=httpHeader, data=data, verify=False, timeout=30)
1177 except(requests.exceptions.Timeout):
1178 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001179 return res.text
Justin Thalere412dc22018-01-12 16:28:24 -06001180 elif(args.powcmd == 'softoff'):
Justin Thaler22b1bb52018-03-15 13:31:32 -05001181 if checkFWactivation(host, args, session):
1182 return ("Chassis Power control disabled during firmware activation")
Justin Thalere412dc22018-01-12 16:28:24 -06001183 print("Attempting to Power off gracefully...:")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001184 url="https://"+host+"/xyz/openbmc_project/state/host0/attr/RequestedHostTransition"
1185 httpHeader = {'Content-Type':'application/json'}
1186 data = '{"data":"xyz.openbmc_project.State.Host.Transition.Off"}'
Justin Thalere412dc22018-01-12 16:28:24 -06001187 try:
1188 res = session.put(url, headers=httpHeader, data=data, verify=False, timeout=30)
1189 except(requests.exceptions.Timeout):
1190 return(connectionErrHandler(args.json, "Timeout", None))
1191 return res.text
1192 elif(args.powcmd == 'hardoff'):
Justin Thaler22b1bb52018-03-15 13:31:32 -05001193 if checkFWactivation(host, args, session):
1194 return ("Chassis Power control disabled during firmware activation")
Justin Thalere412dc22018-01-12 16:28:24 -06001195 print("Attempting to Power off immediately...:")
1196 url="https://"+host+"/xyz/openbmc_project/state/chassis0/attr/RequestedPowerTransition"
1197 httpHeader = {'Content-Type':'application/json'}
1198 data = '{"data":"xyz.openbmc_project.State.Chassis.Transition.Off"}'
1199 try:
1200 res = session.put(url, headers=httpHeader, data=data, verify=False, timeout=30)
1201 except(requests.exceptions.Timeout):
1202 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001203 return res.text
1204 elif(args.powcmd == 'status'):
1205 url="https://"+host+"/xyz/openbmc_project/state/chassis0/attr/CurrentPowerState"
1206 httpHeader = {'Content-Type':'application/json'}
1207# print(url)
Justin Thalere412dc22018-01-12 16:28:24 -06001208 try:
1209 res = session.get(url, headers=httpHeader, verify=False, timeout=30)
1210 except(requests.exceptions.Timeout):
1211 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001212 chassisState = json.loads(res.text)['data'].split('.')[-1]
1213 url="https://"+host+"/xyz/openbmc_project/state/host0/attr/CurrentHostState"
Justin Thalere412dc22018-01-12 16:28:24 -06001214 try:
1215 res = session.get(url, headers=httpHeader, verify=False, timeout=30)
1216 except(requests.exceptions.Timeout):
1217 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001218 hostState = json.loads(res.text)['data'].split('.')[-1]
1219 url="https://"+host+"/xyz/openbmc_project/state/bmc0/attr/CurrentBMCState"
Justin Thalere412dc22018-01-12 16:28:24 -06001220 try:
1221 res = session.get(url, headers=httpHeader, verify=False, timeout=30)
1222 except(requests.exceptions.Timeout):
1223 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001224 bmcState = json.loads(res.text)['data'].split('.')[-1]
1225 if(args.json):
1226 outDict = {"Chassis Power State" : chassisState, "Host Power State" : hostState, "BMC Power State":bmcState}
1227 return json.dumps(outDict, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False)
1228 else:
1229 return "Chassis Power State: " +chassisState + "\nHost Power State: " + hostState + "\nBMC Power State: " + bmcState
1230 else:
1231 return "Invalid chassis power command"
1232
Justin Thalere412dc22018-01-12 16:28:24 -06001233
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001234def chassisIdent(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001235 """
1236 called by the chassis function. Controls the identify led of the chassis. Sets or gets the state
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001237
Justin Thalere412dc22018-01-12 16:28:24 -06001238 @param host: string, the hostname or IP address of the bmc
1239 @param args: contains additional arguments used by the fru sub command
1240 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001241 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
Justin Thalere412dc22018-01-12 16:28:24 -06001242 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001243 if(args.identcmd == 'on'):
1244 print("Attempting to turn identify light on...:")
1245 url="https://"+host+"/xyz/openbmc_project/led/groups/enclosure_identify/attr/Asserted"
1246 httpHeader = {'Content-Type':'application/json',}
1247 data = '{"data":true}'
Justin Thalere412dc22018-01-12 16:28:24 -06001248 try:
1249 res = session.put(url, headers=httpHeader, data=data, verify=False, timeout=30)
1250 except(requests.exceptions.Timeout):
1251 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001252 return res.text
1253 elif(args.identcmd == 'off'):
1254 print("Attempting to turn identify light off...:")
1255 url="https://"+host+"/xyz/openbmc_project/led/groups/enclosure_identify/attr/Asserted"
1256 httpHeader = {'Content-Type':'application/json'}
1257 data = '{"data":false}'
Justin Thalere412dc22018-01-12 16:28:24 -06001258 try:
1259 res = session.put(url, headers=httpHeader, data=data, verify=False, timeout=30)
1260 except(requests.exceptions.Timeout):
1261 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001262 return res.text
1263 elif(args.identcmd == 'status'):
1264 url="https://"+host+"/xyz/openbmc_project/led/groups/enclosure_identify"
1265 httpHeader = {'Content-Type':'application/json'}
Justin Thalere412dc22018-01-12 16:28:24 -06001266 try:
1267 res = session.get(url, headers=httpHeader, verify=False, timeout=30)
1268 except(requests.exceptions.Timeout):
1269 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001270 status = json.loads(res.text)['data']
1271 if(args.json):
1272 return status
1273 else:
1274 if status['Asserted'] == 0:
1275 return "Identify light is off"
1276 else:
1277 return "Identify light is blinking"
1278 else:
1279 return "Invalid chassis identify command"
1280
Justin Thalere412dc22018-01-12 16:28:24 -06001281
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001282def chassis(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001283 """
1284 controls the different chassis commands
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001285
Justin Thalere412dc22018-01-12 16:28:24 -06001286 @param host: string, the hostname or IP address of the bmc
1287 @param args: contains additional arguments used by the fru sub command
1288 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001289 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1290 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001291 if(hasattr(args, 'powcmd')):
1292 result = chassisPower(host,args,session)
1293 elif(hasattr(args, 'identcmd')):
1294 result = chassisIdent(host, args, session)
1295 else:
Justin Thaler22b1bb52018-03-15 13:31:32 -05001296 return "This feature is not yet implemented"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001297 return result
Justin Thalere412dc22018-01-12 16:28:24 -06001298
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001299def bmcDumpRetrieve(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001300 """
1301 Downloads a dump file from the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001302
Justin Thalere412dc22018-01-12 16:28:24 -06001303 @param host: string, the hostname or IP address of the bmc
1304 @param args: contains additional arguments used by the collectServiceData sub command
1305 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001306 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
Justin Thalere412dc22018-01-12 16:28:24 -06001307 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001308 httpHeader = {'Content-Type':'application/json'}
1309 dumpNum = args.dumpNum
1310 if (args.dumpSaveLoc is not None):
1311 saveLoc = args.dumpSaveLoc
1312 else:
Justin Thalercf1deae2018-05-25 19:35:21 -05001313 saveLoc = tempfile.gettempdir()
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001314 url ='https://'+host+'/download/dump/' + str(dumpNum)
1315 try:
Justin Thalere412dc22018-01-12 16:28:24 -06001316 r = session.get(url, headers=httpHeader, stream=True, verify=False, timeout=30)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001317 if (args.dumpSaveLoc is not None):
1318 if os.path.exists(saveLoc):
1319 if saveLoc[-1] != os.path.sep:
1320 saveLoc = saveLoc + os.path.sep
1321 filename = saveLoc + host+'-dump' + str(dumpNum) + '.tar.xz'
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001322
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001323 else:
1324 return 'Invalid save location specified'
1325 else:
Justin Thalercf1deae2018-05-25 19:35:21 -05001326 filename = tempfile.gettempdir()+os.sep + host+'-dump' + str(dumpNum) + '.tar.xz'
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001327
1328 with open(filename, 'wb') as f:
1329 for chunk in r.iter_content(chunk_size =1024):
1330 if chunk:
1331 f.write(chunk)
1332 return 'Saved as ' + filename
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001333
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001334 except(requests.exceptions.Timeout):
1335 return connectionErrHandler(args.json, "Timeout", None)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001336
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001337 except(requests.exceptions.ConnectionError) as err:
1338 return connectionErrHandler(args.json, "ConnectionError", err)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001339
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001340def bmcDumpList(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001341 """
1342 Lists the number of dump files on the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001343
Justin Thalere412dc22018-01-12 16:28:24 -06001344 @param host: string, the hostname or IP address of the bmc
1345 @param args: contains additional arguments used by the collectServiceData sub command
1346 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001347 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1348 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001349 httpHeader = {'Content-Type':'application/json'}
1350 url ='https://'+host+'/xyz/openbmc_project/dump/list'
1351 try:
1352 r = session.get(url, headers=httpHeader, verify=False, timeout=20)
1353 dumpList = json.loads(r.text)
1354 return r.text
1355 except(requests.exceptions.Timeout):
1356 return connectionErrHandler(args.json, "Timeout", None)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001357
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001358 except(requests.exceptions.ConnectionError) as err:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001359 return connectionErrHandler(args.json, "ConnectionError", err)
1360
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001361def bmcDumpDelete(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001362 """
1363 Deletes BMC dump files from the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001364
Justin Thalere412dc22018-01-12 16:28:24 -06001365 @param host: string, the hostname or IP address of the bmc
1366 @param args: contains additional arguments used by the collectServiceData sub command
1367 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001368 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
Justin Thalere412dc22018-01-12 16:28:24 -06001369 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001370 httpHeader = {'Content-Type':'application/json'}
1371 dumpList = []
1372 successList = []
1373 failedList = []
1374 if args.dumpNum is not None:
1375 if isinstance(args.dumpNum, list):
1376 dumpList = args.dumpNum
1377 else:
1378 dumpList.append(args.dumpNum)
1379 for dumpNum in dumpList:
1380 url ='https://'+host+'/xyz/openbmc_project/dump/entry/'+str(dumpNum)+'/action/Delete'
1381 try:
1382 r = session.post(url, headers=httpHeader, json = {"data": []}, verify=False, timeout=30)
1383 if r.status_code == 200:
1384 successList.append(str(dumpNum))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001385 else:
1386 failedList.append(str(dumpNum))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001387 except(requests.exceptions.Timeout):
1388 return connectionErrHandler(args.json, "Timeout", None)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001389 except(requests.exceptions.ConnectionError) as err:
1390 return connectionErrHandler(args.json, "ConnectionError", err)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001391 output = "Successfully deleted dumps: " + ', '.join(successList)
1392 if(len(failedList)>0):
1393 output+= '\nFailed to delete dumps: ' + ', '.join(failedList)
1394 return output
1395 else:
1396 return 'You must specify an entry number to delete'
1397
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001398def bmcDumpDeleteAll(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001399 """
1400 Deletes All BMC dump files from the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001401
Justin Thalere412dc22018-01-12 16:28:24 -06001402 @param host: string, the hostname or IP address of the bmc
1403 @param args: contains additional arguments used by the collectServiceData sub command
1404 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001405 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
Justin Thalere412dc22018-01-12 16:28:24 -06001406 """
1407 dumpResp = bmcDumpList(host, args, session)
1408 if 'FQPSPIN0000M' in dumpResp or 'FQPSPIN0001M'in dumpResp:
1409 return dumpResp
1410 dumpList = json.loads(dumpResp)['data']
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001411 d = vars(args)
1412 dumpNums = []
1413 for dump in dumpList:
1414 if '/xyz/openbmc_project/dump/internal/manager' not in dump:
1415 dumpNums.append(int(dump.strip().split('/')[-1]))
1416 d['dumpNum'] = dumpNums
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001417
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001418 return bmcDumpDelete(host, args, session)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001419
Justin Thalere412dc22018-01-12 16:28:24 -06001420
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001421def bmcDumpCreate(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001422 """
1423 Creates a bmc dump file
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001424
Justin Thalere412dc22018-01-12 16:28:24 -06001425 @param host: string, the hostname or IP address of the bmc
1426 @param args: contains additional arguments used by the collectServiceData sub command
1427 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001428 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
Justin Thalere412dc22018-01-12 16:28:24 -06001429 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001430 httpHeader = {'Content-Type':'application/json'}
1431 url = 'https://'+host+'/xyz/openbmc_project/dump/action/CreateDump'
1432 try:
1433 r = session.post(url, headers=httpHeader, json = {"data": []}, verify=False, timeout=30)
1434 if('"message": "200 OK"' in r.text and not args.json):
1435 return ('Dump successfully created')
1436 else:
1437 return ('Failed to create dump')
1438 except(requests.exceptions.Timeout):
1439 return connectionErrHandler(args.json, "Timeout", None)
1440 except(requests.exceptions.ConnectionError) as err:
1441 return connectionErrHandler(args.json, "ConnectionError", err)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001442
1443
1444
Justin Thalere412dc22018-01-12 16:28:24 -06001445
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001446def collectServiceData(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001447 """
1448 Collects all data needed for service from the BMC
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001449
Justin Thalere412dc22018-01-12 16:28:24 -06001450 @param host: string, the hostname or IP address of the bmc
1451 @param args: contains additional arguments used by the collectServiceData sub command
1452 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001453 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
Justin Thalere412dc22018-01-12 16:28:24 -06001454 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001455
Justin Thaler22b1bb52018-03-15 13:31:32 -05001456 global toolVersion
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001457 #create a bmc dump
1458 dumpcount = len(json.loads(bmcDumpList(host, args, session))['data'])
1459 try:
1460 dumpcreated = bmcDumpCreate(host, args, session)
1461 except Exception as e:
1462 print('failed to create a bmc dump')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001463
1464
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001465 #Collect Inventory
1466 try:
1467 args.silent = True
Justin Thalercf1deae2018-05-25 19:35:21 -05001468 myDir = tempfile.gettempdir()+os.sep + host + "--" + datetime.datetime.now().strftime("%Y-%m-%d_%H.%M.%S")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001469 os.makedirs(myDir)
1470 filelist = []
1471 frulist = fruPrint(host, args, session)
1472 with open(myDir +'/inventory.txt', 'w') as f:
1473 f.write(frulist)
1474 print("Inventory collected and stored in " + myDir + "/inventory.txt")
1475 filelist.append(myDir+'/inventory.txt')
1476 except Exception as e:
1477 print("Failed to collect inventory")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001478
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001479 #Read all the sensor and OCC status
1480 try:
1481 sensorReadings = sensor(host, args, session)
1482 with open(myDir +'/sensorReadings.txt', 'w') as f:
1483 f.write(sensorReadings)
1484 print("Sensor readings collected and stored in " +myDir + "/sensorReadings.txt")
1485 filelist.append(myDir+'/sensorReadings.txt')
1486 except Exception as e:
1487 print("Failed to collect sensor readings")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001488
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001489 #Collect all of the LEDs status
1490 try:
1491 url="https://"+host+"/xyz/openbmc_project/led/enumerate"
1492 httpHeader = {'Content-Type':'application/json'}
1493 leds = session.get(url, headers=httpHeader, verify=False, timeout=20)
1494 with open(myDir +'/ledStatus.txt', 'w') as f:
1495 f.write(leds.text)
1496 print("System LED status collected and stored in "+myDir +"/ledStatus.txt")
1497 filelist.append(myDir+'/ledStatus.txt')
1498 except Exception as e:
1499 print("Failed to collect LED status")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001500
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001501 #Collect the bmc logs
1502 try:
1503 sels = selPrint(host,args,session)
1504 with open(myDir +'/SELshortlist.txt', 'w') as f:
1505 f.write(str(sels))
1506 print("sel short list collected and stored in "+myDir +"/SELshortlist.txt")
1507 filelist.append(myDir+'/SELshortlist.txt')
1508 time.sleep(2)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001509
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001510 d = vars(args)
1511 d['json'] = True
1512 d['fullSel'] = True
1513 parsedfullsels = json.loads(selPrint(host, args, session))
1514 d['fullEsel'] = True
1515 sortedSELs = sortSELs(parsedfullsels)
1516 with open(myDir +'/parsedSELs.txt', 'w') as f:
1517 for log in sortedSELs[0]:
1518 esel = ""
1519 parsedfullsels[sortedSELs[1][str(log)]]['timestamp'] = datetime.datetime.fromtimestamp(int(parsedfullsels[sortedSELs[1][str(log)]]['timestamp']/1000)).strftime("%Y-%m-%d %H:%M:%S")
1520 if ('raweSEL' in parsedfullsels[sortedSELs[1][str(log)]] and args.devdebug):
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001521 esel = parsedfullsels[sortedSELs[1][str(log)]]['raweSEL']
1522 del parsedfullsels[sortedSELs[1][str(log)]]['raweSEL']
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001523 f.write(json.dumps(parsedfullsels[sortedSELs[1][str(log)]],sort_keys=True, indent=4, separators=(',', ': ')))
1524 if(args.devdebug and esel != ""):
1525 f.write(parseESEL(args, esel))
1526 print("fully parsed sels collected and stored in "+myDir +"/parsedSELs.txt")
1527 filelist.append(myDir+'/parsedSELs.txt')
1528 except Exception as e:
1529 print("Failed to collect system event logs")
1530 print(e)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001531
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001532 #collect RAW bmc enumeration
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001533 try:
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001534 url="https://"+host+"/xyz/openbmc_project/enumerate"
1535 print("Attempting to get a full BMC enumeration")
1536 fullDump = session.get(url, headers=httpHeader, verify=False, timeout=120)
1537 with open(myDir +'/bmcFullRaw.txt', 'w') as f:
1538 f.write(fullDump.text)
1539 print("RAW BMC data collected and saved into "+myDir +"/bmcFullRaw.txt")
1540 filelist.append(myDir+'/bmcFullRaw.txt')
1541 except Exception as e:
1542 print("Failed to collect bmc full enumeration")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001543
1544 #collect the dump files
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001545 waitingForNewDump = True
1546 count = 0;
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001547 while(waitingForNewDump):
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001548 dumpList = json.loads(bmcDumpList(host, args, session))['data']
1549 if len(dumpList) > dumpcount:
1550 waitingForNewDump = False
1551 break;
1552 elif(count>30):
1553 print("Timed out waiting for bmc to make a new dump file. Dump space may be full.")
1554 break;
1555 else:
1556 time.sleep(2)
1557 count += 1
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001558 try:
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001559 print('Collecting bmc dump files')
1560 d['dumpSaveLoc'] = myDir
1561 dumpList = json.loads(bmcDumpList(host, args, session))['data']
1562 for dump in dumpList:
1563 if '/xyz/openbmc_project/dump/internal/manager' not in dump:
1564 d['dumpNum'] = int(dump.strip().split('/')[-1])
1565 print('retrieving dump file ' + str(d['dumpNum']))
1566 filename = bmcDumpRetrieve(host, args, session).split('Saved as ')[-1]
1567 filelist.append(filename)
1568 time.sleep(2)
1569 except Exception as e:
1570 print("Failed to collect bmc dump files")
1571 print(e)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001572
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001573 #create the zip file
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001574 try:
Justin Thalercf1deae2018-05-25 19:35:21 -05001575 filename = myDir.split(tempfile.gettempdir()+os.sep)[-1] + "_" + toolVersion + '_openbmc.zip'
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001576 zf = zipfile.ZipFile(myDir+'/' + filename, 'w')
1577 for myfile in filelist:
1578 zf.write(myfile, os.path.basename(myfile))
1579 zf.close()
1580 except Exception as e:
1581 print("Failed to create zip file with collected information")
1582 return "data collection complete"
1583
Justin Thalere412dc22018-01-12 16:28:24 -06001584
1585def healthCheck(host, args, session):
1586 """
1587 runs a health check on the platform
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001588
Justin Thalere412dc22018-01-12 16:28:24 -06001589 @param host: string, the hostname or IP address of the bmc
1590 @param args: contains additional arguments used by the bmc sub command
1591 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001592 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1593 """
Justin Thalere412dc22018-01-12 16:28:24 -06001594 #check fru status and get as json to easily work through
1595 d = vars(args)
1596 useJson = d['json']
1597 d['json'] = True
1598 d['verbose']= False
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001599
Justin Thalere412dc22018-01-12 16:28:24 -06001600 frus = json.loads(fruStatus(host, args, session))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001601
Justin Thalere412dc22018-01-12 16:28:24 -06001602 hwStatus= "OK"
1603 performanceStatus = "OK"
1604 for key in frus:
1605 if frus[key]["Functional"] == "No" and frus[key]["Present"] == "Yes":
1606 hwStatus= "Degraded"
Justin Thalerfb9c81c2018-07-16 11:14:37 -05001607 if("power_supply" in key or "powersupply" in key):
1608 gpuCount =0
1609 for comp in frus:
Justin Thalere412dc22018-01-12 16:28:24 -06001610 if "gv100card" in comp:
1611 gpuCount +=1
1612 if gpuCount > 4:
1613 hwStatus = "Critical"
1614 performanceStatus="Degraded"
1615 break;
1616 elif("fan" in key):
1617 hwStatus = "Degraded"
1618 else:
1619 performanceStatus = "Degraded"
1620 if useJson:
1621 output = {"Hardware Status": hwStatus, "Performance": performanceStatus}
1622 output = json.dumps(output, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False)
1623 else:
1624 output = ("Hardware Status: " + hwStatus +
1625 "\nPerformance: " +performanceStatus )
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001626
1627
Justin Thalere412dc22018-01-12 16:28:24 -06001628 #SW407886: Clear the duplicate entries
1629 #collect the dups
1630 d['devdebug'] = False
1631 sels = json.loads(selPrint(host, args, session))
1632 logNums2Clr = []
1633 oldestLogNum={"logNum": "bogus" ,"key" : ""}
1634 count = 0
1635 if sels['numAlerts'] > 0:
1636 for key in sels:
1637 if "numAlerts" in key:
1638 continue
1639 try:
1640 if "slave@00:00/00:00:00:06/sbefifo1-dev0/occ1-dev0" in sels[key]['Message']:
1641 count += 1
1642 if count > 1:
1643 #preserve first occurrence
1644 if sels[key]['timestamp'] < sels[oldestLogNum['key']]['timestamp']:
1645 oldestLogNum['key']=key
1646 oldestLogNum['logNum'] = sels[key]['logNum']
1647 else:
1648 oldestLogNum['key']=key
1649 oldestLogNum['logNum'] = sels[key]['logNum']
1650 logNums2Clr.append(sels[key]['logNum'])
1651 except KeyError:
1652 continue
1653 if(count >0):
1654 logNums2Clr.remove(oldestLogNum['logNum'])
1655 #delete the dups
1656 if count >1:
1657 httpHeader = {'Content-Type':'application/json'}
1658 data = "{\"data\": [] }"
1659 for logNum in logNums2Clr:
1660 url = "https://"+ host+ "/xyz/openbmc_project/logging/entry/"+logNum+"/action/Delete"
1661 try:
1662 session.post(url, headers=httpHeader, data=data, verify=False, timeout=30)
1663 except(requests.exceptions.Timeout):
1664 deleteFailed = True
1665 except(requests.exceptions.ConnectionError) as err:
1666 deleteFailed = True
1667 #End of defect resolve code
1668 d['json'] = useJson
1669 return output
1670
1671
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001672
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001673def bmc(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001674 """
1675 handles various bmc level commands, currently bmc rebooting
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001676
Justin Thalere412dc22018-01-12 16:28:24 -06001677 @param host: string, the hostname or IP address of the bmc
1678 @param args: contains additional arguments used by the bmc sub command
1679 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001680 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1681 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001682 if(args.type is not None):
1683 return bmcReset(host, args, session)
Justin Thalere412dc22018-01-12 16:28:24 -06001684 if(args.info):
1685 return "Not implemented at this time"
1686
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001687
Justin Thalere412dc22018-01-12 16:28:24 -06001688
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001689def bmcReset(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001690 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001691 controls resetting the bmc. warm reset reboots the bmc, cold reset removes the configuration and reboots.
1692
Justin Thalere412dc22018-01-12 16:28:24 -06001693 @param host: string, the hostname or IP address of the bmc
1694 @param args: contains additional arguments used by the bmcReset sub command
1695 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001696 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1697 """
Justin Thaler22b1bb52018-03-15 13:31:32 -05001698 if checkFWactivation(host, args, session):
1699 return ("BMC reset control disabled during firmware activation")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001700 if(args.type == "warm"):
1701 print("\nAttempting to reboot the BMC...:")
1702 url="https://"+host+"/xyz/openbmc_project/state/bmc0/attr/RequestedBMCTransition"
1703 httpHeader = {'Content-Type':'application/json'}
Justin Thalere412dc22018-01-12 16:28:24 -06001704 data = '{"data":"xyz.openbmc_project.State.BMC.Transition.Reboot"}'
1705 res = session.put(url, headers=httpHeader, data=data, verify=False, timeout=20)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001706 return res.text
1707 elif(args.type =="cold"):
Justin Thalere412dc22018-01-12 16:28:24 -06001708 print("\nAttempting to reboot the BMC...:")
1709 url="https://"+host+"/xyz/openbmc_project/state/bmc0/attr/RequestedBMCTransition"
1710 httpHeader = {'Content-Type':'application/json'}
1711 data = '{"data":"xyz.openbmc_project.State.BMC.Transition.Reboot"}'
1712 res = session.put(url, headers=httpHeader, data=data, verify=False, timeout=20)
1713 return res.text
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001714 else:
1715 return "invalid command"
Justin Thalere412dc22018-01-12 16:28:24 -06001716
1717def gardClear(host, args, session):
1718 """
1719 clears the gard records from the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001720
Justin Thalere412dc22018-01-12 16:28:24 -06001721 @param host: string, the hostname or IP address of the bmc
1722 @param args: contains additional arguments used by the gardClear sub command
1723 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001724 """
Justin Thalere412dc22018-01-12 16:28:24 -06001725 url="https://"+host+"/org/open_power/control/gard/action/Reset"
1726 httpHeader = {'Content-Type':'application/json'}
1727 data = '{"data":[]}'
1728 try:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001729
Justin Thalere412dc22018-01-12 16:28:24 -06001730 res = session.post(url, headers=httpHeader, data=data, verify=False, timeout=30)
1731 if res.status_code == 404:
1732 return "Command not supported by this firmware version"
1733 else:
1734 return res.text
1735 except(requests.exceptions.Timeout):
1736 return connectionErrHandler(args.json, "Timeout", None)
1737 except(requests.exceptions.ConnectionError) as err:
1738 return connectionErrHandler(args.json, "ConnectionError", err)
1739
1740def activateFWImage(host, args, session):
1741 """
1742 activates a firmware image on the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001743
Justin Thalere412dc22018-01-12 16:28:24 -06001744 @param host: string, the hostname or IP address of the bmc
1745 @param args: contains additional arguments used by the fwflash sub command
1746 @param session: the active session to use
1747 @param fwID: the unique ID of the fw image to activate
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001748 """
Justin Thalere412dc22018-01-12 16:28:24 -06001749 fwID = args.imageID
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001750
Justin Thalere412dc22018-01-12 16:28:24 -06001751 #determine the existing versions
1752 httpHeader = {'Content-Type':'application/json'}
1753 url="https://"+host+"/xyz/openbmc_project/software/enumerate"
1754 try:
1755 resp = session.get(url, headers=httpHeader, verify=False, timeout=30)
1756 except(requests.exceptions.Timeout):
1757 return connectionErrHandler(args.json, "Timeout", None)
1758 except(requests.exceptions.ConnectionError) as err:
1759 return connectionErrHandler(args.json, "ConnectionError", err)
1760 existingSoftware = json.loads(resp.text)['data']
1761 altVersionID = ''
1762 versionType = ''
1763 imageKey = '/xyz/openbmc_project/software/'+fwID
1764 if imageKey in existingSoftware:
1765 versionType = existingSoftware[imageKey]['Purpose']
1766 for key in existingSoftware:
1767 if imageKey == key:
1768 continue
1769 if 'Purpose' in existingSoftware[key]:
1770 if versionType == existingSoftware[key]['Purpose']:
1771 altVersionID = key.split('/')[-1]
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001772
1773
1774
1775
Justin Thalere412dc22018-01-12 16:28:24 -06001776 url="https://"+host+"/xyz/openbmc_project/software/"+ fwID + "/attr/Priority"
1777 url1="https://"+host+"/xyz/openbmc_project/software/"+ altVersionID + "/attr/Priority"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001778 data = "{\"data\": 0}"
Justin Thalere412dc22018-01-12 16:28:24 -06001779 data1 = "{\"data\": 1 }"
1780 try:
1781 resp = session.put(url, headers=httpHeader, data=data, verify=False, timeout=30)
1782 resp1 = session.put(url1, headers=httpHeader, data=data1, verify=False, timeout=30)
1783 except(requests.exceptions.Timeout):
1784 return connectionErrHandler(args.json, "Timeout", None)
1785 except(requests.exceptions.ConnectionError) as err:
1786 return connectionErrHandler(args.json, "ConnectionError", err)
1787 if(not args.json):
1788 if resp.status_code == 200 and resp1.status_code == 200:
Justin Thaler22b1bb52018-03-15 13:31:32 -05001789 return 'Firmware flash and activation completed. Please reboot the bmc and then boot the host OS for the changes to take effect. '
Justin Thalere412dc22018-01-12 16:28:24 -06001790 else:
1791 return "Firmware activation failed."
1792 else:
1793 return resp.text + resp1.text
Justin Thaler22b1bb52018-03-15 13:31:32 -05001794
1795def activateStatus(host, args, session):
1796 if checkFWactivation(host, args, session):
1797 return("Firmware is currently being activated. Do not reboot the BMC or start the Host OS")
1798 else:
1799 return("No firmware activations are pending")
1800
1801def extractFWimage(path, imageType):
1802 """
1803 extracts the bmc image and returns information about the package
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001804
Justin Thaler22b1bb52018-03-15 13:31:32 -05001805 @param path: the path and file name of the firmware image
1806 @param imageType: The type of image the user is trying to flash. Host or BMC
1807 @return: the image id associated with the package. returns an empty string on error.
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001808 """
Justin Thaler22b1bb52018-03-15 13:31:32 -05001809 f = tempfile.TemporaryFile()
1810 tmpDir = tempfile.gettempdir()
1811 newImageID = ""
1812 if os.path.exists(path):
1813 try:
1814 imageFile = tarfile.open(path,'r')
1815 contents = imageFile.getmembers()
1816 for tf in contents:
1817 if 'MANIFEST' in tf.name:
1818 imageFile.extract(tf.name, path=tmpDir)
1819 with open(tempfile.gettempdir() +os.sep+ tf.name, 'r') as imageInfo:
1820 for line in imageInfo:
1821 if 'purpose' in line:
1822 purpose = line.split('=')[1]
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001823 if imageType not in purpose.split('.')[-1]:
Justin Thaler22b1bb52018-03-15 13:31:32 -05001824 print('The specified image is not for ' + imageType)
1825 print('Please try again with the image for ' + imageType)
1826 return ""
1827 if 'version' == line.split('=')[0]:
1828 version = line.split('=')[1].strip().encode('utf-8')
1829 m = hashlib.sha512()
1830 m.update(version)
1831 newImageID = m.hexdigest()[:8]
1832 break
1833 try:
1834 os.remove(tempfile.gettempdir() +os.sep+ tf.name)
1835 except OSError:
1836 pass
1837 return newImageID
1838 except tarfile.ExtractError as e:
1839 print('Unable to extract information from the firmware file.')
1840 print('Ensure you have write access to the directory: ' + tmpDir)
1841 return newImageID
1842 except tarfile.TarError as e:
1843 print('This is not a valid firmware file.')
1844 return newImageID
1845 print("This is not a valid firmware file.")
1846 return newImageID
1847 else:
1848 print('The filename and path provided are not valid.')
1849 return newImageID
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001850
Justin Thaler22b1bb52018-03-15 13:31:32 -05001851def getAllFWImageIDs(fwInvDict):
1852 """
1853 gets a list of all the firmware image IDs
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001854
Justin Thaler22b1bb52018-03-15 13:31:32 -05001855 @param fwInvDict: the dictionary to search for FW image IDs
1856 @return: list containing string representation of the found image ids
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001857 """
Justin Thaler22b1bb52018-03-15 13:31:32 -05001858 idList = []
1859 for key in fwInvDict:
1860 if 'Version' in fwInvDict[key]:
1861 idList.append(key.split('/')[-1])
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001862 return idList
1863
Justin Thalere412dc22018-01-12 16:28:24 -06001864def fwFlash(host, args, session):
1865 """
1866 updates the bmc firmware and pnor firmware
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001867
Justin Thalere412dc22018-01-12 16:28:24 -06001868 @param host: string, the hostname or IP address of the bmc
1869 @param args: contains additional arguments used by the fwflash sub command
1870 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001871 """
Justin Thaler22b1bb52018-03-15 13:31:32 -05001872 d = vars(args)
Justin Thalere412dc22018-01-12 16:28:24 -06001873 if(args.type == 'bmc'):
1874 purp = 'BMC'
1875 else:
1876 purp = 'Host'
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001877
1878 #check power state of the machine. No concurrent FW updates allowed
Justin Thaler22b1bb52018-03-15 13:31:32 -05001879 d['powcmd'] = 'status'
1880 powerstate = chassisPower(host, args, session)
1881 if 'Chassis Power State: On' in powerstate:
1882 return("Aborting firmware update. Host is powered on. Please turn off the host and try again.")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001883
Justin Thaler22b1bb52018-03-15 13:31:32 -05001884 #determine the existing images on the bmc
Justin Thalere412dc22018-01-12 16:28:24 -06001885 httpHeader = {'Content-Type':'application/json'}
1886 url="https://"+host+"/xyz/openbmc_project/software/enumerate"
1887 try:
1888 resp = session.get(url, headers=httpHeader, verify=False, timeout=30)
1889 except(requests.exceptions.Timeout):
1890 return connectionErrHandler(args.json, "Timeout", None)
1891 except(requests.exceptions.ConnectionError) as err:
1892 return connectionErrHandler(args.json, "ConnectionError", err)
1893 oldsoftware = json.loads(resp.text)['data']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001894
Justin Thaler22b1bb52018-03-15 13:31:32 -05001895 #Extract the tar and get information from the manifest file
1896 newversionID = extractFWimage(args.fileloc, purp)
1897 if newversionID == "":
1898 return "Unable to verify FW image."
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001899
1900
Justin Thaler22b1bb52018-03-15 13:31:32 -05001901 #check if the new image is already on the bmc
1902 if newversionID not in getAllFWImageIDs(oldsoftware):
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001903
Justin Thaler22b1bb52018-03-15 13:31:32 -05001904 #upload the file
1905 httpHeader = {'Content-Type':'application/octet-stream'}
1906 url="https://"+host+"/upload/image"
1907 data=open(args.fileloc,'rb').read()
1908 print("Uploading file to BMC")
Justin Thalere412dc22018-01-12 16:28:24 -06001909 try:
Justin Thaler22b1bb52018-03-15 13:31:32 -05001910 resp = session.post(url, headers=httpHeader, data=data, verify=False)
Justin Thalere412dc22018-01-12 16:28:24 -06001911 except(requests.exceptions.Timeout):
1912 return connectionErrHandler(args.json, "Timeout", None)
1913 except(requests.exceptions.ConnectionError) as err:
1914 return connectionErrHandler(args.json, "ConnectionError", err)
Justin Thaler22b1bb52018-03-15 13:31:32 -05001915 if resp.status_code != 200:
1916 return "Failed to upload the file to the bmc"
Justin Thalere412dc22018-01-12 16:28:24 -06001917 else:
Justin Thaler22b1bb52018-03-15 13:31:32 -05001918 print("Upload complete.")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001919
Justin Thaler22b1bb52018-03-15 13:31:32 -05001920 #verify bmc processed the image
1921 software ={}
1922 for i in range(0, 5):
1923 httpHeader = {'Content-Type':'application/json'}
1924 url="https://"+host+"/xyz/openbmc_project/software/enumerate"
1925 try:
1926 resp = session.get(url, headers=httpHeader, verify=False, timeout=30)
1927 except(requests.exceptions.Timeout):
1928 return connectionErrHandler(args.json, "Timeout", None)
1929 except(requests.exceptions.ConnectionError) as err:
1930 return connectionErrHandler(args.json, "ConnectionError", err)
1931 software = json.loads(resp.text)['data']
1932 #check if bmc is done processing the new image
1933 if (newversionID in getAllFWImageIDs(software)):
Justin Thalere412dc22018-01-12 16:28:24 -06001934 break
Justin Thaler22b1bb52018-03-15 13:31:32 -05001935 else:
1936 time.sleep(15)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001937
Justin Thaler22b1bb52018-03-15 13:31:32 -05001938 #activate the new image
1939 print("Activating new image: "+newversionID)
1940 url="https://"+host+"/xyz/openbmc_project/software/"+ newversionID + "/attr/RequestedActivation"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001941 data = '{"data":"xyz.openbmc_project.Software.Activation.RequestedActivations.Active"}'
Justin Thaler22b1bb52018-03-15 13:31:32 -05001942 try:
1943 resp = session.put(url, headers=httpHeader, data=data, verify=False, timeout=30)
1944 except(requests.exceptions.Timeout):
1945 return connectionErrHandler(args.json, "Timeout", None)
1946 except(requests.exceptions.ConnectionError) as err:
1947 return connectionErrHandler(args.json, "ConnectionError", err)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001948
Justin Thaler22b1bb52018-03-15 13:31:32 -05001949 #wait for the activation to complete, timeout after ~1 hour
1950 i=0
1951 while i < 360:
1952 url="https://"+host+"/xyz/openbmc_project/software/"+ newversionID
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001953 data = '{"data":"xyz.openbmc_project.Software.Activation.RequestedActivations.Active"}'
Justin Thaler22b1bb52018-03-15 13:31:32 -05001954 try:
1955 resp = session.get(url, headers=httpHeader, verify=False, timeout=30)
1956 except(requests.exceptions.Timeout):
1957 return connectionErrHandler(args.json, "Timeout", None)
1958 except(requests.exceptions.ConnectionError) as err:
1959 return connectionErrHandler(args.json, "ConnectionError", err)
1960 fwInfo = json.loads(resp.text)['data']
1961 if 'Activating' not in fwInfo['Activation'] and 'Activating' not in fwInfo['RequestedActivation']:
1962 print('')
1963 break
1964 else:
1965 sys.stdout.write('.')
1966 sys.stdout.flush()
1967 time.sleep(10) #check every 10 seconds
1968 return "Firmware flash and activation completed. Please reboot the bmc and then boot the host OS for the changes to take effect. "
1969 else:
1970 print("This image has been found on the bmc. Activating image: " + newversionID)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001971
Justin Thaler22b1bb52018-03-15 13:31:32 -05001972 d['imageID'] = newversionID
1973 return activateFWImage(host, args, session)
Justin Thalere412dc22018-01-12 16:28:24 -06001974
Justin Thaler3d71d402018-07-24 14:35:39 -05001975def getFWInventoryAttributes(rawFWInvItem, ID):
1976 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001977 gets and lists all of the firmware in the system.
1978
Justin Thaler3d71d402018-07-24 14:35:39 -05001979 @return: returns a dictionary containing the image attributes
1980 """
1981 reqActivation = rawFWInvItem["RequestedActivation"].split('.')[-1]
1982 pendingActivation = ""
1983 if reqActivation == "None":
1984 pendingActivation = "No"
1985 else:
1986 pendingActivation = "Yes"
1987 firmwareAttr = {ID: {
1988 "Purpose": rawFWInvItem["Purpose"].split('.')[-1],
1989 "Version": rawFWInvItem["Version"],
1990 "RequestedActivation": pendingActivation,
1991 "ID": ID}}
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001992
Justin Thaler3d71d402018-07-24 14:35:39 -05001993 if "ExtendedVersion" in rawFWInvItem:
1994 firmwareAttr[ID]['ExtendedVersion'] = rawFWInvItem['ExtendedVersion'].split(',')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001995 else:
Justin Thaler3d71d402018-07-24 14:35:39 -05001996 firmwareAttr[ID]['ExtendedVersion'] = ""
1997 return firmwareAttr
1998
1999def parseFWdata(firmwareDict):
2000 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002001 creates a dictionary with parsed firmware data
2002
Justin Thaler3d71d402018-07-24 14:35:39 -05002003 @return: returns a dictionary containing the image attributes
2004 """
2005 firmwareInfoDict = {"Functional": {}, "Activated":{}, "NeedsActivated":{}}
2006 for key in firmwareDict['data']:
2007 #check for valid endpoint
2008 if "Purpose" in firmwareDict['data'][key]:
2009 id = key.split('/')[-1]
2010 if firmwareDict['data'][key]['Activation'].split('.')[-1] == "Active":
2011 fwActivated = True
2012 else:
2013 fwActivated = False
2014 if firmwareDict['data'][key]['Priority'] == 0:
2015 firmwareInfoDict['Functional'].update(getFWInventoryAttributes(firmwareDict['data'][key], id))
2016 elif firmwareDict['data'][key]['Priority'] >= 0 and fwActivated:
2017 firmwareInfoDict['Activated'].update(getFWInventoryAttributes(firmwareDict['data'][key], id))
2018 else:
2019 firmwareInfoDict['Activated'].update(getFWInventoryAttributes(firmwareDict['data'][key], id))
2020 emptySections = []
2021 for key in firmwareInfoDict:
2022 if len(firmwareInfoDict[key])<=0:
2023 emptySections.append(key)
2024 for key in emptySections:
2025 del firmwareInfoDict[key]
2026 return firmwareInfoDict
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002027
Justin Thaler3d71d402018-07-24 14:35:39 -05002028def displayFWInvenory(firmwareInfoDict, args):
2029 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002030 gets and lists all of the firmware in the system.
2031
Justin Thaler3d71d402018-07-24 14:35:39 -05002032 @return: returns a string containing all of the firmware information
2033 """
2034 output = ""
2035 if not args.json:
2036 for key in firmwareInfoDict:
2037 for subkey in firmwareInfoDict[key]:
2038 firmwareInfoDict[key][subkey]['ExtendedVersion'] = str(firmwareInfoDict[key][subkey]['ExtendedVersion'])
2039 if not args.verbose:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002040 output = "---Running Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002041 colNames = ["Purpose", "Version", "ID"]
2042 keylist = ["Purpose", "Version", "ID"]
2043 output += tableDisplay(keylist, colNames, firmwareInfoDict["Functional"])
2044 if "Activated" in firmwareInfoDict:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002045 output += "\n---Available Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002046 output += tableDisplay(keylist, colNames, firmwareInfoDict["Activated"])
2047 if "NeedsActivated" in firmwareInfoDict:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002048 output += "\n---Needs Activated Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002049 output += tableDisplay(keylist, colNames, firmwareInfoDict["NeedsActivated"])
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002050
Justin Thaler3d71d402018-07-24 14:35:39 -05002051 else:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002052 output = "---Running Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002053 colNames = ["Purpose", "Version", "ID", "Pending Activation", "Extended Version"]
2054 keylist = ["Purpose", "Version", "ID", "RequestedActivation", "ExtendedVersion"]
2055 output += tableDisplay(keylist, colNames, firmwareInfoDict["Functional"])
2056 if "Activated" in firmwareInfoDict:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002057 output += "\n---Available Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002058 output += tableDisplay(keylist, colNames, firmwareInfoDict["Activated"])
2059 if "NeedsActivated" in firmwareInfoDict:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002060 output += "\n---Needs Activated Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002061 output += tableDisplay(keylist, colNames, firmwareInfoDict["NeedsActivated"])
2062 return output
2063 else:
2064 return str(json.dumps(firmwareInfoDict, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False))
2065
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002066def firmwareList(host, args, session):
Justin Thaler3d71d402018-07-24 14:35:39 -05002067 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002068 gets and lists all of the firmware in the system.
2069
Justin Thaler3d71d402018-07-24 14:35:39 -05002070 @return: returns a string containing all of the firmware information
2071 """
2072 httpHeader = {'Content-Type':'application/json'}
2073 url="https://{hostname}/xyz/openbmc_project/software/enumerate".format(hostname=host)
2074 try:
2075 res = session.get(url, headers=httpHeader, verify=False, timeout=40)
2076 except(requests.exceptions.Timeout):
2077 return(connectionErrHandler(args.json, "Timeout", None))
2078 firmwareDict = json.loads(res.text)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002079
Justin Thaler3d71d402018-07-24 14:35:39 -05002080 #sort the received information
2081 firmwareInfoDict = parseFWdata(firmwareDict)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002082
Justin Thaler3d71d402018-07-24 14:35:39 -05002083 #display the information
2084 return displayFWInvenory(firmwareInfoDict, args)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002085
2086
Adriana Kobylak5af2fad2018-11-08 12:33:43 -06002087def deleteFWVersion(host, args, session):
2088 """
2089 deletes a firmware version on the BMC
2090
2091 @param host: string, the hostname or IP address of the BMC
2092 @param args: contains additional arguments used by the fwflash sub command
2093 @param session: the active session to use
2094 @param fwID: the unique ID of the fw version to delete
2095 """
2096 fwID = args.versionID
2097
2098 print("Deleting version: "+fwID)
2099 url="https://"+host+"/xyz/openbmc_project/software/"+ fwID + "/action/Delete"
2100 httpHeader = {'Content-Type':'application/json'}
2101 data = "{\"data\": [] }"
2102
2103 try:
2104 res = session.post(url, headers=httpHeader, data=data, verify=False, timeout=30)
2105 except(requests.exceptions.Timeout):
2106 return(connectionErrHandler(args.json, "Timeout", None))
2107 if res.status_code == 200:
2108 return ('The firmware version has been deleted')
2109 else:
2110 return ('Unable to delete the specified firmware version')
2111
2112
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05002113def restLogging(host, args, session):
2114 """
2115 Called by the logging function. Turns REST API logging on/off.
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002116
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05002117 @param host: string, the hostname or IP address of the bmc
2118 @param args: contains additional arguments used by the logging sub command
2119 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002120 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05002121 """
2122
2123 url="https://"+host+"/xyz/openbmc_project/logging/rest_api_logs/attr/Enabled"
2124 httpHeader = {'Content-Type':'application/json'}
2125
2126 if(args.rest_logging == 'on'):
2127 data = '{"data": 1}'
2128 elif(args.rest_logging == 'off'):
2129 data = '{"data": 0}'
2130 else:
2131 return "Invalid logging rest_api command"
2132
2133 try:
2134 res = session.put(url, headers=httpHeader, data=data, verify=False, timeout=30)
2135 except(requests.exceptions.Timeout):
2136 return(connectionErrHandler(args.json, "Timeout", None))
2137 return res.text
2138
2139
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002140def remoteLogging(host, args, session):
2141 """
2142 Called by the logging function. View config information for/disable remote logging (rsyslog).
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002143
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002144 @param host: string, the hostname or IP address of the bmc
2145 @param args: contains additional arguments used by the logging sub command
2146 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002147 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002148 """
2149
2150 url="https://"+host+"/xyz/openbmc_project/logging/config/remote"
2151 httpHeader = {'Content-Type':'application/json'}
2152
2153 try:
2154 if(args.remote_logging == 'view'):
2155 res = session.get(url, headers=httpHeader, verify=False, timeout=30)
2156 elif(args.remote_logging == 'disable'):
2157 res = session.put(url + '/attr/Port', headers=httpHeader, json = {"data": 0}, verify=False, timeout=30)
2158 res = session.put(url + '/attr/Address', headers=httpHeader, json = {"data": ""}, verify=False, timeout=30)
2159 else:
2160 return "Invalid logging remote_logging command"
2161 except(requests.exceptions.Timeout):
2162 return(connectionErrHandler(args.json, "Timeout", None))
2163 return res.text
2164
2165
2166def remoteLoggingConfig(host, args, session):
2167 """
2168 Called by the logging function. Configures remote logging (rsyslog).
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002169
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002170 @param host: string, the hostname or IP address of the bmc
2171 @param args: contains additional arguments used by the logging sub command
2172 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002173 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002174 """
2175
2176 url="https://"+host+"/xyz/openbmc_project/logging/config/remote"
2177 httpHeader = {'Content-Type':'application/json'}
2178
2179 try:
2180 res = session.put(url + '/attr/Port', headers=httpHeader, json = {"data": args.port}, verify=False, timeout=30)
2181 res = session.put(url + '/attr/Address', headers=httpHeader, json = {"data": args.address}, verify=False, timeout=30)
2182 except(requests.exceptions.Timeout):
2183 return(connectionErrHandler(args.json, "Timeout", None))
2184 return res.text
2185
Ratan Gupta9166cd22018-10-01 18:09:40 +05302186
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002187def certificateUpdate(host, args, session):
2188 """
2189 Called by certificate management function. update server/client/authority certificates
2190 Example:
2191 certificate update server https -f cert.pem
2192 certificate update authority ldap -f Root-CA.pem
2193 certificate update client ldap -f cert.pem
2194 @param host: string, the hostname or IP address of the bmc
2195 @param args: contains additional arguments used by the certificate update sub command
2196 @param session: the active session to use
2197 """
2198
2199 httpHeader = {'Content-Type': 'application/octet-stream'}
2200 url = "https://" + host + "/xyz/openbmc_project/certs/" + args.type.lower() + "/" + args.service.lower()
2201 data = open(args.fileloc, 'rb').read()
2202 print("Updating certificate url=" + url)
2203 try:
2204 resp = session.put(url, headers=httpHeader, data=data, verify=False)
2205 except(requests.exceptions.Timeout):
2206 return(connectionErrHandler(args.json, "Timeout", None))
2207 except(requests.exceptions.ConnectionError) as err:
2208 return connectionErrHandler(args.json, "ConnectionError", err)
2209 if resp.status_code != 200:
2210 print(resp.text)
2211 return "Failed to update the certificate"
2212 else:
2213 print("Update complete.")
2214
2215
2216def certificateDelete(host, args, session):
2217 """
2218 Called by certificate management function to delete certificate
2219 Example:
2220 certificate delete server https
2221 certificate delete authority ldap
2222 certificate delete client ldap
2223 @param host: string, the hostname or IP address of the bmc
2224 @param args: contains additional arguments used by the certificate delete sub command
2225 @param session: the active session to use
2226 """
2227
2228 httpHeader = {'Content-Type': 'multipart/form-data'}
2229 url = "https://" + host + "/xyz/openbmc_project/certs/" + args.type.lower() + "/" + args.service.lower()
2230 print("Deleting certificate url=" + url)
2231 try:
2232 resp = session.delete(url, headers=httpHeader)
2233 except(requests.exceptions.Timeout):
2234 return(connectionErrHandler(args.json, "Timeout", None))
2235 except(requests.exceptions.ConnectionError) as err:
2236 return connectionErrHandler(args.json, "ConnectionError", err)
2237 if resp.status_code != 200:
2238 print(resp.text)
2239 return "Failed to delete the certificate"
2240 else:
2241 print("Delete complete.")
2242
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002243
Ratan Gupta9166cd22018-10-01 18:09:40 +05302244def enableLDAP(host, args, session):
2245 """
2246 Called by the ldap function. Configures LDAP.
2247
2248 @param host: string, the hostname or IP address of the bmc
2249 @param args: contains additional arguments used by the ldap subcommand
2250 @param session: the active session to use
2251 @param args.json: boolean, if this flag is set to true, the output will
2252 be provided in json format for programmatic consumption
2253 """
2254
2255 url='https://'+host+'/xyz/openbmc_project/user/ldap/action/CreateConfig'
2256 httpHeader = {'Content-Type':'application/json'}
2257 scope = {
2258 'sub' : 'xyz.openbmc_project.User.Ldap.Create.SearchScope.sub',
2259 'one' : 'xyz.openbmc_project.User.Ldap.Create.SearchScope.one',
2260 'base': 'xyz.openbmc_project.User.Ldap.Create.SearchScope.base'
2261 }
2262
2263 serverType = {
2264 'ActiveDirectory' : 'xyz.openbmc_project.User.Ldap.Create.Type.ActiveDirectory',
2265 'OpenLDAP' : 'xyz.openbmc_project.User.Ldap.Create.Type.OpenLdap'
2266 }
2267
2268 data = {"data": [args.uri, args.bindDN, args.baseDN, args.bindPassword, scope[args.scope], serverType[args.serverType]]}
2269
2270 try:
2271 res = session.post(url, headers=httpHeader, json=data, verify=False, timeout=30)
2272 except(requests.exceptions.Timeout):
2273 return(connectionErrHandler(args.json, "Timeout", None))
2274 except(requests.exceptions.ConnectionError) as err:
2275 return connectionErrHandler(args.json, "ConnectionError", err)
2276
2277 return res.text
2278
2279
2280def disableLDAP(host, args, session):
2281 """
2282 Called by the ldap function. Deletes the LDAP Configuration.
2283
2284 @param host: string, the hostname or IP address of the bmc
2285 @param args: contains additional arguments used by the ldap subcommand
2286 @param session: the active session to use
2287 @param args.json: boolean, if this flag is set to true, the output
2288 will be provided in json format for programmatic consumption
2289 """
2290
2291 url='https://'+host+'/xyz/openbmc_project/user/ldap/config/action/delete'
2292 httpHeader = {'Content-Type':'application/json'}
2293 data = {"data": []}
2294
2295 try:
2296 res = session.post(url, headers=httpHeader, json=data, verify=False, timeout=30)
2297 except(requests.exceptions.Timeout):
2298 return(connectionErrHandler(args.json, "Timeout", None))
2299 except(requests.exceptions.ConnectionError) as err:
2300 return connectionErrHandler(args.json, "ConnectionError", err)
2301
2302 return res.text
2303
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06002304
2305def enableDHCP(host, args, session):
2306
2307 """
2308 Called by the network function. Enables DHCP.
2309
2310 @param host: string, the hostname or IP address of the bmc
2311 @param args: contains additional arguments used by the ldap subcommand
2312 args.json: boolean, if this flag is set to true, the output
2313 will be provided in json format for programmatic consumption
2314 @param session: the active session to use
2315 """
2316
2317 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
2318 "/attr/DHCPEnabled"
2319 httpHeader = {'Content-Type': 'application/json'}
2320 data = "{\"data\": 1 }"
2321 try:
2322 res = session.put(url, headers=httpHeader, data=data, verify=False,
2323 timeout=30)
2324
2325 except(requests.exceptions.Timeout):
2326 return(connectionErrHandler(args.json, "Timeout", None))
2327 except(requests.exceptions.ConnectionError) as err:
2328 return connectionErrHandler(args.json, "ConnectionError", err)
2329 if res.status_code == 403:
2330 return "The specified Interface"+"("+args.Interface+")"+\
2331 " doesn't exist"
2332
2333 return res.text
2334
2335
2336def disableDHCP(host, args, session):
2337 """
2338 Called by the network function. Disables DHCP.
2339
2340 @param host: string, the hostname or IP address of the bmc
2341 @param args: contains additional arguments used by the ldap subcommand
2342 args.json: boolean, if this flag is set to true, the output
2343 will be provided in json format for programmatic consumption
2344 @param session: the active session to use
2345 """
2346
2347 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
2348 "/attr/DHCPEnabled"
2349 httpHeader = {'Content-Type': 'application/json'}
2350 data = "{\"data\": 0 }"
2351 try:
2352 res = session.put(url, headers=httpHeader, data=data, verify=False,
2353 timeout=30)
2354 except(requests.exceptions.Timeout):
2355 return(connectionErrHandler(args.json, "Timeout", None))
2356 except(requests.exceptions.ConnectionError) as err:
2357 return connectionErrHandler(args.json, "ConnectionError", err)
2358 if res.status_code == 403:
2359 return "The specified Interface"+"("+args.Interface+")"+\
2360 " doesn't exist"
2361 return res.text
2362
2363
2364def getHostname(host, args, session):
2365
2366 """
2367 Called by the network function. Prints out the Hostname.
2368
2369 @param host: string, the hostname or IP address of the bmc
2370 @param args: contains additional arguments used by the ldap subcommand
2371 args.json: boolean, if this flag is set to true, the output
2372 will be provided in json format for programmatic consumption
2373 @param session: the active session to use
2374 """
2375
2376 url = "https://"+host+"/xyz/openbmc_project/network/config/attr/HostName"
2377 httpHeader = {'Content-Type': 'application/json'}
2378
2379 try:
2380 res = session.get(url, headers=httpHeader, verify=False, timeout=40)
2381 except(requests.exceptions.Timeout):
2382 return(connectionErrHandler(args.json, "Timeout", None))
2383 except(requests.exceptions.ConnectionError) as err:
2384 return connectionErrHandler(args.json, "ConnectionError", err)
2385
2386 return res.text
2387
2388
2389def setHostname(host, args, session):
2390 """
2391 Called by the network function. Sets the Hostname.
2392
2393 @param host: string, the hostname or IP address of the bmc
2394 @param args: contains additional arguments used by the ldap subcommand
2395 args.json: boolean, if this flag is set to true, the output
2396 will be provided in json format for programmatic consumption
2397 @param session: the active session to use
2398 """
2399
2400 url = "https://"+host+"/xyz/openbmc_project/network/config/attr/HostName"
2401 httpHeader = {'Content-Type': 'application/json'}
2402
2403 data = {"data": args.HostName}
2404
2405 try:
2406 res = session.put(url, headers=httpHeader, json=data, verify=False,
2407 timeout=30)
2408 except(requests.exceptions.Timeout):
2409 return(connectionErrHandler(args.json, "Timeout", None))
2410 except(requests.exceptions.ConnectionError) as err:
2411 return connectionErrHandler(args.json, "ConnectionError", err)
2412
2413 return res.text
2414
2415
2416def getDomainName(host, args, session):
2417
2418 """
2419 Called by the network function. Prints out the DomainName.
2420
2421 @param host: string, the hostname or IP address of the bmc
2422 @param args: contains additional arguments used by the ldap subcommand
2423 args.json: boolean, if this flag is set to true, the output
2424 will be provided in json format for programmatic consumption
2425 @param session: the active session to use
2426 """
2427
2428 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
2429 "/attr/DomainName"
2430 httpHeader = {'Content-Type': 'application/json'}
2431
2432 try:
2433 res = session.get(url, headers=httpHeader, verify=False, timeout=40)
2434 except(requests.exceptions.Timeout):
2435 return(connectionErrHandler(args.json, "Timeout", None))
2436 except(requests.exceptions.ConnectionError) as err:
2437 return connectionErrHandler(args.json, "ConnectionError", err)
2438 if res.status_code == 404:
2439 return "The specified Interface"+"("+args.Interface+")"+\
2440 " doesn't exist"
2441
2442 return res.text
2443
2444
2445def setDomainName(host, args, session):
2446 """
2447 Called by the network function. Sets the DomainName.
2448
2449 @param host: string, the hostname or IP address of the bmc
2450 @param args: contains additional arguments used by the ldap subcommand
2451 args.json: boolean, if this flag is set to true, the output
2452 will be provided in json format for programmatic consumption
2453 @param session: the active session to use
2454 """
2455
2456 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
2457 "/attr/DomainName"
2458 httpHeader = {'Content-Type': 'application/json'}
2459
2460 data = {"data": args.DomainName.split(",")}
2461
2462 try:
2463 res = session.put(url, headers=httpHeader, json=data, verify=False,
2464 timeout=30)
2465 except(requests.exceptions.Timeout):
2466 return(connectionErrHandler(args.json, "Timeout", None))
2467 except(requests.exceptions.ConnectionError) as err:
2468 return connectionErrHandler(args.json, "ConnectionError", err)
2469 if res.status_code == 403:
2470 return "The specified Interface"+"("+args.Interface+")"+\
2471 " doesn't exist"
2472
2473 return res.text
2474
2475
2476def getMACAddress(host, args, session):
2477
2478 """
2479 Called by the network function. Prints out the MACAddress.
2480
2481 @param host: string, the hostname or IP address of the bmc
2482 @param args: contains additional arguments used by the ldap subcommand
2483 args.json: boolean, if this flag is set to true, the output
2484 will be provided in json format for programmatic consumption
2485 @param session: the active session to use
2486 """
2487
2488 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
2489 "/attr/MACAddress"
2490 httpHeader = {'Content-Type': 'application/json'}
2491
2492 try:
2493 res = session.get(url, headers=httpHeader, verify=False, timeout=40)
2494 except(requests.exceptions.Timeout):
2495 return(connectionErrHandler(args.json, "Timeout", None))
2496 except(requests.exceptions.ConnectionError) as err:
2497 return connectionErrHandler(args.json, "ConnectionError", err)
2498 if res.status_code == 404:
2499 return "The specified Interface"+"("+args.Interface+")"+\
2500 " doesn't exist"
2501
2502 return res.text
2503
2504
2505def setMACAddress(host, args, session):
2506 """
2507 Called by the network function. Sets the MACAddress.
2508
2509 @param host: string, the hostname or IP address of the bmc
2510 @param args: contains additional arguments used by the ldap subcommand
2511 args.json: boolean, if this flag is set to true, the output
2512 will be provided in json format for programmatic consumption
2513 @param session: the active session to use
2514 """
2515
2516 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
2517 "/attr/MACAddress"
2518 httpHeader = {'Content-Type': 'application/json'}
2519
2520 data = {"data": args.MACAddress}
2521
2522 try:
2523 res = session.put(url, headers=httpHeader, json=data, verify=False,
2524 timeout=30)
2525 except(requests.exceptions.Timeout):
2526 return(connectionErrHandler(args.json, "Timeout", None))
2527 except(requests.exceptions.ConnectionError) as err:
2528 return connectionErrHandler(args.json, "ConnectionError", err)
2529 if res.status_code == 403:
2530 return "The specified Interface"+"("+args.Interface+")"+\
2531 " doesn't exist"
2532
2533 return res.text
2534
2535
2536def getDefaultGateway(host, args, session):
2537
2538 """
2539 Called by the network function. Prints out the DefaultGateway.
2540
2541 @param host: string, the hostname or IP address of the bmc
2542 @param args: contains additional arguments used by the ldap subcommand
2543 args.json: boolean, if this flag is set to true, the output
2544 will be provided in json format for programmatic consumption
2545 @param session: the active session to use
2546 """
2547
2548 url = "https://"+host+"/xyz/openbmc_project/network/config/attr/DefaultGateway"
2549 httpHeader = {'Content-Type': 'application/json'}
2550
2551 try:
2552 res = session.get(url, headers=httpHeader, verify=False, timeout=40)
2553 except(requests.exceptions.Timeout):
2554 return(connectionErrHandler(args.json, "Timeout", None))
2555 except(requests.exceptions.ConnectionError) as err:
2556 return connectionErrHandler(args.json, "ConnectionError", err)
2557 if res.status_code == 404:
2558 return "Failed to get Default Gateway info!!"
2559
2560 return res.text
2561
2562
2563def setDefaultGateway(host, args, session):
2564 """
2565 Called by the network function. Sets the DefaultGateway.
2566
2567 @param host: string, the hostname or IP address of the bmc
2568 @param args: contains additional arguments used by the ldap subcommand
2569 args.json: boolean, if this flag is set to true, the output
2570 will be provided in json format for programmatic consumption
2571 @param session: the active session to use
2572 """
2573
2574 url = "https://"+host+"/xyz/openbmc_project/network/config/attr/DefaultGateway"
2575 httpHeader = {'Content-Type': 'application/json'}
2576
2577 data = {"data": args.DefaultGW}
2578
2579 try:
2580 res = session.put(url, headers=httpHeader, json=data, verify=False,
2581 timeout=30)
2582 except(requests.exceptions.Timeout):
2583 return(connectionErrHandler(args.json, "Timeout", None))
2584 except(requests.exceptions.ConnectionError) as err:
2585 return connectionErrHandler(args.json, "ConnectionError", err)
2586 if res.status_code == 403:
2587 return "Failed to set Default Gateway!!"
2588
2589 return res.text
2590
2591
2592def viewNWConfig(host, args, session):
2593 """
2594 Called by the ldap function. Prints out network configured properties
2595
2596 @param host: string, the hostname or IP address of the bmc
2597 @param args: contains additional arguments used by the ldap subcommand
2598 args.json: boolean, if this flag is set to true, the output
2599 will be provided in json format for programmatic consumption
2600 @param session: the active session to use
2601 @return returns LDAP's configured properties.
2602 """
2603 url = "https://"+host+"/xyz/openbmc_project/network/enumerate"
2604 httpHeader = {'Content-Type': 'application/json'}
2605 try:
2606 res = session.get(url, headers=httpHeader, verify=False, timeout=40)
2607 except(requests.exceptions.Timeout):
2608 return(connectionErrHandler(args.json, "Timeout", None))
2609 except(requests.exceptions.ConnectionError) as err:
2610 return connectionErrHandler(args.json, "ConnectionError", err)
2611 except(requests.exceptions.RequestException) as err:
2612 return connectionErrHandler(args.json, "RequestException", err)
2613 if res.status_code == 404:
2614 return "LDAP server config has not been created"
2615 return res.text
2616
2617
2618def getDNS(host, args, session):
2619
2620 """
2621 Called by the network function. Prints out DNS servers on the interface
2622
2623 @param host: string, the hostname or IP address of the bmc
2624 @param args: contains additional arguments used by the ldap subcommand
2625 args.json: boolean, if this flag is set to true, the output
2626 will be provided in json format for programmatic consumption
2627 @param session: the active session to use
2628 """
2629
2630 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
2631 + "/attr/Nameservers"
2632 httpHeader = {'Content-Type': 'application/json'}
2633
2634 try:
2635 res = session.get(url, headers=httpHeader, verify=False, timeout=40)
2636 except(requests.exceptions.Timeout):
2637 return(connectionErrHandler(args.json, "Timeout", None))
2638 except(requests.exceptions.ConnectionError) as err:
2639 return connectionErrHandler(args.json, "ConnectionError", err)
2640 if res.status_code == 404:
2641 return "The specified Interface"+"("+args.Interface+")" + \
2642 " doesn't exist"
2643
2644 return res.text
2645
2646
2647def setDNS(host, args, session):
2648 """
2649 Called by the network function. Sets DNS servers on the interface.
2650
2651 @param host: string, the hostname or IP address of the bmc
2652 @param args: contains additional arguments used by the ldap subcommand
2653 args.json: boolean, if this flag is set to true, the output
2654 will be provided in json format for programmatic consumption
2655 @param session: the active session to use
2656 """
2657
2658 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
2659 + "/attr/Nameservers"
2660 httpHeader = {'Content-Type': 'application/json'}
2661
2662 data = {"data": args.DNSServers.split(",")}
2663
2664 try:
2665 res = session.put(url, headers=httpHeader, json=data, verify=False,
2666 timeout=30)
2667 except(requests.exceptions.Timeout):
2668 return(connectionErrHandler(args.json, "Timeout", None))
2669 except(requests.exceptions.ConnectionError) as err:
2670 return connectionErrHandler(args.json, "ConnectionError", err)
2671 if res.status_code == 403:
2672 return "The specified Interface"+"("+args.Interface+")" +\
2673 " doesn't exist"
2674
2675 return res.text
2676
2677
2678def getNTP(host, args, session):
2679
2680 """
2681 Called by the network function. Prints out NTP servers on the interface
2682
2683 @param host: string, the hostname or IP address of the bmc
2684 @param args: contains additional arguments used by the ldap subcommand
2685 args.json: boolean, if this flag is set to true, the output
2686 will be provided in json format for programmatic consumption
2687 @param session: the active session to use
2688 """
2689
2690 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
2691 + "/attr/NTPServers"
2692 httpHeader = {'Content-Type': 'application/json'}
2693
2694 try:
2695 res = session.get(url, headers=httpHeader, verify=False, timeout=40)
2696 except(requests.exceptions.Timeout):
2697 return(connectionErrHandler(args.json, "Timeout", None))
2698 except(requests.exceptions.ConnectionError) as err:
2699 return connectionErrHandler(args.json, "ConnectionError", err)
2700 if res.status_code == 404:
2701 return "The specified Interface"+"("+args.Interface+")" + \
2702 " doesn't exist"
2703
2704 return res.text
2705
2706
2707def setNTP(host, args, session):
2708 """
2709 Called by the network function. Sets NTP servers on the interface.
2710
2711 @param host: string, the hostname or IP address of the bmc
2712 @param args: contains additional arguments used by the ldap subcommand
2713 args.json: boolean, if this flag is set to true, the output
2714 will be provided in json format for programmatic consumption
2715 @param session: the active session to use
2716 """
2717
2718 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
2719 + "/attr/NTPServers"
2720 httpHeader = {'Content-Type': 'application/json'}
2721
2722 data = {"data": args.NTPServers.split(",")}
2723
2724 try:
2725 res = session.put(url, headers=httpHeader, json=data, verify=False,
2726 timeout=30)
2727 except(requests.exceptions.Timeout):
2728 return(connectionErrHandler(args.json, "Timeout", None))
2729 except(requests.exceptions.ConnectionError) as err:
2730 return connectionErrHandler(args.json, "ConnectionError", err)
2731 if res.status_code == 403:
2732 return "The specified Interface"+"("+args.Interface+")" +\
2733 " doesn't exist"
2734
2735 return res.text
2736
2737
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06002738def addIP(host, args, session):
2739 """
2740 Called by the network function. Configures IP address on given interface
2741
2742 @param host: string, the hostname or IP address of the bmc
2743 @param args: contains additional arguments used by the ldap subcommand
2744 args.json: boolean, if this flag is set to true, the output
2745 will be provided in json format for programmatic consumption
2746 @param session: the active session to use
2747 """
2748
2749 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
2750 + "/action/IP"
2751 httpHeader = {'Content-Type': 'application/json'}
2752 protocol = {
2753 'ipv4': 'xyz.openbmc_project.Network.IP.Protocol.IPv4',
2754 'ipv6': 'xyz.openbmc_project.Network.IP.Protocol.IPv6'
2755 }
2756
2757 data = {"data": [protocol[args.type], args.address, int(args.prefixLength),
2758 args.gateway]}
2759
2760 try:
2761 res = session.post(url, headers=httpHeader, json=data, verify=False,
2762 timeout=30)
2763 except(requests.exceptions.Timeout):
2764 return(connectionErrHandler(args.json, "Timeout", None))
2765 except(requests.exceptions.ConnectionError) as err:
2766 return connectionErrHandler(args.json, "ConnectionError", err)
2767 if res.status_code == 404:
2768 return "The specified Interface" + "(" + args.Interface + ")" +\
2769 " doesn't exist"
2770
2771 return res.text
2772
2773
2774def getIP(host, args, session):
2775 """
2776 Called by the network function. Prints out IP address of given interface
2777
2778 @param host: string, the hostname or IP address of the bmc
2779 @param args: contains additional arguments used by the ldap subcommand
2780 args.json: boolean, if this flag is set to true, the output
2781 will be provided in json format for programmatic consumption
2782 @param session: the active session to use
2783 """
2784
2785 url = "https://" + host+"/xyz/openbmc_project/network/" + args.Interface +\
2786 "/enumerate"
2787 httpHeader = {'Content-Type': 'application/json'}
2788 try:
2789 res = session.get(url, headers=httpHeader, verify=False, timeout=40)
2790 except(requests.exceptions.Timeout):
2791 return(connectionErrHandler(args.json, "Timeout", None))
2792 except(requests.exceptions.ConnectionError) as err:
2793 return connectionErrHandler(args.json, "ConnectionError", err)
2794 if res.status_code == 404:
2795 return "The specified Interface" + "(" + args.Interface + ")" +\
2796 " doesn't exist"
2797
2798 return res.text
2799
2800
2801def deleteIP(host, args, session):
2802 """
2803 Called by the network function. Deletes the IP address from given Interface
2804
2805 @param host: string, the hostname or IP address of the bmc
2806 @param args: contains additional arguments used by the ldap subcommand
2807 @param session: the active session to use
2808 @param args.json: boolean, if this flag is set to true, the output
2809 will be provided in json format for programmatic consumption
2810 """
2811
2812 url = "https://"+host+"/xyz/openbmc_project/network/" + args.Interface+\
2813 "/enumerate"
2814 httpHeader = {'Content-Type':'application/json'}
2815 data = {"data": []}
2816 try:
2817 res = session.get(url, headers=httpHeader, verify=False, timeout=40)
2818 except(requests.exceptions.Timeout):
2819 return(connectionErrHandler(args.json, "Timeout", None))
2820 except(requests.exceptions.ConnectionError) as err:
2821 return connectionErrHandler(args.json, "ConnectionError", err)
2822 if res.status_code == 404:
2823 return "The specified Interface" + "(" + args.Interface + ")" +\
2824 " doesn't exist"
2825 objDict = json.loads(res.text)
2826 if not objDict['data']:
2827 return "No object found for given address on given Interface"
2828
2829 for obj in objDict['data']:
2830 if args.address in objDict['data'][obj]['Address']:
2831 url = "https://"+host+obj+"/action/delete"
2832 try:
2833 res = session.post(url, headers=httpHeader, json=data,
2834 verify=False, timeout=30)
2835 except(requests.exceptions.Timeout):
2836 return(connectionErrHandler(args.json, "Timeout", None))
2837 except(requests.exceptions.ConnectionError) as err:
2838 return connectionErrHandler(args.json, "ConnectionError", err)
2839 return res.text
2840 else:
2841 continue
2842 return "No object found for given address on given Interface"
2843
2844
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06002845def addVLAN(host, args, session):
2846 """
2847 Called by the network function. Creates VLAN on given interface.
2848
2849 @param host: string, the hostname or IP address of the bmc
2850 @param args: contains additional arguments used by the ldap subcommand
2851 args.json: boolean, if this flag is set to true, the output
2852 will be provided in json format for programmatic consumption
2853 @param session: the active session to use
2854 """
2855
2856 url = "https://" + host+"/xyz/openbmc_project/network/action/VLAN"
2857 httpHeader = {'Content-Type': 'application/json'}
2858
2859 data = {"data": [args.Interface,args.Identifier]}
2860
2861 try:
2862 res = session.post(url, headers=httpHeader, json=data, verify=False,
2863 timeout=30)
2864 except(requests.exceptions.Timeout):
2865 return(connectionErrHandler(args.json, "Timeout", None))
2866 except(requests.exceptions.ConnectionError) as err:
2867 return connectionErrHandler(args.json, "ConnectionError", err)
2868 if res.status_code == 400:
2869 return "The specified Interface" + "(" + args.Interface + ")" +\
2870 " doesn't exist"
2871
2872 return res.text
2873
2874
2875def deleteVLAN(host, args, session):
2876 """
2877 Called by the network function. Creates VLAN on given interface.
2878
2879 @param host: string, the hostname or IP address of the bmc
2880 @param args: contains additional arguments used by the ldap subcommand
2881 args.json: boolean, if this flag is set to true, the output
2882 will be provided in json format for programmatic consumption
2883 @param session: the active session to use
2884 """
2885
2886 url = "https://" + host+"/xyz/openbmc_project/network/"+args.Interface+"/action/delete"
2887 httpHeader = {'Content-Type':'application/json'}
2888 data = {"data": []}
2889
2890 try:
2891 res = session.post(url, headers=httpHeader, json=data, verify=False, timeout=30)
2892 except(requests.exceptions.Timeout):
2893 return(connectionErrHandler(args.json, "Timeout", None))
2894 except(requests.exceptions.ConnectionError) as err:
2895 return connectionErrHandler(args.json, "ConnectionError", err)
2896 if res.status_code == 404:
2897 return "The specified VLAN"+"("+args.Interface+"_"+args.Identifier\
2898 +")" +" doesn't exist"
2899
2900 return res.text
2901
2902
2903def viewDHCPConfig(host, args, session):
2904 """
2905 Called by the network function. Shows DHCP configured Properties.
2906
2907 @param host: string, the hostname or IP address of the bmc
2908 @param args: contains additional arguments used by the ldap subcommand
2909 args.json: boolean, if this flag is set to true, the output
2910 will be provided in json format for programmatic consumption
2911 @param session: the active session to use
2912 """
2913
2914 url="https://"+host+"/xyz/openbmc_project/network/config/dhcp"
2915 httpHeader = {'Content-Type':'application/json'}
2916
2917 try:
2918 res = session.get(url, headers=httpHeader, verify=False, timeout=30)
2919 except(requests.exceptions.Timeout):
2920 return(connectionErrHandler(args.json, "Timeout", None))
2921 except(requests.exceptions.ConnectionError) as err:
2922 return connectionErrHandler(args.json, "ConnectionError", err)
2923
2924 return res.text
2925
2926
2927def configureDHCP(host, args, session):
2928 """
2929 Called by the network function. Configures/updates DHCP Properties.
2930
2931 @param host: string, the hostname or IP address of the bmc
2932 @param args: contains additional arguments used by the ldap subcommand
2933 args.json: boolean, if this flag is set to true, the output
2934 will be provided in json format for programmatic consumption
2935 @param session: the active session to use
2936 """
2937
2938 httpHeader = {'Content-Type': 'application/json'}
2939
2940 try:
2941 url="https://"+host+"/xyz/openbmc_project/network/config/dhcp"
2942 if(args.DNSEnabled == True):
2943 data = '{"data": 1}'
2944 else:
2945 data = '{"data": 0}'
2946 res = session.put(url + '/attr/DNSEnabled', headers=httpHeader,
2947 data=data, verify=False, timeout=30)
2948 if(args.HostNameEnabled == True):
2949 data = '{"data": 1}'
2950 else:
2951 data = '{"data": 0}'
2952 res = session.put(url + '/attr/HostNameEnabled', headers=httpHeader,
2953 data=data, verify=False, timeout=30)
2954 if(args.NTPEnabled == True):
2955 data = '{"data": 1}'
2956 else:
2957 data = '{"data": 0}'
2958 res = session.put(url + '/attr/NTPEnabled', headers=httpHeader,
2959 data=data, verify=False, timeout=30)
2960 if(args.SendHostNameEnabled == True):
2961 data = '{"data": 1}'
2962 else:
2963 data = '{"data": 0}'
2964 res = session.put(url + '/attr/SendHostNameEnabled', headers=httpHeader,
2965 data=data, verify=False, timeout=30)
2966 except(requests.exceptions.Timeout):
2967 return(connectionErrHandler(args.json, "Timeout", None))
2968 except(requests.exceptions.ConnectionError) as err:
2969 return connectionErrHandler(args.json, "ConnectionError", err)
2970
2971 return res.text
2972
2973
2974def nwReset(host, args, session):
2975
2976 """
2977 Called by the network function. Resets networks setting to factory defaults.
2978
2979 @param host: string, the hostname or IP address of the bmc
2980 @param args: contains additional arguments used by the ldap subcommand
2981 args.json: boolean, if this flag is set to true, the output
2982 will be provided in json format for programmatic consumption
2983 @param session: the active session to use
2984 """
2985
2986 url = "https://"+host+"/xyz/openbmc_project/network/action/Reset"
2987 httpHeader = {'Content-Type': 'application/json'}
2988 data = '{"data":[] }'
2989 try:
2990 res = session.post(url, headers=httpHeader, data=data, verify=False,
2991 timeout=30)
2992
2993 except(requests.exceptions.Timeout):
2994 return(connectionErrHandler(args.json, "Timeout", None))
2995 except(requests.exceptions.ConnectionError) as err:
2996 return connectionErrHandler(args.json, "ConnectionError", err)
2997
2998 return res.text
2999
3000
Ratan Guptafeee6372018-10-17 23:25:51 +05303001def createPrivilegeMapping(host, args, session):
3002 """
3003 Called by the ldap function. Creates the group and the privilege mapping.
3004
3005 @param host: string, the hostname or IP address of the bmc
3006 @param args: contains additional arguments used by the ldap subcommand
3007 @param session: the active session to use
3008 @param args.json: boolean, if this flag is set to true, the output
3009 will be provided in json format for programmatic consumption
3010 """
3011
3012 url = 'https://'+host+'/xyz/openbmc_project/user/ldap/action/Create'
3013 httpHeader = {'Content-Type':'application/json'}
3014
3015 data = {"data": [args.groupName,args.privilege]}
3016
3017 try:
3018 res = session.post(url, headers=httpHeader, json = data, verify=False, timeout=30)
3019 except(requests.exceptions.Timeout):
3020 return(connectionErrHandler(args.json, "Timeout", None))
3021 except(requests.exceptions.ConnectionError) as err:
3022 return connectionErrHandler(args.json, "ConnectionError", err)
3023 return res.text
3024
3025def listPrivilegeMapping(host, args, session):
3026 """
3027 Called by the ldap function. Lists the group and the privilege mapping.
3028
3029 @param host: string, the hostname or IP address of the bmc
3030 @param args: contains additional arguments used by the ldap subcommand
3031 @param session: the active session to use
3032 @param args.json: boolean, if this flag is set to true, the output
3033 will be provided in json format for programmatic consumption
3034 """
3035 url = 'https://'+host+'/xyz/openbmc_project/user/ldap/enumerate'
3036 httpHeader = {'Content-Type': 'application/json'}
3037 data = {"data": []}
3038
3039 try:
3040 res = session.get(url, headers=httpHeader, json = data, verify=False, timeout=30)
3041 except(requests.exceptions.Timeout):
3042 return(connectionErrHandler(args.json, "Timeout", None))
3043 except(requests.exceptions.ConnectionError) as err:
3044 return connectionErrHandler(args.json, "ConnectionError", err)
3045 return res.text
3046
3047def deletePrivilegeMapping(host, args, session):
3048 """
3049 Called by the ldap function. Deletes the mapping associated with the group.
3050
3051 @param host: string, the hostname or IP address of the bmc
3052 @param args: contains additional arguments used by the ldap subcommand
3053 @param session: the active session to use
3054 @param args.json: boolean, if this flag is set to true, the output
3055 will be provided in json format for programmatic consumption
3056 """
3057 (ldapNameSpaceObjects) = listPrivilegeMapping(host, args, session)
3058 ldapNameSpaceObjects = json.loads(ldapNameSpaceObjects)["data"]
3059 path = ''
3060
3061 # not interested in the config objet
3062 ldapNameSpaceObjects.pop('/xyz/openbmc_project/user/ldap/config', None)
3063
3064 # search for the object having the mapping for the given group
3065 for key,value in ldapNameSpaceObjects.items():
3066 if value['GroupName'] == args.groupName:
3067 path = key
3068 break
3069
3070 if path == '':
3071 return "No privilege mapping found for this group."
3072
3073 # delete the object
3074 url = 'https://'+host+path+'/action/delete'
3075 httpHeader = {'Content-Type': 'application/json'}
3076 data = {"data": []}
3077
3078 try:
3079 res = session.post(url, headers=httpHeader, json = data, verify=False, timeout=30)
3080 except(requests.exceptions.Timeout):
3081 return(connectionErrHandler(args.json, "Timeout", None))
3082 except(requests.exceptions.ConnectionError) as err:
3083 return connectionErrHandler(args.json, "ConnectionError", err)
3084 return res.text
Ratan Gupta9166cd22018-10-01 18:09:40 +05303085
Sivas SRR78835272018-11-27 05:27:19 -06003086def deleteAllPrivilegeMapping(host, args, session):
3087 """
3088 Called by the ldap function. Deletes all the privilege mapping and group defined.
3089 @param host: string, the hostname or IP address of the bmc
3090 @param args: contains additional arguments used by the ldap subcommand
3091 @param session: the active session to use
3092 @param args.json: boolean, if this flag is set to true, the output
3093 will be provided in json format for programmatic consumption
3094 """
3095 ldapNameSpaceObjects = listPrivilegeMapping(host, args, session)
3096 ldapNameSpaceObjects = json.loads(ldapNameSpaceObjects)["data"]
3097 path = ''
3098
3099 # Remove the config object.
3100 ldapNameSpaceObjects.pop('/xyz/openbmc_project/user/ldap/config', None)
3101 httpHeader = {'Content-Type': 'application/json'}
3102 data = {"data": []}
3103
3104 try:
3105 # search for GroupName property and delete if it is available.
3106 for path in ldapNameSpaceObjects.keys():
3107 # delete the object
3108 url = 'https://'+host+path+'/action/delete'
3109 res = session.post(url, headers=httpHeader, json = data, verify=False, timeout=30)
3110 except(requests.exceptions.Timeout):
3111 return(connectionErrHandler(args.json, "Timeout", None))
3112 except(requests.exceptions.ConnectionError) as err:
3113 return connectionErrHandler(args.json, "ConnectionError", err)
3114 return res.text
3115
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06003116def viewLDAPConfig(host, args, session):
3117 """
3118 Called by the ldap function. Prints out LDAP's configured properties
3119
3120 @param host: string, the hostname or IP address of the bmc
3121 @param args: contains additional arguments used by the ldap subcommand
3122 args.json: boolean, if this flag is set to true, the output
3123 will be provided in json format for programmatic consumption
3124 @param session: the active session to use
3125 @return returns LDAP's configured properties.
3126 """
3127 url = "https://"+host+"/xyz/openbmc_project/user/ldap/config"
3128 httpHeader = {'Content-Type': 'application/json'}
3129 try:
3130 res = session.get(url, headers=httpHeader, verify=False, timeout=40)
3131 except(requests.exceptions.Timeout):
3132 return(connectionErrHandler(args.json, "Timeout", None))
3133 except(requests.exceptions.ConnectionError) as err:
3134 return connectionErrHandler(args.json, "ConnectionError", err)
3135 except(requests.exceptions.RequestException) as err:
3136 return connectionErrHandler(args.json, "RequestException", err)
3137 if res.status_code == 404:
3138 return "LDAP server config has not been created"
3139 return res.text
3140
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003141def str2bool(v):
3142 if v.lower() in ('yes', 'true', 't', 'y', '1'):
3143 return True
3144 elif v.lower() in ('no', 'false', 'f', 'n', '0'):
3145 return False
3146 else:
3147 raise argparse.ArgumentTypeError('Boolean value expected.')
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06003148
Matt Spinler7d426c22018-09-24 14:42:07 -05003149def localUsers(host, args, session):
3150 """
3151 Enables and disables local BMC users.
3152
3153 @param host: string, the hostname or IP address of the bmc
3154 @param args: contains additional arguments used by the logging sub command
3155 @param session: the active session to use
3156 """
3157
3158 httpHeader = {'Content-Type':'application/json'}
3159 url="https://{hostname}/xyz/openbmc_project/user/enumerate".format(hostname=host)
3160 try:
3161 res = session.get(url, headers=httpHeader, verify=False, timeout=40)
3162 except(requests.exceptions.Timeout):
3163 return(connectionErrHandler(args.json, "Timeout", None))
3164 usersDict = json.loads(res.text)
3165
3166 if not usersDict['data']:
3167 return "No users found"
3168
3169 output = ""
3170 for user in usersDict['data']:
Matt Spinler015adc22018-10-23 14:30:19 -05003171
3172 # Skip LDAP and another non-local users
3173 if 'UserEnabled' not in usersDict['data'][user]:
3174 continue
3175
Matt Spinler7d426c22018-09-24 14:42:07 -05003176 name = user.split('/')[-1]
3177 url = "https://{hostname}{user}/attr/UserEnabled".format(hostname=host, user=user)
3178
3179 if args.local_users == "queryenabled":
3180 try:
3181 res = session.get(url, headers=httpHeader,verify=False, timeout=30)
3182 except(requests.exceptions.Timeout):
3183 return(connectionErrHandler(args.json, "Timeout", None))
3184
3185 result = json.loads(res.text)
3186 output += ("User: {name} Enabled: {result}\n").format(name=name, result=result['data'])
3187
3188 elif args.local_users in ["enableall", "disableall"]:
3189 action = ""
3190 if args.local_users == "enableall":
3191 data = '{"data": true}'
3192 action = "Enabling"
3193 else:
3194 data = '{"data": false}'
3195 action = "Disabling"
3196
3197 output += "{action} {name}\n".format(action=action, name=name)
3198
3199 try:
3200 resp = session.put(url, headers=httpHeader, data=data, verify=False, timeout=30)
3201 except(requests.exceptions.Timeout):
3202 return connectionErrHandler(args.json, "Timeout", None)
3203 except(requests.exceptions.ConnectionError) as err:
3204 return connectionErrHandler(args.json, "ConnectionError", err)
3205 else:
3206 return "Invalid local users argument"
3207
3208 return output
3209
Marri Devender Rao2c2a5162018-11-05 08:57:11 -06003210def setPassword(host, args, session):
3211 """
3212 Set local user password
3213 @param host: string, the hostname or IP address of the bmc
3214 @param args: contains additional arguments used by the logging sub
3215 command
3216 @param session: the active session to use
3217 @param args.json: boolean, if this flag is set to true, the output
3218 will be provided in json format for programmatic consumption
3219 @return: Session object
3220 """
3221 url = "https://" + host + "/xyz/openbmc_project/user/" + args.user + \
3222 "/action/SetPassword"
3223 httpHeader = {'Content-Type': 'application/json'}
3224 try:
3225 res = session.post(url, headers=httpHeader,
3226 json={"data": [args.password]}, verify=False,
3227 timeout=30)
3228 except(requests.exceptions.Timeout):
3229 return(connectionErrHandler(args.json, "Timeout", None))
3230 except(requests.exceptions.ConnectionError) as err:
3231 return connectionErrHandler(args.json, "ConnectionError", err)
3232 except(requests.exceptions.RequestException) as err:
3233 return connectionErrHandler(args.json, "RequestException", err)
3234 return res.text
3235
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003236def createCommandParser():
Justin Thalere412dc22018-01-12 16:28:24 -06003237 """
3238 creates the parser for the command line along with help for each command and subcommand
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003239
Justin Thalere412dc22018-01-12 16:28:24 -06003240 @return: returns the parser for the command line
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003241 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003242 parser = argparse.ArgumentParser(description='Process arguments')
Justin Thalere412dc22018-01-12 16:28:24 -06003243 parser.add_argument("-H", "--host", help='A hostname or IP for the BMC')
3244 parser.add_argument("-U", "--user", help='The username to login with')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003245 group = parser.add_mutually_exclusive_group()
3246 group.add_argument("-A", "--askpw", action='store_true', help='prompt for password')
3247 group.add_argument("-P", "--PW", help='Provide the password in-line')
3248 parser.add_argument('-j', '--json', action='store_true', help='output json data only')
3249 parser.add_argument('-t', '--policyTableLoc', help='The location of the policy table to parse alerts')
3250 parser.add_argument('-c', '--CerFormat', action='store_true', help=argparse.SUPPRESS)
3251 parser.add_argument('-T', '--procTime', action='store_true', help= argparse.SUPPRESS)
Justin Thalere412dc22018-01-12 16:28:24 -06003252 parser.add_argument('-V', '--version', action='store_true', help='Display the version number of the openbmctool')
3253 subparsers = parser.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003254
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003255 #fru command
3256 parser_inv = subparsers.add_parser("fru", help='Work with platform inventory')
Justin Thalere412dc22018-01-12 16:28:24 -06003257 inv_subparser = parser_inv.add_subparsers(title='subcommands', description='valid inventory actions', help="valid inventory actions", dest='command')
Justin Thaler53bf2f12018-07-16 14:05:32 -05003258 inv_subparser.required = True
3259 #fru print
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003260 inv_print = inv_subparser.add_parser("print", help="prints out a list of all FRUs")
3261 inv_print.set_defaults(func=fruPrint)
3262 #fru list [0....n]
3263 inv_list = inv_subparser.add_parser("list", help="print out details on selected FRUs. Specifying no items will list the entire inventory")
3264 inv_list.add_argument('items', nargs='?', help="print out details on selected FRUs. Specifying no items will list the entire inventory")
3265 inv_list.set_defaults(func=fruList)
3266 #fru status
3267 inv_status = inv_subparser.add_parser("status", help="prints out the status of all FRUs")
Justin Thalere412dc22018-01-12 16:28:24 -06003268 inv_status.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003269 inv_status.set_defaults(func=fruStatus)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003270
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003271 #sensors command
3272 parser_sens = subparsers.add_parser("sensors", help="Work with platform sensors")
Justin Thalere412dc22018-01-12 16:28:24 -06003273 sens_subparser=parser_sens.add_subparsers(title='subcommands', description='valid sensor actions', help='valid sensor actions', dest='command')
Justin Thaler53bf2f12018-07-16 14:05:32 -05003274 sens_subparser.required = True
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003275 #sensor print
3276 sens_print= sens_subparser.add_parser('print', help="prints out a list of all Sensors.")
3277 sens_print.set_defaults(func=sensor)
3278 #sensor list[0...n]
3279 sens_list=sens_subparser.add_parser("list", help="Lists all Sensors in the platform. Specify a sensor for full details. ")
3280 sens_list.add_argument("sensNum", nargs='?', help="The Sensor number to get full details on" )
3281 sens_list.set_defaults(func=sensor)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003282
3283
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003284 #sel command
3285 parser_sel = subparsers.add_parser("sel", help="Work with platform alerts")
Justin Thalere412dc22018-01-12 16:28:24 -06003286 sel_subparser = parser_sel.add_subparsers(title='subcommands', description='valid SEL actions', help = 'valid SEL actions', dest='command')
Justin Thaler53bf2f12018-07-16 14:05:32 -05003287 sel_subparser.required = True
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003288 #sel print
3289 sel_print = sel_subparser.add_parser("print", help="prints out a list of all sels in a condensed list")
3290 sel_print.add_argument('-d', '--devdebug', action='store_true', help=argparse.SUPPRESS)
3291 sel_print.add_argument('-v', '--verbose', action='store_true', help="Changes the output to being very verbose")
3292 sel_print.add_argument('-f', '--fileloc', help='Parse a file instead of the BMC output')
3293 sel_print.set_defaults(func=selPrint)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003294
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003295 #sel list
3296 sel_list = sel_subparser.add_parser("list", help="Lists all SELs in the platform. Specifying a specific number will pull all the details for that individual SEL")
3297 sel_list.add_argument("selNum", nargs='?', type=int, help="The SEL entry to get details on")
3298 sel_list.set_defaults(func=selList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003299
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003300 sel_get = sel_subparser.add_parser("get", help="Gets the verbose details of a specified SEL entry")
3301 sel_get.add_argument('selNum', type=int, help="the number of the SEL entry to get")
3302 sel_get.set_defaults(func=selList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003303
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003304 sel_clear = sel_subparser.add_parser("clear", help="Clears all entries from the SEL")
3305 sel_clear.set_defaults(func=selClear)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003306
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003307 sel_setResolved = sel_subparser.add_parser("resolve", help="Sets the sel entry to resolved")
Justin Thalere412dc22018-01-12 16:28:24 -06003308 sel_setResolved.add_argument('-n', '--selNum', type=int, help="the number of the SEL entry to resolve")
3309 sel_ResolveAll_sub = sel_setResolved.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
3310 sel_ResolveAll = sel_ResolveAll_sub.add_parser('all', help='Resolve all SEL entries')
3311 sel_ResolveAll.set_defaults(func=selResolveAll)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003312 sel_setResolved.set_defaults(func=selSetResolved)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003313
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003314 parser_chassis = subparsers.add_parser("chassis", help="Work with chassis power and status")
Justin Thalere412dc22018-01-12 16:28:24 -06003315 chas_sub = parser_chassis.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003316
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003317 parser_chassis.add_argument('status', action='store_true', help='Returns the current status of the platform')
3318 parser_chassis.set_defaults(func=chassis)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003319
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003320 parser_chasPower = chas_sub.add_parser("power", help="Turn the chassis on or off, check the power state")
Justin Thalere412dc22018-01-12 16:28:24 -06003321 parser_chasPower.add_argument('powcmd', choices=['on','softoff', 'hardoff', 'status'], help='The value for the power command. on, off, or status')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003322 parser_chasPower.set_defaults(func=chassisPower)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003323
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003324 #control the chassis identify led
3325 parser_chasIdent = chas_sub.add_parser("identify", help="Control the chassis identify led")
3326 parser_chasIdent.add_argument('identcmd', choices=['on', 'off', 'status'], help='The control option for the led: on, off, blink, status')
3327 parser_chasIdent.set_defaults(func=chassisIdent)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003328
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003329 #collect service data
3330 parser_servData = subparsers.add_parser("collect_service_data", help="Collect all bmc data needed for service")
3331 parser_servData.add_argument('-d', '--devdebug', action='store_true', help=argparse.SUPPRESS)
3332 parser_servData.set_defaults(func=collectServiceData)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003333
Justin Thalere412dc22018-01-12 16:28:24 -06003334 #system quick health check
3335 parser_healthChk = subparsers.add_parser("health_check", help="Work with platform sensors")
3336 parser_healthChk.set_defaults(func=healthCheck)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003337
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003338 #work with bmc dumps
3339 parser_bmcdump = subparsers.add_parser("dump", help="Work with bmc dump files")
Justin Thalere412dc22018-01-12 16:28:24 -06003340 bmcDump_sub = parser_bmcdump.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Justin Thaler53bf2f12018-07-16 14:05:32 -05003341 bmcDump_sub.required = True
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003342 dump_Create = bmcDump_sub.add_parser('create', help="Create a bmc dump")
3343 dump_Create.set_defaults(func=bmcDumpCreate)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003344
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003345 dump_list = bmcDump_sub.add_parser('list', help="list all bmc dump files")
3346 dump_list.set_defaults(func=bmcDumpList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003347
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003348 parserdumpdelete = bmcDump_sub.add_parser('delete', help="Delete bmc dump files")
3349 parserdumpdelete.add_argument("-n", "--dumpNum", nargs='*', type=int, help="The Dump entry to delete")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003350 parserdumpdelete.set_defaults(func=bmcDumpDelete)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003351
Justin Thalere412dc22018-01-12 16:28:24 -06003352 bmcDumpDelsub = parserdumpdelete.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003353 deleteAllDumps = bmcDumpDelsub.add_parser('all', help='Delete all bmc dump files')
3354 deleteAllDumps.set_defaults(func=bmcDumpDeleteAll)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003355
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003356 parser_dumpretrieve = bmcDump_sub.add_parser('retrieve', help='Retrieve a dump file')
3357 parser_dumpretrieve.add_argument("dumpNum", type=int, help="The Dump entry to delete")
3358 parser_dumpretrieve.add_argument("-s", "--dumpSaveLoc", help="The location to save the bmc dump file")
3359 parser_dumpretrieve.set_defaults(func=bmcDumpRetrieve)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003360
Justin Thaler22b1bb52018-03-15 13:31:32 -05003361 #bmc command for reseting the bmc
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003362 parser_bmc = subparsers.add_parser('bmc', help="Work with the bmc")
Justin Thalere412dc22018-01-12 16:28:24 -06003363 bmc_sub = parser_bmc.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003364 parser_BMCReset = bmc_sub.add_parser('reset', help='Reset the bmc' )
3365 parser_BMCReset.add_argument('type', choices=['warm','cold'], help="Warm: Reboot the BMC, Cold: CLEAR config and reboot bmc")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003366 parser_bmc.add_argument('info', action='store_true', help="Displays information about the BMC hardware, including device revision, firmware revision, IPMI version supported, manufacturer ID, and information on additional device support.")
3367 parser_bmc.set_defaults(func=bmc)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003368
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003369 #add alias to the bmc command
3370 parser_mc = subparsers.add_parser('mc', help="Work with the management controller")
Justin Thalere412dc22018-01-12 16:28:24 -06003371 mc_sub = parser_mc.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003372 parser_MCReset = mc_sub.add_parser('reset', help='Reset the bmc' )
3373 parser_MCReset.add_argument('type', choices=['warm','cold'], help="Reboot the BMC")
3374 #parser_MCReset.add_argument('cold', action='store_true', help="Reboot the BMC and CLEAR the configuration")
3375 parser_mc.add_argument('info', action='store_true', help="Displays information about the BMC hardware, including device revision, firmware revision, IPMI version supported, manufacturer ID, and information on additional device support.")
Justin Thalere412dc22018-01-12 16:28:24 -06003376 parser_MCReset.set_defaults(func=bmcReset)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003377 parser_mc.set_defaults(func=bmc)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003378
Justin Thalere412dc22018-01-12 16:28:24 -06003379 #gard clear
3380 parser_gc = subparsers.add_parser("gardclear", help="Used to clear gard records")
3381 parser_gc.set_defaults(func=gardClear)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003382
Justin Thalere412dc22018-01-12 16:28:24 -06003383 #firmware_flash
3384 parser_fw = subparsers.add_parser("firmware", help="Work with the system firmware")
3385 fwflash_subproc = parser_fw.add_subparsers(title='subcommands', description='valid firmware commands', help='sub-command help', dest='command')
Justin Thaler53bf2f12018-07-16 14:05:32 -05003386 fwflash_subproc.required = True
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003387
Justin Thalere412dc22018-01-12 16:28:24 -06003388 fwflash = fwflash_subproc.add_parser('flash', help="Flash the system firmware")
3389 fwflash.add_argument('type', choices=['bmc', 'pnor'], help="image type to flash")
3390 fwflash.add_argument('-f', '--fileloc', required=True, help="The absolute path to the firmware image")
3391 fwflash.set_defaults(func=fwFlash)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003392
Justin Thaler22b1bb52018-03-15 13:31:32 -05003393 fwActivate = fwflash_subproc.add_parser('activate', help="Activate existing image on the bmc")
Justin Thalere412dc22018-01-12 16:28:24 -06003394 fwActivate.add_argument('imageID', help="The image ID to activate from the firmware list. Ex: 63c95399")
3395 fwActivate.set_defaults(func=activateFWImage)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003396
Justin Thaler22b1bb52018-03-15 13:31:32 -05003397 fwActivateStatus = fwflash_subproc.add_parser('activation_status', help="Check Status of activations")
3398 fwActivateStatus.set_defaults(func=activateStatus)
3399
Justin Thaler3d71d402018-07-24 14:35:39 -05003400 fwList = fwflash_subproc.add_parser('list', help="List all of the installed firmware")
3401 fwList.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
3402 fwList.set_defaults(func=firmwareList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003403
Justin Thaler3d71d402018-07-24 14:35:39 -05003404 fwprint = fwflash_subproc.add_parser('print', help="List all of the installed firmware")
3405 fwprint.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
3406 fwprint.set_defaults(func=firmwareList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003407
Adriana Kobylak5af2fad2018-11-08 12:33:43 -06003408 fwDelete = fwflash_subproc.add_parser('delete', help="Delete an existing firmware version")
3409 fwDelete.add_argument('versionID', help="The version ID to delete from the firmware list. Ex: 63c95399")
3410 fwDelete.set_defaults(func=deleteFWVersion)
3411
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05003412 #logging
3413 parser_logging = subparsers.add_parser("logging", help="logging controls")
3414 logging_sub = parser_logging.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003415
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05003416 #turn rest api logging on/off
3417 parser_rest_logging = logging_sub.add_parser("rest_api", help="turn rest api logging on/off")
3418 parser_rest_logging.add_argument('rest_logging', choices=['on', 'off'], help='The control option for rest logging: on, off')
3419 parser_rest_logging.set_defaults(func=restLogging)
Deepak Kodihalli02d53282018-09-18 06:53:31 -05003420
3421 #remote logging
3422 parser_remote_logging = logging_sub.add_parser("remote_logging", help="Remote logging (rsyslog) commands")
3423 parser_remote_logging.add_argument('remote_logging', choices=['view', 'disable'], help='Remote logging (rsyslog) commands')
3424 parser_remote_logging.set_defaults(func=remoteLogging)
3425
3426 #configure remote logging
3427 parser_remote_logging_config = logging_sub.add_parser("remote_logging_config", help="Configure remote logging (rsyslog)")
3428 parser_remote_logging_config.add_argument("-a", "--address", required=True, help="Set IP address of rsyslog server")
3429 parser_remote_logging_config.add_argument("-p", "--port", required=True, type=int, help="Set Port of rsyslog server")
3430 parser_remote_logging_config.set_defaults(func=remoteLoggingConfig)
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05003431
3432 #certificate management
3433 parser_cert = subparsers.add_parser("certificate", help="Certificate management")
3434 certMgmt_subproc = parser_cert.add_subparsers(title='subcommands', description='valid certificate commands', help='sub-command help', dest='command')
3435
3436 certUpdate = certMgmt_subproc.add_parser('update', help="Update the certificate")
3437 certUpdate.add_argument('type', choices=['server', 'client', 'authority'], help="certificate type to update")
3438 certUpdate.add_argument('service', choices=['https', 'ldap'], help="Service to update")
3439 certUpdate.add_argument('-f', '--fileloc', required=True, help="The absolute path to the certificate file")
3440 certUpdate.set_defaults(func=certificateUpdate)
3441
3442 certDelete = certMgmt_subproc.add_parser('delete', help="Delete the certificate")
3443 certDelete.add_argument('type', choices=['server', 'client', 'authority'], help="certificate type to delete")
3444 certDelete.add_argument('service', choices=['https', 'ldap'], help="Service to delete the certificate")
3445 certDelete.set_defaults(func=certificateDelete)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003446
Matt Spinler7d426c22018-09-24 14:42:07 -05003447 # local users
3448 parser_users = subparsers.add_parser("local_users", help="Work with local users")
3449 parser_users.add_argument('local_users', choices=['disableall','enableall', 'queryenabled'], help="Disable, enable or query local user accounts")
3450 parser_users.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
3451 parser_users.set_defaults(func=localUsers)
3452
Ratan Gupta9166cd22018-10-01 18:09:40 +05303453 #LDAP
3454 parser_ldap = subparsers.add_parser("ldap", help="LDAP controls")
3455 ldap_sub = parser_ldap.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
3456
3457 #configure and enable LDAP
3458 parser_ldap_config = ldap_sub.add_parser("enable", help="Configure and enables the LDAP")
3459 parser_ldap_config.add_argument("-a", "--uri", required=True, help="Set LDAP server URI")
3460 parser_ldap_config.add_argument("-B", "--bindDN", required=True, help="Set the bind DN of the LDAP server")
3461 parser_ldap_config.add_argument("-b", "--baseDN", required=True, help="Set the base DN of the LDAP server")
3462 parser_ldap_config.add_argument("-p", "--bindPassword", required=True, help="Set the bind password of the LDAP server")
3463 parser_ldap_config.add_argument("-S", "--scope", choices=['sub','one', 'base'],
3464 help='Specifies the search scope:subtree, one level or base object.')
3465 parser_ldap_config.add_argument("-t", "--serverType", choices=['ActiveDirectory','OpenLDAP'],
3466 help='Specifies the configured server is ActiveDirectory(AD) or OpenLdap')
3467 parser_ldap_config.set_defaults(func=enableLDAP)
3468
3469 # disable LDAP
3470 parser_disable_ldap = ldap_sub.add_parser("disable", help="disables the LDAP")
3471 parser_disable_ldap.set_defaults(func=disableLDAP)
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06003472 # view-config
3473 parser_ldap_config = \
3474 ldap_sub.add_parser("view-config", help="prints out a list of all \
3475 LDAPS's configured properties")
3476 parser_ldap_config.set_defaults(func=viewLDAPConfig)
Ratan Gupta9166cd22018-10-01 18:09:40 +05303477
Ratan Guptafeee6372018-10-17 23:25:51 +05303478 #create group privilege mapping
3479 parser_ldap_mapper = ldap_sub.add_parser("privilege-mapper", help="LDAP group privilege controls")
3480 parser_ldap_mapper_sub = parser_ldap_mapper.add_subparsers(title='subcommands', description='valid subcommands',
3481 help="sub-command help", dest='command')
3482
3483 parser_ldap_mapper_create = parser_ldap_mapper_sub.add_parser("create", help="Create mapping of ldap group and privilege")
3484 parser_ldap_mapper_create.add_argument("-g","--groupName",required=True,help="Group Name")
3485 parser_ldap_mapper_create.add_argument("-p","--privilege",choices=['priv-admin','priv-user'],required=True,help="Privilege")
3486 parser_ldap_mapper_create.set_defaults(func=createPrivilegeMapping)
3487
3488 #list group privilege mapping
3489 parser_ldap_mapper_list = parser_ldap_mapper_sub.add_parser("list",help="List privilege mapping")
3490 parser_ldap_mapper_list.set_defaults(func=listPrivilegeMapping)
3491
3492 #delete group privilege mapping
3493 parser_ldap_mapper_delete = parser_ldap_mapper_sub.add_parser("delete",help="Delete privilege mapping")
3494 parser_ldap_mapper_delete.add_argument("-g","--groupName",required=True,help="Group Name")
3495 parser_ldap_mapper_delete.set_defaults(func=deletePrivilegeMapping)
3496
Sivas SRR78835272018-11-27 05:27:19 -06003497 #deleteAll group privilege mapping
3498 parser_ldap_mapper_delete = parser_ldap_mapper_sub.add_parser("purge",help="Delete All privilege mapping")
3499 parser_ldap_mapper_delete.set_defaults(func=deleteAllPrivilegeMapping)
3500
Marri Devender Rao2c2a5162018-11-05 08:57:11 -06003501 # set local user password
3502 parser_set_password = subparsers.add_parser("set_password",
3503 help="Set password of local user")
3504 parser_set_password.add_argument( "-p", "--password", required=True,
3505 help="Password of local user")
3506 parser_set_password.set_defaults(func=setPassword)
3507
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003508 # network
3509 parser_nw = subparsers.add_parser("network", help="network controls")
3510 nw_sub = parser_nw.add_subparsers(title='subcommands',
3511 description='valid subcommands',
3512 help="sub-command help",
3513 dest='command')
3514
3515 # enable DHCP
3516 parser_enable_dhcp = nw_sub.add_parser("enableDHCP",
3517 help="enables the DHCP on given "
3518 "Interface")
3519 parser_enable_dhcp.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003520 help="Name of the ethernet interface(it can"
3521 "be obtained by the "
3522 "command:network view-config)"
3523 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003524 parser_enable_dhcp.set_defaults(func=enableDHCP)
3525
3526 # disable DHCP
3527 parser_disable_dhcp = nw_sub.add_parser("disableDHCP",
3528 help="disables the DHCP on given "
3529 "Interface")
3530 parser_disable_dhcp.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003531 help="Name of the ethernet interface(it can"
3532 "be obtained by the "
3533 "command:network view-config)"
3534 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003535 parser_disable_dhcp.set_defaults(func=disableDHCP)
3536
3537 # get HostName
3538 parser_gethostname = nw_sub.add_parser("getHostName",
3539 help="prints out HostName")
3540 parser_gethostname.set_defaults(func=getHostname)
3541
3542 # set HostName
3543 parser_sethostname = nw_sub.add_parser("setHostName", help="sets HostName")
3544 parser_sethostname.add_argument("-H", "--HostName", required=True,
3545 help="A HostName for the BMC")
3546 parser_sethostname.set_defaults(func=setHostname)
3547
3548 # get domainname
3549 parser_getdomainname = nw_sub.add_parser("getDomainName",
3550 help="prints out DomainName of "
3551 "given Interface")
3552 parser_getdomainname.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003553 help="Name of the ethernet interface(it "
3554 "can be obtained by the "
3555 "command:network view-config)"
3556 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003557 parser_getdomainname.set_defaults(func=getDomainName)
3558
3559 # set domainname
3560 parser_setdomainname = nw_sub.add_parser("setDomainName",
3561 help="sets DomainName of given "
3562 "Interface")
3563 parser_setdomainname.add_argument("-D", "--DomainName", required=True,
3564 help="Ex: DomainName=Domain1,Domain2,...")
3565 parser_setdomainname.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003566 help="Name of the ethernet interface(it "
3567 "can be obtained by the "
3568 "command:network view-config)"
3569 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003570 parser_setdomainname.set_defaults(func=setDomainName)
3571
3572 # get MACAddress
3573 parser_getmacaddress = nw_sub.add_parser("getMACAddress",
3574 help="prints out MACAddress the "
3575 "given Interface")
3576 parser_getmacaddress.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003577 help="Name of the ethernet interface(it "
3578 "can be obtained by the "
3579 "command:network view-config)"
3580 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003581 parser_getmacaddress.set_defaults(func=getMACAddress)
3582
3583 # set MACAddress
3584 parser_setmacaddress = nw_sub.add_parser("setMACAddress",
3585 help="sets MACAddress")
3586 parser_setmacaddress.add_argument("-MA", "--MACAddress", required=True,
3587 help="A MACAddress for the given "
3588 "Interface")
3589 parser_setmacaddress.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003590 help="Name of the ethernet interface(it can"
3591 "be obtained by the "
3592 "command:network view-config)"
3593 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003594 parser_setmacaddress.set_defaults(func=setMACAddress)
3595
3596 # get DefaultGW
3597 parser_getdefaultgw = nw_sub.add_parser("getDefaultGW",
3598 help="prints out DefaultGateway "
3599 "the BMC")
3600 parser_getdefaultgw.set_defaults(func=getDefaultGateway)
3601
3602 # set DefaultGW
3603 parser_setdefaultgw = nw_sub.add_parser("setDefaultGW",
3604 help="sets DefaultGW")
3605 parser_setdefaultgw.add_argument("-GW", "--DefaultGW", required=True,
3606 help="A DefaultGateway for the BMC")
3607 parser_setdefaultgw.set_defaults(func=setDefaultGateway)
3608
3609 # view network Config
3610 parser_ldap_config = nw_sub.add_parser("view-config", help="prints out a "
3611 "list of all network's configured "
3612 "properties")
3613 parser_ldap_config.set_defaults(func=viewNWConfig)
3614
3615 # get DNS
3616 parser_getDNS = nw_sub.add_parser("getDNS",
3617 help="prints out DNS servers on the "
3618 "given interface")
3619 parser_getDNS.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003620 help="Name of the ethernet interface(it can"
3621 "be obtained by the "
3622 "command:network view-config)"
3623 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003624 parser_getDNS.set_defaults(func=getDNS)
3625
3626 # set DNS
3627 parser_setDNS = nw_sub.add_parser("setDNS",
3628 help="sets DNS servers on the given "
3629 "interface")
3630 parser_setDNS.add_argument("-d", "--DNSServers", required=True,
3631 help="Ex: DNSSERVERS=DNS1,DNS2,...")
3632 parser_setDNS.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003633 help="Name of the ethernet interface(it can"
3634 "be obtained by the "
3635 "command:network view-config)"
3636 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003637 parser_setDNS.set_defaults(func=setDNS)
3638
3639 # get NTP
3640 parser_getNTP = nw_sub.add_parser("getNTP",
3641 help="prints out NTP servers on the "
3642 "given interface")
3643 parser_getNTP.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003644 help="Name of the ethernet interface(it can"
3645 "be obtained by the "
3646 "command:network view-config)"
3647 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003648 parser_getNTP.set_defaults(func=getNTP)
3649
3650 # set NTP
3651 parser_setNTP = nw_sub.add_parser("setNTP",
3652 help="sets NTP servers on the given "
3653 "interface")
3654 parser_setNTP.add_argument("-N", "--NTPServers", required=True,
3655 help="Ex: NTPSERVERS=NTP1,NTP2,...")
3656 parser_setNTP.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003657 help="Name of the ethernet interface(it can"
3658 "be obtained by the "
3659 "command:network view-config)"
3660 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003661 parser_setNTP.set_defaults(func=setNTP)
3662
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003663 # configure IP
3664 parser_ip_config = nw_sub.add_parser("addIP", help="Sets IP address to"
3665 "given interface")
3666 parser_ip_config.add_argument("-a", "--address", required=True,
3667 help="IP address of given interface")
3668 parser_ip_config.add_argument("-gw", "--gateway", required=False, default='',
3669 help="The gateway for given interface")
3670 parser_ip_config.add_argument("-l", "--prefixLength", required=True,
3671 help="The prefixLength of IP address")
3672 parser_ip_config.add_argument("-p", "--type", choices=['ipv4', 'ipv6'],
3673 help="The protocol type of the given"
3674 "IP address")
3675 parser_ip_config.add_argument("-I", "--Interface", required=True,
3676 help="Name of the ethernet interface(it can"
3677 "be obtained by the "
3678 "command:network view-config)"
3679 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
3680 parser_ip_config.set_defaults(func=addIP)
3681
3682 # getIP
3683 parser_getIP = nw_sub.add_parser("getIP", help="prints out IP address"
3684 "of given interface")
3685 parser_getIP.add_argument("-I", "--Interface", required=True,
3686 help="Name of the ethernet interface(it can"
3687 "be obtained by the command:network view-config)"
3688 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
3689 parser_getIP.set_defaults(func=getIP)
3690
3691 # rmIP
3692 parser_rmIP = nw_sub.add_parser("rmIP", help="deletes IP address"
3693 "of given interface")
3694 parser_rmIP.add_argument("-a", "--address", required=True,
3695 help="IP address to remove form given Interface")
3696 parser_rmIP.add_argument("-I", "--Interface", required=True,
3697 help="Name of the ethernet interface(it can"
3698 "be obtained by the command:network view-config)"
3699 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
3700 parser_rmIP.set_defaults(func=deleteIP)
3701
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003702 # add VLAN
3703 parser_create_vlan = nw_sub.add_parser("addVLAN", help="enables VLAN "
3704 "on given interface with given "
3705 "VLAN Identifier")
3706 parser_create_vlan.add_argument("-I", "--Interface", required=True,
3707 choices=['eth0', 'eth1'],
3708 help="Name of the ethernet interface")
3709 parser_create_vlan.add_argument("-n", "--Identifier", required=True,
3710 help="VLAN Identifier")
3711 parser_create_vlan.set_defaults(func=addVLAN)
3712
3713 # delete VLAN
3714 parser_delete_vlan = nw_sub.add_parser("deleteVLAN", help="disables VLAN "
3715 "on given interface with given "
3716 "VLAN Identifier")
3717 parser_delete_vlan.add_argument("-I", "--Interface", required=True,
3718 help="Name of the ethernet interface(it can"
3719 "be obtained by the "
3720 "command:network view-config)"
3721 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
3722 parser_delete_vlan.set_defaults(func=deleteVLAN)
3723
3724 # viewDHCPConfig
3725 parser_viewDHCPConfig = nw_sub.add_parser("viewDHCPConfig",
3726 help="Shows DHCP configured "
3727 "Properties")
3728 parser_viewDHCPConfig.set_defaults(func=viewDHCPConfig)
3729
3730 # configureDHCP
3731 parser_configDHCP = nw_sub.add_parser("configureDHCP",
3732 help="Configures/updates DHCP "
3733 "Properties")
3734 parser_configDHCP.add_argument("-d", "--DNSEnabled", type=str2bool,
3735 required=True, help="Sets DNSEnabled property")
3736 parser_configDHCP.add_argument("-n", "--HostNameEnabled", type=str2bool,
3737 required=True,
3738 help="Sets HostNameEnabled property")
3739 parser_configDHCP.add_argument("-t", "--NTPEnabled", type=str2bool,
3740 required=True,
3741 help="Sets NTPEnabled property")
3742 parser_configDHCP.add_argument("-s", "--SendHostNameEnabled", type=str2bool,
3743 required=True,
3744 help="Sets SendHostNameEnabled property")
3745 parser_configDHCP.set_defaults(func=configureDHCP)
3746
3747 # network factory reset
3748 parser_nw_reset = nw_sub.add_parser("nwReset",
3749 help="Resets networks setting to "
3750 "factory defaults. "
3751 "note:Reset settings will be applied "
3752 "after BMC reboot")
3753 parser_nw_reset.set_defaults(func=nwReset)
3754
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003755 return parser
3756
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003757def main(argv=None):
Justin Thalere412dc22018-01-12 16:28:24 -06003758 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003759 main function for running the command line utility as a sub application
3760 """
3761 global toolVersion
Adriana Kobylak5af2fad2018-11-08 12:33:43 -06003762 toolVersion = "1.11"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003763 parser = createCommandParser()
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003764 args = parser.parse_args(argv)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003765
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003766 totTimeStart = int(round(time.time()*1000))
3767
3768 if(sys.version_info < (3,0)):
3769 urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
3770 if sys.version_info >= (3,0):
3771 requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)
Justin Thalere412dc22018-01-12 16:28:24 -06003772 if (args.version):
Justin Thaler22b1bb52018-03-15 13:31:32 -05003773 print("Version: "+ toolVersion)
Justin Thalere412dc22018-01-12 16:28:24 -06003774 sys.exit(0)
3775 if (hasattr(args, 'fileloc') and args.fileloc is not None and 'print' in args.command):
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003776 mysess = None
Justin Thalere412dc22018-01-12 16:28:24 -06003777 print(selPrint('N/A', args, mysess))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003778 else:
Justin Thalere412dc22018-01-12 16:28:24 -06003779 if(hasattr(args, 'host') and hasattr(args,'user')):
3780 if (args.askpw):
3781 pw = getpass.getpass()
3782 elif(args.PW is not None):
3783 pw = args.PW
3784 else:
3785 print("You must specify a password")
3786 sys.exit()
3787 logintimeStart = int(round(time.time()*1000))
3788 mysess = login(args.host, args.user, pw, args.json)
Justin Thalera9415b42018-05-25 19:40:13 -05003789 if(sys.version_info < (3,0)):
3790 if isinstance(mysess, basestring):
3791 print(mysess)
3792 sys.exit(1)
3793 elif sys.version_info >= (3,0):
3794 if isinstance(mysess, str):
3795 print(mysess)
3796 sys.exit(1)
Justin Thalere412dc22018-01-12 16:28:24 -06003797 logintimeStop = int(round(time.time()*1000))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003798
3799 commandTimeStart = int(round(time.time()*1000))
Justin Thalere412dc22018-01-12 16:28:24 -06003800 output = args.func(args.host, args, mysess)
3801 commandTimeStop = int(round(time.time()*1000))
3802 print(output)
3803 if (mysess is not None):
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003804 logout(args.host, args.user, pw, mysess, args.json)
3805 if(args.procTime):
Justin Thalere412dc22018-01-12 16:28:24 -06003806 print("Total time: " + str(int(round(time.time()*1000))- totTimeStart))
3807 print("loginTime: " + str(logintimeStop - logintimeStart))
3808 print("command Time: " + str(commandTimeStop - commandTimeStart))
3809 else:
3810 print("usage: openbmctool.py [-h] -H HOST -U USER [-A | -P PW] [-j]\n" +
3811 "\t[-t POLICYTABLELOC] [-V]\n" +
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05003812 "\t{fru,sensors,sel,chassis,collect_service_data, \
3813 health_check,dump,bmc,mc,gardclear,firmware,logging}\n" +
Justin Thalere412dc22018-01-12 16:28:24 -06003814 "\t...\n" +
3815 "openbmctool.py: error: the following arguments are required: -H/--host, -U/--user")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003816 sys.exit()
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003817
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003818if __name__ == '__main__':
Justin Thalere412dc22018-01-12 16:28:24 -06003819 """
3820 main function when called from the command line
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003821
3822 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003823 import sys
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003824
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003825 isTTY = sys.stdout.isatty()
3826 assert sys.version_info >= (2,7)
3827 main()