blob: 021cef4780854fb8f7e1431722703665e440ef34 [file] [log] [blame]
Justin Thalerb8807ce2018-05-25 19:16:20 -05001#!/usr/bin/python3
Justin Thalere412dc22018-01-12 16:28:24 -06002"""
Joseph Reynoldsa2d54c52019-06-11 22:02:57 -05003 Copyright 2017,2019 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
Matt Spinler220c3c42019-01-04 15:09:29 -060034jsonHeader = {'Content-Type' : 'application/json'}
35xAuthHeader = {}
Justin Thaler27197622019-01-23 14:42:11 -060036baseTimeout = 60
Matt Spinler220c3c42019-01-04 15:09:29 -060037
Justin Thalerf9aee3e2017-12-05 12:11:09 -060038def hilight(textToColor, color, bold):
Justin Thalere412dc22018-01-12 16:28:24 -060039 """
40 Used to add highlights to various text for displaying in a terminal
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -060041
Justin Thalere412dc22018-01-12 16:28:24 -060042 @param textToColor: string, the text to be colored
43 @param color: string, used to color the text red or green
44 @param bold: boolean, used to bold the textToColor
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -060045 @return: Buffered reader containing the modified string.
46 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -060047 if(sys.platform.__contains__("win")):
48 if(color == "red"):
49 os.system('color 04')
50 elif(color == "green"):
51 os.system('color 02')
52 else:
53 os.system('color') #reset to default
54 return textToColor
55 else:
56 attr = []
57 if(color == "red"):
58 attr.append('31')
59 elif(color == "green"):
60 attr.append('32')
61 else:
62 attr.append('0')
63 if bold:
64 attr.append('1')
65 else:
66 attr.append('0')
67 return '\x1b[%sm%s\x1b[0m' % (';'.join(attr),textToColor)
68
Justin Thalerf9aee3e2017-12-05 12:11:09 -060069def connectionErrHandler(jsonFormat, errorStr, err):
Justin Thalere412dc22018-01-12 16:28:24 -060070 """
71 Error handler various connection errors to bmcs
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -060072
73 @param jsonFormat: boolean, used to output in json format with an error code.
Justin Thalere412dc22018-01-12 16:28:24 -060074 @param errorStr: string, used to color the text red or green
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -060075 @param err: string, the text from the exception
76 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -060077 if errorStr == "Timeout":
78 if not jsonFormat:
79 return("FQPSPIN0000M: Connection timed out. Ensure you have network connectivity to the bmc")
80 else:
Justin Thaler115bca72018-05-25 19:29:08 -050081 conerror = {}
82 conerror['CommonEventID'] = 'FQPSPIN0000M'
83 conerror['sensor']="N/A"
84 conerror['state']="N/A"
85 conerror['additionalDetails'] = "N/A"
86 conerror['Message']="Connection timed out. Ensure you have network connectivity to the BMC"
87 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."
88 conerror['Serviceable']="Yes"
89 conerror['CallHomeCandidate']= "No"
90 conerror['Severity'] = "Critical"
91 conerror['EventType'] = "Communication Failure/Timeout"
92 conerror['VMMigrationFlag'] = "Yes"
93 conerror["AffectedSubsystem"] = "Interconnect (Networking)"
94 conerror["timestamp"] = str(int(time.time()))
95 conerror["UserAction"] = "Verify network connectivity between the two systems and the bmc is functional."
96 eventdict = {}
97 eventdict['event0'] = conerror
98 eventdict['numAlerts'] = '1'
Justin Thaler115bca72018-05-25 19:29:08 -050099 errorMessageStr = errorMessageStr = json.dumps(eventdict, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600100 return(errorMessageStr)
101 elif errorStr == "ConnectionError":
102 if not jsonFormat:
103 return("FQPSPIN0001M: " + str(err))
104 else:
Justin Thaler115bca72018-05-25 19:29:08 -0500105 conerror = {}
106 conerror['CommonEventID'] = 'FQPSPIN0001M'
107 conerror['sensor']="N/A"
108 conerror['state']="N/A"
109 conerror['additionalDetails'] = str(err)
110 conerror['Message']="Connection Error. View additional details for more information"
111 conerror['LengthyDescription'] = "A connection error to the specified BMC occurred and additional details are provided. Review these details to resolve the issue."
112 conerror['Serviceable']="Yes"
113 conerror['CallHomeCandidate']= "No"
114 conerror['Severity'] = "Critical"
115 conerror['EventType'] = "Communication Failure/Timeout"
116 conerror['VMMigrationFlag'] = "Yes"
117 conerror["AffectedSubsystem"] = "Interconnect (Networking)"
118 conerror["timestamp"] = str(int(time.time()))
119 conerror["UserAction"] = "Correct the issue highlighted in additional details and try again"
120 eventdict = {}
121 eventdict['event0'] = conerror
122 eventdict['numAlerts'] = '1'
Justin Thaler115bca72018-05-25 19:29:08 -0500123 errorMessageStr = json.dumps(eventdict, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600124 return(errorMessageStr)
Justin Thaler115bca72018-05-25 19:29:08 -0500125
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600126 else:
127 return("Unknown Error: "+ str(err))
128
Justin Thalere412dc22018-01-12 16:28:24 -0600129
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600130def setColWidth(keylist, numCols, dictForOutput, colNames):
Justin Thalere412dc22018-01-12 16:28:24 -0600131 """
132 Sets the output width of the columns to display
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600133
134 @param keylist: list, list of strings representing the keys for the dictForOutput
Justin Thalere412dc22018-01-12 16:28:24 -0600135 @param numcols: the total number of columns in the final output
136 @param dictForOutput: dictionary, contains the information to print to the screen
137 @param colNames: list, The strings to use for the column headings, in order of the keylist
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600138 @return: A list of the column widths for each respective column.
Justin Thalere412dc22018-01-12 16:28:24 -0600139 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600140 colWidths = []
141 for x in range(0, numCols):
142 colWidths.append(0)
143 for key in dictForOutput:
144 for x in range(0, numCols):
145 colWidths[x] = max(colWidths[x], len(str(dictForOutput[key][keylist[x]])))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600146
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600147 for x in range(0, numCols):
148 colWidths[x] = max(colWidths[x], len(colNames[x])) +2
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600149
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600150 return colWidths
151
152def loadPolicyTable(pathToPolicyTable):
Justin Thalere412dc22018-01-12 16:28:24 -0600153 """
154 loads a json based policy table into a dictionary
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600155
Justin Thalere412dc22018-01-12 16:28:24 -0600156 @param value: boolean, the value to convert
157 @return: A string of "Yes" or "No"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600158 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600159 policyTable = {}
160 if(os.path.exists(pathToPolicyTable)):
161 with open(pathToPolicyTable, 'r') as stream:
162 try:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600163 contents =json.load(stream)
164 policyTable = contents['events']
Justin Thalere412dc22018-01-12 16:28:24 -0600165 except Exception as err:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600166 print(err)
167 return policyTable
168
Justin Thalere412dc22018-01-12 16:28:24 -0600169
170def boolToString(value):
171 """
172 converts a boolean value to a human readable string value
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600173
Justin Thalere412dc22018-01-12 16:28:24 -0600174 @param value: boolean, the value to convert
175 @return: A string of "Yes" or "No"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600176 """
Justin Thalere412dc22018-01-12 16:28:24 -0600177 if(value):
178 return "Yes"
179 else:
180 return "No"
181
Justin Thalera6b5df72018-07-16 11:10:07 -0500182def stringToInt(text):
183 """
184 returns an integer if the string can be converted, otherwise returns the string
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600185
Justin Thalera6b5df72018-07-16 11:10:07 -0500186 @param text: the string to try to convert to an integer
187 """
188 if text.isdigit():
189 return int(text)
190 else:
191 return text
Justin Thalere412dc22018-01-12 16:28:24 -0600192
Justin Thalera6b5df72018-07-16 11:10:07 -0500193def naturalSort(text):
194 """
195 provides a way to naturally sort a list
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600196
Justin Thalera6b5df72018-07-16 11:10:07 -0500197 @param text: the key to convert for sorting
198 @return list containing the broken up string parts by integers and strings
199 """
200 stringPartList = []
201 for c in re.split('(\d+)', text):
202 stringPartList.append(stringToInt(c))
203 return stringPartList
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600204
Justin Thalere412dc22018-01-12 16:28:24 -0600205def tableDisplay(keylist, colNames, output):
206 """
207 Logs into the BMC and creates a session
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600208
Justin Thalere412dc22018-01-12 16:28:24 -0600209 @param keylist: list, keys for the output dictionary, ordered by colNames
210 @param colNames: Names for the Table of the columns
211 @param output: The dictionary of data to display
212 @return: Session object
213 """
214 colWidth = setColWidth(keylist, len(colNames), output, colNames)
215 row = ""
216 outputText = ""
217 for i in range(len(colNames)):
218 if (i != 0): row = row + "| "
219 row = row + colNames[i].ljust(colWidth[i])
220 outputText += row + "\n"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600221
Justin Thalera6b5df72018-07-16 11:10:07 -0500222 output_keys = list(output.keys())
223 output_keys.sort(key=naturalSort)
224 for key in output_keys:
Justin Thalere412dc22018-01-12 16:28:24 -0600225 row = ""
Justin Thaler8fe0c732018-07-24 14:32:35 -0500226 for i in range(len(keylist)):
Justin Thalere412dc22018-01-12 16:28:24 -0600227 if (i != 0): row = row + "| "
228 row = row + output[key][keylist[i]].ljust(colWidth[i])
229 outputText += row + "\n"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600230
Justin Thalere412dc22018-01-12 16:28:24 -0600231 return outputText
232
Justin Thaler22b1bb52018-03-15 13:31:32 -0500233def checkFWactivation(host, args, session):
234 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600235 Checks the software inventory for an image that is being activated.
236
Justin Thaler22b1bb52018-03-15 13:31:32 -0500237 @return: True if an image is being activated, false is no activations are happening
238 """
239 url="https://"+host+"/xyz/openbmc_project/software/enumerate"
Justin Thaler22b1bb52018-03-15 13:31:32 -0500240 try:
Justin Thaler27197622019-01-23 14:42:11 -0600241 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thaler22b1bb52018-03-15 13:31:32 -0500242 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
Justin Thaler3a5771b2019-01-23 14:31:52 -0600248 fwInfo = resp.json()['data']
Justin Thaler22b1bb52018-03-15 13:31:32 -0500249 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...")
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600267 mysess = requests.session()
268 try:
Justin Thaler27197622019-01-23 14:42:11 -0600269 r = mysess.post('https://'+host+'/login', headers=jsonHeader, json = {"data": [username, pw]}, verify=False, timeout=baseTimeout)
Matt Spinler220c3c42019-01-04 15:09:29 -0600270
271 cookie = r.headers['Set-Cookie']
272 match = re.search('SESSION=(\w+);', cookie)
273 if match:
274 xAuthHeader['X-Auth-Token'] = match.group(1)
275 jsonHeader.update(xAuthHeader)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600276 loginMessage = json.loads(r.text)
277 if (loginMessage['status'] != "ok"):
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600278 print(loginMessage["data"]["description"].encode('utf-8'))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600279 sys.exit(1)
280# if(sys.version_info < (3,0)):
281# urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
282# if sys.version_info >= (3,0):
283# requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)
284 return mysess
285 except(requests.exceptions.Timeout):
Justin Thaler115bca72018-05-25 19:29:08 -0500286 return (connectionErrHandler(jsonFormat, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600287 except(requests.exceptions.ConnectionError) as err:
Justin Thaler115bca72018-05-25 19:29:08 -0500288 return (connectionErrHandler(jsonFormat, "ConnectionError", err))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600289
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600290
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600291def logout(host, username, pw, session, jsonFormat):
Justin Thalere412dc22018-01-12 16:28:24 -0600292 """
293 Logs out of the bmc and terminates the session
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600294
Justin Thalere412dc22018-01-12 16:28:24 -0600295 @param host: string, the hostname or IP address of the bmc to log out of
296 @param username: The user name for the bmc to log out of
297 @param pw: The password for the BMC to log out of
298 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600299 @param jsonFormat: boolean, flag that will only allow relevant data from user command to be display. This function becomes silent when set to true.
300 """
Justin Thalere412dc22018-01-12 16:28:24 -0600301 try:
Justin Thaler27197622019-01-23 14:42:11 -0600302 r = session.post('https://'+host+'/logout', headers=jsonHeader,json = {"data": [username, pw]}, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600303 except(requests.exceptions.Timeout):
304 print(connectionErrHandler(jsonFormat, "Timeout", None))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600305
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600306 if(jsonFormat==False):
Matt Spinlereae05b02019-01-24 12:59:34 -0600307 if r.status_code == 200:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600308 print('User ' +username + ' has been logged out')
309
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600310
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600311def fru(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -0600312 """
313 prints out the system inventory. deprecated see fruPrint and fruList
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600314
Justin Thalere412dc22018-01-12 16:28:24 -0600315 @param host: string, the hostname or IP address of the bmc
316 @param args: contains additional arguments used by the fru sub command
317 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600318 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
319 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600320 #url="https://"+host+"/org/openbmc/inventory/system/chassis/enumerate"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600321
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600322 #print(url)
323 #res = session.get(url, headers=httpHeader, verify=False)
324 #print(res.text)
325 #sample = res.text
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600326
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600327 #inv_list = json.loads(sample)["data"]
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600328
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600329 url="https://"+host+"/xyz/openbmc_project/inventory/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600330 try:
Justin Thaler27197622019-01-23 14:42:11 -0600331 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600332 except(requests.exceptions.Timeout):
333 return(connectionErrHandler(args.json, "Timeout", None))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600334
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600335 sample = res.text
336# inv_list.update(json.loads(sample)["data"])
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600337#
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600338# #determine column width's
339# colNames = ["FRU Name", "FRU Type", "Has Fault", "Is FRU", "Present", "Version"]
340# colWidths = setColWidth(["FRU Name", "fru_type", "fault", "is_fru", "present", "version"], 6, inv_list, colNames)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600341#
342# 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 -0600343# "Present".ljust(colWidths[4]) + "Version".ljust(colWidths[5]))
344# format the output
345# for key in sorted(inv_list.keys()):
346# keyParts = key.split("/")
347# isFRU = "True" if (inv_list[key]["is_fru"]==1) else "False"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600348#
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600349# fruEntry = (keyParts[len(keyParts) - 1].ljust(colWidths[0]) + inv_list[key]["fru_type"].ljust(colWidths[1])+
350# inv_list[key]["fault"].ljust(colWidths[2])+isFRU.ljust(colWidths[3])+
351# inv_list[key]["present"].ljust(colWidths[4])+ inv_list[key]["version"].ljust(colWidths[5]))
352# if(isTTY):
353# if(inv_list[key]["is_fru"] == 1):
354# color = "green"
355# bold = True
356# else:
357# color='black'
358# bold = False
359# fruEntry = hilight(fruEntry, color, bold)
360# print (fruEntry)
361 return sample
Justin Thalere412dc22018-01-12 16:28:24 -0600362
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600363def fruPrint(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -0600364 """
365 prints out all inventory
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600366
Justin Thalere412dc22018-01-12 16:28:24 -0600367 @param host: string, the hostname or IP address of the bmc
368 @param args: contains additional arguments used by the fru sub command
369 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600370 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
371 @return returns the total fru list.
372 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600373 url="https://"+host+"/xyz/openbmc_project/inventory/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600374 try:
Justin Thaler27197622019-01-23 14:42:11 -0600375 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600376 except(requests.exceptions.Timeout):
377 return(connectionErrHandler(args.json, "Timeout", None))
378
Justin Thaler3a5771b2019-01-23 14:31:52 -0600379 frulist={}
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600380# print(res.text)
Justin Thaler3a5771b2019-01-23 14:31:52 -0600381 if res.status_code==200:
382 frulist['Hardware'] = res.json()['data']
383 else:
384 if not args.json:
385 return "Error retrieving the system inventory. BMC message: {msg}".format(msg=res.json()['message'])
386 else:
387 return res.json()
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600388 url="https://"+host+"/xyz/openbmc_project/software/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600389 try:
Justin Thaler27197622019-01-23 14:42:11 -0600390 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600391 except(requests.exceptions.Timeout):
392 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600393# print(res.text)
Justin Thaler3a5771b2019-01-23 14:31:52 -0600394 if res.status_code==200:
395 frulist['Software'] = res.json()['data']
396 else:
397 if not args.json():
398 return "Error retrieving the system inventory. BMC message: {msg}".format(msg=res.json()['message'])
399 else:
400 return res.json()
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600401 return frulist
402
Justin Thalere412dc22018-01-12 16:28:24 -0600403
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600404def fruList(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -0600405 """
406 prints out all inventory or only a specific specified item
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600407
Justin Thalere412dc22018-01-12 16:28:24 -0600408 @param host: string, the hostname or IP address of the bmc
409 @param args: contains additional arguments used by the fru sub command
410 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600411 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
412 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600413 if(args.items==True):
414 return fruPrint(host, args, session)
415 else:
Justin Thalere412dc22018-01-12 16:28:24 -0600416 return fruPrint(host, args, session)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600417
418
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600419
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600420def fruStatus(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -0600421 """
422 prints out the status of all FRUs
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600423
Justin Thalere412dc22018-01-12 16:28:24 -0600424 @param host: string, the hostname or IP address of the bmc
425 @param args: contains additional arguments used by the fru sub command
426 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600427 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
428 """
Justin Thalere412dc22018-01-12 16:28:24 -0600429 url="https://"+host+"/xyz/openbmc_project/inventory/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600430 try:
Matt Spinler220c3c42019-01-04 15:09:29 -0600431 res = session.get(url, headers=jsonHeader, verify=False)
Justin Thalere412dc22018-01-12 16:28:24 -0600432 except(requests.exceptions.Timeout):
433 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600434# print(res.text)
Justin Thaler3a5771b2019-01-23 14:31:52 -0600435 frulist = res.json()['data']
Justin Thalere412dc22018-01-12 16:28:24 -0600436 frus = {}
437 for key in frulist:
438 component = frulist[key]
439 isFru = False
440 present = False
441 func = False
442 hasSels = False
443 keyPieces = key.split('/')
444 fruName = keyPieces[-1]
445 if 'core' in fruName: #associate cores to cpus
446 fruName = keyPieces[-2] + '-' + keyPieces[-1]
447 if 'Functional' in component:
448 if('Present' in component):
Justin Thalere412dc22018-01-12 16:28:24 -0600449 if 'FieldReplaceable' in component:
450 if component['FieldReplaceable'] == 1:
451 isFru = True
452 if "fan" in fruName:
453 isFru = True;
454 if component['Present'] == 1:
455 present = True
456 if component['Functional'] == 1:
457 func = True
458 if ((key + "/fault") in frulist):
459 hasSels = True;
460 if args.verbose:
461 if hasSels:
462 loglist = []
463 faults = frulist[key+"/fault"]['endpoints']
464 for item in faults:
465 loglist.append(item.split('/')[-1])
466 frus[fruName] = {"compName": fruName, "Functional": boolToString(func), "Present":boolToString(present), "IsFru": boolToString(isFru), "selList": ', '.join(loglist).strip() }
467 else:
468 frus[fruName] = {"compName": fruName, "Functional": boolToString(func), "Present":boolToString(present), "IsFru": boolToString(isFru), "selList": "None" }
469 else:
470 frus[fruName] = {"compName": fruName, "Functional": boolToString(func), "Present":boolToString(present), "IsFru": boolToString(isFru), "hasSEL": boolToString(hasSels) }
Justin Thalerfb9c81c2018-07-16 11:14:37 -0500471 elif "power_supply" in fruName or "powersupply" in fruName:
Justin Thalere412dc22018-01-12 16:28:24 -0600472 if component['Present'] ==1:
473 present = True
474 isFru = True
475 if ((key + "/fault") in frulist):
476 hasSels = True;
477 if args.verbose:
478 if hasSels:
479 loglist = []
480 faults = frulist[key+"/fault"]['endpoints']
Obihörnchenff8035f2018-12-05 21:07:37 +0100481 for item in faults:
482 loglist.append(item.split('/')[-1])
Justin Thalere412dc22018-01-12 16:28:24 -0600483 frus[fruName] = {"compName": fruName, "Functional": "No", "Present":boolToString(present), "IsFru": boolToString(isFru), "selList": ', '.join(loglist).strip() }
484 else:
485 frus[fruName] = {"compName": fruName, "Functional": "Yes", "Present":boolToString(present), "IsFru": boolToString(isFru), "selList": "None" }
486 else:
487 frus[fruName] = {"compName": fruName, "Functional": boolToString(not hasSels), "Present":boolToString(present), "IsFru": boolToString(isFru), "hasSEL": boolToString(hasSels) }
488 if not args.json:
489 if not args.verbose:
490 colNames = ["Component", "Is a FRU", "Present", "Functional", "Has Logs"]
491 keylist = ["compName", "IsFru", "Present", "Functional", "hasSEL"]
492 else:
493 colNames = ["Component", "Is a FRU", "Present", "Functional", "Assoc. Log Number(s)"]
494 keylist = ["compName", "IsFru", "Present", "Functional", "selList"]
495 return tableDisplay(keylist, colNames, frus)
496 else:
497 return str(json.dumps(frus, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600498
Justin Thalere412dc22018-01-12 16:28:24 -0600499def sensor(host, args, session):
500 """
501 prints out all sensors
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600502
Justin Thalere412dc22018-01-12 16:28:24 -0600503 @param host: string, the hostname or IP address of the bmc
504 @param args: contains additional arguments used by the sensor sub command
505 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600506 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
507 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600508 url="https://"+host+"/xyz/openbmc_project/sensors/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600509 try:
Justin Thaler27197622019-01-23 14:42:11 -0600510 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600511 except(requests.exceptions.Timeout):
512 return(connectionErrHandler(args.json, "Timeout", None))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600513
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600514 #Get OCC status
515 url="https://"+host+"/org/open_power/control/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600516 try:
Justin Thaler27197622019-01-23 14:42:11 -0600517 occres = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600518 except(requests.exceptions.Timeout):
519 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600520 if not args.json:
521 colNames = ['sensor', 'type', 'units', 'value', 'target']
Justin Thaler3a5771b2019-01-23 14:31:52 -0600522 sensors = res.json()["data"]
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600523 output = {}
524 for key in sensors:
525 senDict = {}
526 keyparts = key.split("/")
527 senDict['sensorName'] = keyparts[-1]
528 senDict['type'] = keyparts[-2]
Justin Thalere412dc22018-01-12 16:28:24 -0600529 try:
530 senDict['units'] = sensors[key]['Unit'].split('.')[-1]
531 except KeyError:
Justin Thaler22b1bb52018-03-15 13:31:32 -0500532 senDict['units'] = "N/A"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600533 if('Scale' in sensors[key]):
534 scale = 10 ** sensors[key]['Scale']
535 else:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600536 scale = 1
Justin Thaler22b1bb52018-03-15 13:31:32 -0500537 try:
538 senDict['value'] = str(sensors[key]['Value'] * scale)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600539 except KeyError:
Justin Thaler22b1bb52018-03-15 13:31:32 -0500540 if 'value' in sensors[key]:
541 senDict['value'] = sensors[key]['value']
542 else:
543 senDict['value'] = "N/A"
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600544 if 'Target' in sensors[key]:
545 senDict['target'] = str(sensors[key]['Target'])
546 else:
547 senDict['target'] = 'N/A'
548 output[senDict['sensorName']] = senDict
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600549
Justin Thaler3a5771b2019-01-23 14:31:52 -0600550 occstatus = occres.json()["data"]
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600551 if '/org/open_power/control/occ0' in occstatus:
552 occ0 = occstatus["/org/open_power/control/occ0"]['OccActive']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600553 if occ0 == 1:
554 occ0 = 'Active'
555 else:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600556 occ0 = 'Inactive'
557 output['OCC0'] = {'sensorName':'OCC0', 'type': 'Discrete', 'units': 'N/A', 'value': occ0, 'target': 'Active'}
558 occ1 = occstatus["/org/open_power/control/occ1"]['OccActive']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600559 if occ1 == 1:
560 occ1 = 'Active'
561 else:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600562 occ1 = 'Inactive'
563 output['OCC1'] = {'sensorName':'OCC1', 'type': 'Discrete', 'units': 'N/A', 'value': occ0, 'target': 'Active'}
564 else:
565 output['OCC0'] = {'sensorName':'OCC0', 'type': 'Discrete', 'units': 'N/A', 'value': 'Inactive', 'target': 'Inactive'}
566 output['OCC1'] = {'sensorName':'OCC1', 'type': 'Discrete', 'units': 'N/A', 'value': 'Inactive', 'target': 'Inactive'}
567 keylist = ['sensorName', 'type', 'units', 'value', 'target']
Justin Thalere412dc22018-01-12 16:28:24 -0600568
569 return tableDisplay(keylist, colNames, output)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600570 else:
571 return res.text + occres.text
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600572
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600573def sel(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -0600574 """
575 prints out the bmc alerts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600576
Justin Thalere412dc22018-01-12 16:28:24 -0600577 @param host: string, the hostname or IP address of the bmc
578 @param args: contains additional arguments used by the sel sub command
579 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600580 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
581 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600582
583 url="https://"+host+"/xyz/openbmc_project/logging/entry/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600584 try:
Justin Thaler27197622019-01-23 14:42:11 -0600585 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600586 except(requests.exceptions.Timeout):
587 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600588 return res.text
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600589
590
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600591def parseESEL(args, eselRAW):
Justin Thalere412dc22018-01-12 16:28:24 -0600592 """
593 parses the esel data and gets predetermined search terms
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600594
Justin Thalere412dc22018-01-12 16:28:24 -0600595 @param eselRAW: string, the raw esel string from the bmc
596 @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 -0600597 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600598 eselParts = {}
599 esel_bin = binascii.unhexlify(''.join(eselRAW.split()[16:]))
600 #search terms contains the search term as the key and the return dictionary key as it's value
601 searchTerms = { 'Signature Description':'signatureDescription', 'devdesc':'devdesc',
Justin Thaler22b1bb52018-03-15 13:31:32 -0500602 'Callout type': 'calloutType', 'Procedure':'procedure', 'Sensor Type': 'sensorType'}
Justin Thaler24d4efa2018-11-08 22:48:10 -0600603 uniqueID = str(uuid.uuid4())
604 eselBinPath = tempfile.gettempdir() + os.sep + uniqueID + 'esel.bin'
Justin Thalercf1deae2018-05-25 19:35:21 -0500605 with open(eselBinPath, 'wb') as f:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600606 f.write(esel_bin)
607 errlPath = ""
608 #use the right errl file for the machine architecture
609 arch = platform.machine()
610 if(arch =='x86_64' or arch =='AMD64'):
611 if os.path.exists('/opt/ibm/ras/bin/x86_64/errl'):
612 errlPath = '/opt/ibm/ras/bin/x86_64/errl'
613 elif os.path.exists('errl/x86_64/errl'):
614 errlPath = 'errl/x86_64/errl'
615 else:
616 errlPath = 'x86_64/errl'
617 elif (platform.machine()=='ppc64le'):
618 if os.path.exists('/opt/ibm/ras/bin/ppc64le/errl'):
619 errlPath = '/opt/ibm/ras/bin/ppc64le/errl'
620 elif os.path.exists('errl/ppc64le/errl'):
621 errlPath = 'errl/ppc64le/errl'
622 else:
623 errlPath = 'ppc64le/errl'
624 else:
625 print("machine architecture not supported for parsing eSELs")
626 return eselParts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600627
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600628 if(os.path.exists(errlPath)):
Justin Thalercf1deae2018-05-25 19:35:21 -0500629 output= subprocess.check_output([errlPath, '-d', '--file='+eselBinPath]).decode('utf-8')
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600630# output = proc.communicate()[0]
631 lines = output.split('\n')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600632
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600633 if(hasattr(args, 'fullEsel')):
634 return output
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600635
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600636 for i in range(0, len(lines)):
637 lineParts = lines[i].split(':')
638 if(len(lineParts)>1): #ignore multi lines, output formatting lines, and other information
639 for term in searchTerms:
640 if(term in lineParts[0]):
641 temp = lines[i][lines[i].find(':')+1:].strip()[:-1].strip()
642 if lines[i+1].find(':') != -1:
643 if (len(lines[i+1].split(':')[0][1:].strip())==0):
644 while(len(lines[i][:lines[i].find(':')].strip())>2):
Justin Thaler43030422018-11-08 22:50:21 -0600645 #has multiple lines, process and update line counter
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600646 if((i+1) <= len(lines)):
647 i+=1
648 else:
649 i=i-1
650 break
Justin Thaler43030422018-11-08 22:50:21 -0600651 #Append the content from the next line removing the pretty display characters
652 #Finds the first colon then starts 2 characters after, then removes all whitespace
653 temp = temp + lines[i][lines[i].find(':')+2:].strip()[:-1].strip()[:-1].strip()
Justin Thaler22b1bb52018-03-15 13:31:32 -0500654 if(searchTerms[term] in eselParts):
655 eselParts[searchTerms[term]] = eselParts[searchTerms[term]] + ", " + temp
656 else:
657 eselParts[searchTerms[term]] = temp
Justin Thalercf1deae2018-05-25 19:35:21 -0500658 os.remove(eselBinPath)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600659 else:
660 print("errl file cannot be found")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600661
662 return eselParts
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600663
Justin Thalere412dc22018-01-12 16:28:24 -0600664
Matt Spinler02d0dff2018-08-29 13:19:25 -0500665def getESELSeverity(esel):
666 """
667 Finds the severity type in an eSEL from the User Header section.
668 @param esel - the eSEL data
669 @return severity - e.g. 'Critical'
670 """
671
672 # everything but 1 and 2 are Critical
673 # '1': 'recovered',
674 # '2': 'predictive',
675 # '4': 'unrecoverable',
676 # '5': 'critical',
677 # '6': 'diagnostic',
678 # '7': 'symptom'
679 severities = {
680 '1': 'Informational',
681 '2': 'Warning'
682 }
683
684 try:
685 headerPosition = esel.index('55 48') # 'UH'
686 # The severity is the last byte in the 8 byte section (a byte is ' bb')
687 severity = esel[headerPosition:headerPosition+32].split(' ')[-1]
688 type = severity[0]
689 except ValueError:
690 print("Could not find severity value in UH section in eSEL")
691 type = 'x';
692
693 return severities.get(type, 'Critical')
694
695
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600696def sortSELs(events):
Justin Thalere412dc22018-01-12 16:28:24 -0600697 """
698 sorts the sels by timestamp, then log entry number
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600699
Justin Thalere412dc22018-01-12 16:28:24 -0600700 @param events: Dictionary containing events
701 @return: list containing a list of the ordered log entries, and dictionary of keys
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600702 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600703 logNumList = []
704 timestampList = []
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600705 eventKeyDict = {}
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600706 eventsWithTimestamp = {}
707 logNum2events = {}
708 for key in events:
709 if key == 'numAlerts': continue
710 if 'callout' in key: continue
711 timestamp = (events[key]['timestamp'])
712 if timestamp not in timestampList:
713 eventsWithTimestamp[timestamp] = [events[key]['logNum']]
714 else:
715 eventsWithTimestamp[timestamp].append(events[key]['logNum'])
716 #map logNumbers to the event dictionary keys
717 eventKeyDict[str(events[key]['logNum'])] = key
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600718
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600719 timestampList = list(eventsWithTimestamp.keys())
720 timestampList.sort()
721 for ts in timestampList:
722 if len(eventsWithTimestamp[ts]) > 1:
723 tmplist = eventsWithTimestamp[ts]
724 tmplist.sort()
725 logNumList = logNumList + tmplist
726 else:
727 logNumList = logNumList + eventsWithTimestamp[ts]
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600728
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600729 return [logNumList, eventKeyDict]
730
Justin Thalere412dc22018-01-12 16:28:24 -0600731
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600732def parseAlerts(policyTable, selEntries, args):
Justin Thalere412dc22018-01-12 16:28:24 -0600733 """
734 parses alerts in the IBM CER format, using an IBM policy Table
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600735
Justin Thalere412dc22018-01-12 16:28:24 -0600736 @param policyTable: dictionary, the policy table entries
737 @param selEntries: dictionary, the alerts retrieved from the bmc
738 @return: A dictionary of the parsed entries, in chronological order
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600739 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600740 eventDict = {}
741 eventNum =""
742 count = 0
743 esel = ""
744 eselParts = {}
745 i2cdevice= ""
Matt Spinler02d0dff2018-08-29 13:19:25 -0500746 eselSeverity = None
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600747
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600748 'prepare and sort the event entries'
749 for key in selEntries:
750 if 'callout' not in key:
751 selEntries[key]['logNum'] = key.split('/')[-1]
752 selEntries[key]['timestamp'] = selEntries[key]['Timestamp']
753 sortedEntries = sortSELs(selEntries)
754 logNumList = sortedEntries[0]
755 eventKeyDict = sortedEntries[1]
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600756
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600757 for logNum in logNumList:
758 key = eventKeyDict[logNum]
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600759 hasEsel=False
760 i2creadFail = False
761 if 'callout' in key:
762 continue
763 else:
764 messageID = str(selEntries[key]['Message'])
765 addDataPiece = selEntries[key]['AdditionalData']
766 calloutIndex = 0
767 calloutFound = False
768 for i in range(len(addDataPiece)):
769 if("CALLOUT_INVENTORY_PATH" in addDataPiece[i]):
770 calloutIndex = i
771 calloutFound = True
772 fruCallout = str(addDataPiece[calloutIndex]).split('=')[1]
773 if("CALLOUT_DEVICE_PATH" in addDataPiece[i]):
774 i2creadFail = True
Matt Spinlerd178a472018-08-31 09:48:52 -0500775
776 fruCallout = str(addDataPiece[calloutIndex]).split('=')[1]
777
778 # Fall back to "I2C"/"FSI" if dev path isn't in policy table
779 if (messageID + '||' + fruCallout) not in policyTable:
780 i2cdevice = str(addDataPiece[i]).strip().split('=')[1]
781 i2cdevice = '/'.join(i2cdevice.split('/')[-4:])
782 if 'fsi' in str(addDataPiece[calloutIndex]).split('=')[1]:
783 fruCallout = 'FSI'
784 else:
785 fruCallout = 'I2C'
Justin Thalere34c43a2018-05-25 19:37:55 -0500786 calloutFound = True
787 if("CALLOUT_GPIO_NUM" in addDataPiece[i]):
788 if not calloutFound:
789 fruCallout = 'GPIO'
790 calloutFound = True
791 if("CALLOUT_IIC_BUS" in addDataPiece[i]):
792 if not calloutFound:
793 fruCallout = "I2C"
794 calloutFound = True
795 if("CALLOUT_IPMI_SENSOR_NUM" in addDataPiece[i]):
796 if not calloutFound:
797 fruCallout = "IPMI"
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600798 calloutFound = True
799 if("ESEL" in addDataPiece[i]):
800 esel = str(addDataPiece[i]).strip().split('=')[1]
Matt Spinler02d0dff2018-08-29 13:19:25 -0500801 eselSeverity = getESELSeverity(esel)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600802 if args.devdebug:
803 eselParts = parseESEL(args, esel)
804 hasEsel=True
805 if("GPU" in addDataPiece[i]):
806 fruCallout = '/xyz/openbmc_project/inventory/system/chassis/motherboard/gpu' + str(addDataPiece[i]).strip()[-1]
807 calloutFound = True
808 if("PROCEDURE" in addDataPiece[i]):
809 fruCallout = str(hex(int(str(addDataPiece[i]).split('=')[1])))[2:]
810 calloutFound = True
Justin Thalere412dc22018-01-12 16:28:24 -0600811 if("RAIL_NAME" in addDataPiece[i]):
812 calloutFound=True
813 fruCallout = str(addDataPiece[i]).split('=')[1].strip()
814 if("INPUT_NAME" in addDataPiece[i]):
815 calloutFound=True
816 fruCallout = str(addDataPiece[i]).split('=')[1].strip()
817 if("SENSOR_TYPE" in addDataPiece[i]):
818 calloutFound=True
819 fruCallout = str(addDataPiece[i]).split('=')[1].strip()
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600820
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600821 if(calloutFound):
Justin Thaler22b1bb52018-03-15 13:31:32 -0500822 if fruCallout != "":
823 policyKey = messageID +"||" + fruCallout
Matt Spinler02d0dff2018-08-29 13:19:25 -0500824
825 # Also use the severity for hostboot errors
826 if eselSeverity and messageID == 'org.open_power.Host.Error.Event':
827 policyKey += '||' + eselSeverity
828
829 # if not in the table, fall back to the original key
830 if policyKey not in policyTable:
831 policyKey = policyKey.replace('||'+eselSeverity, '')
832
Justin Thalere34c43a2018-05-25 19:37:55 -0500833 if policyKey not in policyTable:
834 policyKey = messageID
Justin Thaler22b1bb52018-03-15 13:31:32 -0500835 else:
836 policyKey = messageID
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600837 else:
838 policyKey = messageID
839 event = {}
840 eventNum = str(count)
841 if policyKey in policyTable:
842 for pkey in policyTable[policyKey]:
843 if(type(policyTable[policyKey][pkey])== bool):
844 event[pkey] = boolToString(policyTable[policyKey][pkey])
845 else:
846 if (i2creadFail and pkey == 'Message'):
847 event[pkey] = policyTable[policyKey][pkey] + ' ' +i2cdevice
848 else:
849 event[pkey] = policyTable[policyKey][pkey]
850 event['timestamp'] = selEntries[key]['Timestamp']
851 event['resolved'] = bool(selEntries[key]['Resolved'])
852 if(hasEsel):
853 if args.devdebug:
854 event['eselParts'] = eselParts
855 event['raweSEL'] = esel
856 event['logNum'] = key.split('/')[-1]
857 eventDict['event' + eventNum] = event
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600858
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600859 else:
860 severity = str(selEntries[key]['Severity']).split('.')[-1]
861 if severity == 'Error':
862 severity = 'Critical'
863 eventDict['event'+eventNum] = {}
864 eventDict['event' + eventNum]['error'] = "error: Not found in policy table: " + policyKey
865 eventDict['event' + eventNum]['timestamp'] = selEntries[key]['Timestamp']
866 eventDict['event' + eventNum]['Severity'] = severity
867 if(hasEsel):
868 if args.devdebug:
869 eventDict['event' +eventNum]['eselParts'] = eselParts
870 eventDict['event' +eventNum]['raweSEL'] = esel
871 eventDict['event' +eventNum]['logNum'] = key.split('/')[-1]
872 eventDict['event' +eventNum]['resolved'] = bool(selEntries[key]['Resolved'])
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600873 count += 1
874 return eventDict
875
876
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600877def selDisplay(events, args):
Justin Thalere412dc22018-01-12 16:28:24 -0600878 """
879 displays alerts in human readable format
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600880
Justin Thalere412dc22018-01-12 16:28:24 -0600881 @param events: Dictionary containing events
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600882 @return:
883 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600884 activeAlerts = []
885 historyAlerts = []
886 sortedEntries = sortSELs(events)
887 logNumList = sortedEntries[0]
888 eventKeyDict = sortedEntries[1]
889 keylist = ['Entry', 'ID', 'Timestamp', 'Serviceable', 'Severity','Message']
890 if(args.devdebug):
891 colNames = ['Entry', 'ID', 'Timestamp', 'Serviceable', 'Severity','Message', 'eSEL contents']
892 keylist.append('eSEL')
893 else:
894 colNames = ['Entry', 'ID', 'Timestamp', 'Serviceable', 'Severity', 'Message']
895 for log in logNumList:
896 selDict = {}
897 alert = events[eventKeyDict[str(log)]]
898 if('error' in alert):
899 selDict['Entry'] = alert['logNum']
900 selDict['ID'] = 'Unknown'
901 selDict['Timestamp'] = datetime.datetime.fromtimestamp(int(alert['timestamp']/1000)).strftime("%Y-%m-%d %H:%M:%S")
902 msg = alert['error']
903 polMsg = msg.split("policy table:")[0]
904 msg = msg.split("policy table:")[1]
905 msgPieces = msg.split("||")
906 err = msgPieces[0]
907 if(err.find("org.open_power.")!=-1):
908 err = err.split("org.open_power.")[1]
909 elif(err.find("xyz.openbmc_project.")!=-1):
910 err = err.split("xyz.openbmc_project.")[1]
911 else:
912 err = msgPieces[0]
913 callout = ""
914 if len(msgPieces) >1:
915 callout = msgPieces[1]
916 if(callout.find("/org/open_power/")!=-1):
917 callout = callout.split("/org/open_power/")[1]
918 elif(callout.find("/xyz/openbmc_project/")!=-1):
919 callout = callout.split("/xyz/openbmc_project/")[1]
920 else:
921 callout = msgPieces[1]
922 selDict['Message'] = polMsg +"policy table: "+ err + "||" + callout
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600923 selDict['Serviceable'] = 'Unknown'
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600924 selDict['Severity'] = alert['Severity']
925 else:
926 selDict['Entry'] = alert['logNum']
927 selDict['ID'] = alert['CommonEventID']
928 selDict['Timestamp'] = datetime.datetime.fromtimestamp(int(alert['timestamp']/1000)).strftime("%Y-%m-%d %H:%M:%S")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600929 selDict['Message'] = alert['Message']
930 selDict['Serviceable'] = alert['Serviceable']
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600931 selDict['Severity'] = alert['Severity']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600932
933
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600934 eselOrder = ['refCode','signatureDescription', 'eselType', 'devdesc', 'calloutType', 'procedure']
935 if ('eselParts' in alert and args.devdebug):
936 eselOutput = ""
937 for item in eselOrder:
938 if item in alert['eselParts']:
939 eselOutput = eselOutput + item + ": " + alert['eselParts'][item] + " | "
940 selDict['eSEL'] = eselOutput
941 else:
942 if args.devdebug:
943 selDict['eSEL'] = "None"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600944
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600945 if not alert['resolved']:
946 activeAlerts.append(selDict)
947 else:
948 historyAlerts.append(selDict)
949 mergedOutput = activeAlerts + historyAlerts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600950 colWidth = setColWidth(keylist, len(colNames), dict(enumerate(mergedOutput)), colNames)
951
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600952 output = ""
953 if(len(activeAlerts)>0):
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600954 row = ""
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600955 output +="----Active Alerts----\n"
956 for i in range(0, len(colNames)):
957 if i!=0: row =row + "| "
958 row = row + colNames[i].ljust(colWidth[i])
959 output += row + "\n"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600960
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600961 for i in range(0,len(activeAlerts)):
962 row = ""
963 for j in range(len(activeAlerts[i])):
964 if (j != 0): row = row + "| "
965 row = row + activeAlerts[i][keylist[j]].ljust(colWidth[j])
966 output += row + "\n"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600967
968 if(len(historyAlerts)>0):
969 row = ""
970 output+= "----Historical Alerts----\n"
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600971 for i in range(len(colNames)):
972 if i!=0: row =row + "| "
973 row = row + colNames[i].ljust(colWidth[i])
974 output += row + "\n"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600975
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600976 for i in range(0, len(historyAlerts)):
977 row = ""
978 for j in range(len(historyAlerts[i])):
979 if (j != 0): row = row + "| "
980 row = row + historyAlerts[i][keylist[j]].ljust(colWidth[j])
981 output += row + "\n"
982# print(events[eventKeyDict[str(log)]])
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600983 return output
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600984
Justin Thalere412dc22018-01-12 16:28:24 -0600985
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600986def selPrint(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -0600987 """
988 prints out all bmc alerts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600989
Justin Thalere412dc22018-01-12 16:28:24 -0600990 @param host: string, the hostname or IP address of the bmc
991 @param args: contains additional arguments used by the fru sub command
992 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600993 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
994 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600995 if(args.policyTableLoc is None):
996 if os.path.exists('policyTable.json'):
997 ptableLoc = "policyTable.json"
998 elif os.path.exists('/opt/ibm/ras/lib/policyTable.json'):
999 ptableLoc = '/opt/ibm/ras/lib/policyTable.json'
1000 else:
1001 ptableLoc = 'lib/policyTable.json'
1002 else:
1003 ptableLoc = args.policyTableLoc
1004 policyTable = loadPolicyTable(ptableLoc)
1005 rawselEntries = ""
1006 if(hasattr(args, 'fileloc') and args.fileloc is not None):
1007 if os.path.exists(args.fileloc):
1008 with open(args.fileloc, 'r') as selFile:
1009 selLines = selFile.readlines()
1010 rawselEntries = ''.join(selLines)
1011 else:
1012 print("Error: File not found")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001013 sys.exit(1)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001014 else:
1015 rawselEntries = sel(host, args, session)
1016 loadFailed = False
1017 try:
1018 selEntries = json.loads(rawselEntries)
1019 except ValueError:
1020 loadFailed = True
1021 if loadFailed:
1022 cleanSels = json.dumps(rawselEntries).replace('\\n', '')
1023 #need to load json twice as original content was string escaped a second time
1024 selEntries = json.loads(json.loads(cleanSels))
1025 selEntries = selEntries['data']
Justin Thalere412dc22018-01-12 16:28:24 -06001026
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001027 if 'description' in selEntries:
1028 if(args.json):
1029 return("{\n\t\"numAlerts\": 0\n}")
1030 else:
1031 return("No log entries found")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001032
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001033 else:
1034 if(len(policyTable)>0):
1035 events = parseAlerts(policyTable, selEntries, args)
1036 if(args.json):
1037 events["numAlerts"] = len(events)
1038 retValue = str(json.dumps(events, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False))
1039 return retValue
1040 elif(hasattr(args, 'fullSel')):
1041 return events
1042 else:
1043 #get log numbers to order event entries sequentially
1044 return selDisplay(events, args)
1045 else:
1046 if(args.json):
1047 return selEntries
1048 else:
1049 print("error: Policy Table not found.")
1050 return selEntries
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001051
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001052def selList(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001053 """
1054 prints out all all bmc alerts, or only prints out the specified alerts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001055
Justin Thalere412dc22018-01-12 16:28:24 -06001056 @param host: string, the hostname or IP address of the bmc
1057 @param args: contains additional arguments used by the fru sub command
1058 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001059 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1060 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001061 return(sel(host, args, session))
1062
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001063
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001064def selClear(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001065 """
1066 clears all alerts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001067
Justin Thalere412dc22018-01-12 16:28:24 -06001068 @param host: string, the hostname or IP address of the bmc
1069 @param args: contains additional arguments used by the fru sub command
1070 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001071 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1072 """
Matt Spinler47b13e92019-01-04 14:58:53 -06001073 url="https://"+host+"/xyz/openbmc_project/logging/action/DeleteAll"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001074 data = "{\"data\": [] }"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001075
Justin Thalere412dc22018-01-12 16:28:24 -06001076 try:
Justin Thaler27197622019-01-23 14:42:11 -06001077 res = session.post(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001078 except(requests.exceptions.Timeout):
1079 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001080 if res.status_code == 200:
1081 return "The Alert Log has been cleared. Please allow a few minutes for the action to complete."
1082 else:
1083 print("Unable to clear the logs, trying to clear 1 at a time")
1084 sels = json.loads(sel(host, args, session))['data']
1085 for key in sels:
1086 if 'callout' not in key:
1087 logNum = key.split('/')[-1]
1088 url = "https://"+ host+ "/xyz/openbmc_project/logging/entry/"+logNum+"/action/Delete"
1089 try:
Justin Thaler27197622019-01-23 14:42:11 -06001090 session.post(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001091 except(requests.exceptions.Timeout):
1092 return connectionErrHandler(args.json, "Timeout", None)
1093 sys.exit(1)
1094 except(requests.exceptions.ConnectionError) as err:
1095 return connectionErrHandler(args.json, "ConnectionError", err)
1096 sys.exit(1)
1097 return ('Sel clearing complete')
1098
1099def selSetResolved(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001100 """
1101 sets a sel entry to resolved
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001102
Justin Thalere412dc22018-01-12 16:28:24 -06001103 @param host: string, the hostname or IP address of the bmc
1104 @param args: contains additional arguments used by the fru sub command
1105 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001106 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1107 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001108 url="https://"+host+"/xyz/openbmc_project/logging/entry/" + str(args.selNum) + "/attr/Resolved"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001109 data = "{\"data\": 1 }"
Justin Thalere412dc22018-01-12 16:28:24 -06001110 try:
Justin Thaler27197622019-01-23 14:42:11 -06001111 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001112 except(requests.exceptions.Timeout):
1113 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001114 if res.status_code == 200:
1115 return "Sel entry "+ str(args.selNum) +" is now set to resolved"
1116 else:
1117 return "Unable to set the alert to resolved"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001118
Justin Thalere412dc22018-01-12 16:28:24 -06001119def selResolveAll(host, args, session):
1120 """
1121 sets a sel entry to resolved
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001122
Justin Thalere412dc22018-01-12 16:28:24 -06001123 @param host: string, the hostname or IP address of the bmc
1124 @param args: contains additional arguments used by the fru sub command
1125 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001126 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1127 """
Justin Thalere412dc22018-01-12 16:28:24 -06001128 rawselEntries = sel(host, args, session)
1129 loadFailed = False
1130 try:
1131 selEntries = json.loads(rawselEntries)
1132 except ValueError:
1133 loadFailed = True
1134 if loadFailed:
1135 cleanSels = json.dumps(rawselEntries).replace('\\n', '')
1136 #need to load json twice as original content was string escaped a second time
1137 selEntries = json.loads(json.loads(cleanSels))
1138 selEntries = selEntries['data']
1139
1140 if 'description' in selEntries:
1141 if(args.json):
1142 return("{\n\t\"selsResolved\": 0\n}")
1143 else:
1144 return("No log entries found")
1145 else:
1146 d = vars(args)
1147 successlist = []
1148 failedlist = []
1149 for key in selEntries:
1150 if 'callout' not in key:
1151 d['selNum'] = key.split('/')[-1]
1152 resolved = selSetResolved(host,args,session)
1153 if 'Sel entry' in resolved:
1154 successlist.append(d['selNum'])
1155 else:
1156 failedlist.append(d['selNum'])
1157 output = ""
1158 successlist.sort()
1159 failedlist.sort()
1160 if len(successlist)>0:
1161 output = "Successfully resolved: " +', '.join(successlist) +"\n"
1162 if len(failedlist)>0:
1163 output += "Failed to resolve: " + ', '.join(failedlist) + "\n"
1164 return output
1165
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001166def chassisPower(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001167 """
1168 called by the chassis function. Controls the power state of the chassis, or gets the status
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001169
Justin Thalere412dc22018-01-12 16:28:24 -06001170 @param host: string, the hostname or IP address of the bmc
1171 @param args: contains additional arguments used by the fru sub command
1172 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001173 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1174 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001175 if(args.powcmd == 'on'):
Justin Thaler22b1bb52018-03-15 13:31:32 -05001176 if checkFWactivation(host, args, session):
1177 return ("Chassis Power control disabled during firmware activation")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001178 print("Attempting to Power on...:")
1179 url="https://"+host+"/xyz/openbmc_project/state/host0/attr/RequestedHostTransition"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001180 data = '{"data":"xyz.openbmc_project.State.Host.Transition.On"}'
Justin Thalere412dc22018-01-12 16:28:24 -06001181 try:
Justin Thaler27197622019-01-23 14:42:11 -06001182 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001183 except(requests.exceptions.Timeout):
1184 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001185 return res.text
Justin Thalere412dc22018-01-12 16:28:24 -06001186 elif(args.powcmd == 'softoff'):
Justin Thaler22b1bb52018-03-15 13:31:32 -05001187 if checkFWactivation(host, args, session):
1188 return ("Chassis Power control disabled during firmware activation")
Justin Thalere412dc22018-01-12 16:28:24 -06001189 print("Attempting to Power off gracefully...:")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001190 url="https://"+host+"/xyz/openbmc_project/state/host0/attr/RequestedHostTransition"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001191 data = '{"data":"xyz.openbmc_project.State.Host.Transition.Off"}'
Justin Thalere412dc22018-01-12 16:28:24 -06001192 try:
Justin Thaler27197622019-01-23 14:42:11 -06001193 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001194 except(requests.exceptions.Timeout):
1195 return(connectionErrHandler(args.json, "Timeout", None))
1196 return res.text
1197 elif(args.powcmd == 'hardoff'):
Justin Thaler22b1bb52018-03-15 13:31:32 -05001198 if checkFWactivation(host, args, session):
1199 return ("Chassis Power control disabled during firmware activation")
Justin Thalere412dc22018-01-12 16:28:24 -06001200 print("Attempting to Power off immediately...:")
1201 url="https://"+host+"/xyz/openbmc_project/state/chassis0/attr/RequestedPowerTransition"
Justin Thalere412dc22018-01-12 16:28:24 -06001202 data = '{"data":"xyz.openbmc_project.State.Chassis.Transition.Off"}'
1203 try:
Justin Thaler27197622019-01-23 14:42:11 -06001204 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001205 except(requests.exceptions.Timeout):
1206 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001207 return res.text
1208 elif(args.powcmd == 'status'):
1209 url="https://"+host+"/xyz/openbmc_project/state/chassis0/attr/CurrentPowerState"
Justin Thalere412dc22018-01-12 16:28:24 -06001210 try:
Justin Thaler27197622019-01-23 14:42:11 -06001211 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001212 except(requests.exceptions.Timeout):
1213 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001214 chassisState = json.loads(res.text)['data'].split('.')[-1]
1215 url="https://"+host+"/xyz/openbmc_project/state/host0/attr/CurrentHostState"
Justin Thalere412dc22018-01-12 16:28:24 -06001216 try:
Justin Thaler27197622019-01-23 14:42:11 -06001217 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001218 except(requests.exceptions.Timeout):
1219 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001220 hostState = json.loads(res.text)['data'].split('.')[-1]
1221 url="https://"+host+"/xyz/openbmc_project/state/bmc0/attr/CurrentBMCState"
Justin Thalere412dc22018-01-12 16:28:24 -06001222 try:
Justin Thaler27197622019-01-23 14:42:11 -06001223 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001224 except(requests.exceptions.Timeout):
1225 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001226 bmcState = json.loads(res.text)['data'].split('.')[-1]
1227 if(args.json):
1228 outDict = {"Chassis Power State" : chassisState, "Host Power State" : hostState, "BMC Power State":bmcState}
1229 return json.dumps(outDict, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False)
1230 else:
1231 return "Chassis Power State: " +chassisState + "\nHost Power State: " + hostState + "\nBMC Power State: " + bmcState
1232 else:
1233 return "Invalid chassis power command"
1234
Justin Thalere412dc22018-01-12 16:28:24 -06001235
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001236def chassisIdent(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001237 """
1238 called by the chassis function. Controls the identify led of the chassis. Sets or gets the state
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001239
Justin Thalere412dc22018-01-12 16:28:24 -06001240 @param host: string, the hostname or IP address of the bmc
1241 @param args: contains additional arguments used by the fru sub command
1242 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001243 @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 -06001244 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001245 if(args.identcmd == 'on'):
1246 print("Attempting to turn identify light on...:")
1247 url="https://"+host+"/xyz/openbmc_project/led/groups/enclosure_identify/attr/Asserted"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001248 data = '{"data":true}'
Justin Thalere412dc22018-01-12 16:28:24 -06001249 try:
Justin Thaler27197622019-01-23 14:42:11 -06001250 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001251 except(requests.exceptions.Timeout):
1252 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001253 return res.text
1254 elif(args.identcmd == 'off'):
1255 print("Attempting to turn identify light off...:")
1256 url="https://"+host+"/xyz/openbmc_project/led/groups/enclosure_identify/attr/Asserted"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001257 data = '{"data":false}'
Justin Thalere412dc22018-01-12 16:28:24 -06001258 try:
Justin Thaler27197622019-01-23 14:42:11 -06001259 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001260 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"
Justin Thalere412dc22018-01-12 16:28:24 -06001265 try:
Justin Thaler27197622019-01-23 14:42:11 -06001266 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001267 except(requests.exceptions.Timeout):
1268 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001269 status = json.loads(res.text)['data']
1270 if(args.json):
1271 return status
1272 else:
1273 if status['Asserted'] == 0:
1274 return "Identify light is off"
1275 else:
1276 return "Identify light is blinking"
1277 else:
1278 return "Invalid chassis identify command"
1279
Justin Thalere412dc22018-01-12 16:28:24 -06001280
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001281def chassis(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001282 """
1283 controls the different chassis commands
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001284
Justin Thalere412dc22018-01-12 16:28:24 -06001285 @param host: string, the hostname or IP address of the bmc
1286 @param args: contains additional arguments used by the fru sub command
1287 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001288 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1289 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001290 if(hasattr(args, 'powcmd')):
1291 result = chassisPower(host,args,session)
1292 elif(hasattr(args, 'identcmd')):
1293 result = chassisIdent(host, args, session)
1294 else:
Justin Thaler22b1bb52018-03-15 13:31:32 -05001295 return "This feature is not yet implemented"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001296 return result
Justin Thalere412dc22018-01-12 16:28:24 -06001297
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001298def bmcDumpRetrieve(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001299 """
1300 Downloads a dump file from the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001301
Justin Thalere412dc22018-01-12 16:28:24 -06001302 @param host: string, the hostname or IP address of the bmc
1303 @param args: contains additional arguments used by the collectServiceData sub command
1304 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001305 @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 -06001306 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001307 dumpNum = args.dumpNum
1308 if (args.dumpSaveLoc is not None):
1309 saveLoc = args.dumpSaveLoc
1310 else:
Justin Thalercf1deae2018-05-25 19:35:21 -05001311 saveLoc = tempfile.gettempdir()
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001312 url ='https://'+host+'/download/dump/' + str(dumpNum)
1313 try:
Justin Thaler27197622019-01-23 14:42:11 -06001314 r = session.get(url, headers=jsonHeader, stream=True, verify=False, timeout=baseTimeout)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001315 if (args.dumpSaveLoc is not None):
1316 if os.path.exists(saveLoc):
1317 if saveLoc[-1] != os.path.sep:
1318 saveLoc = saveLoc + os.path.sep
1319 filename = saveLoc + host+'-dump' + str(dumpNum) + '.tar.xz'
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001320
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001321 else:
1322 return 'Invalid save location specified'
1323 else:
Justin Thalercf1deae2018-05-25 19:35:21 -05001324 filename = tempfile.gettempdir()+os.sep + host+'-dump' + str(dumpNum) + '.tar.xz'
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001325
1326 with open(filename, 'wb') as f:
1327 for chunk in r.iter_content(chunk_size =1024):
1328 if chunk:
1329 f.write(chunk)
1330 return 'Saved as ' + filename
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001331
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001332 except(requests.exceptions.Timeout):
1333 return connectionErrHandler(args.json, "Timeout", None)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001334
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001335 except(requests.exceptions.ConnectionError) as err:
1336 return connectionErrHandler(args.json, "ConnectionError", err)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001337
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001338def bmcDumpList(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001339 """
1340 Lists the number of dump files on the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001341
Justin Thalere412dc22018-01-12 16:28:24 -06001342 @param host: string, the hostname or IP address of the bmc
1343 @param args: contains additional arguments used by the collectServiceData sub command
1344 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001345 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1346 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001347 url ='https://'+host+'/xyz/openbmc_project/dump/list'
1348 try:
Justin Thaler27197622019-01-23 14:42:11 -06001349 r = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thaler3a5771b2019-01-23 14:31:52 -06001350 dumpList = r.json()
1351 return dumpList
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001352 except(requests.exceptions.Timeout):
1353 return connectionErrHandler(args.json, "Timeout", None)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001354
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001355 except(requests.exceptions.ConnectionError) as err:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001356 return connectionErrHandler(args.json, "ConnectionError", err)
1357
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001358def bmcDumpDelete(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001359 """
1360 Deletes BMC dump files from the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001361
Justin Thalere412dc22018-01-12 16:28:24 -06001362 @param host: string, the hostname or IP address of the bmc
1363 @param args: contains additional arguments used by the collectServiceData sub command
1364 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001365 @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 -06001366 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001367 dumpList = []
1368 successList = []
1369 failedList = []
1370 if args.dumpNum is not None:
1371 if isinstance(args.dumpNum, list):
1372 dumpList = args.dumpNum
1373 else:
1374 dumpList.append(args.dumpNum)
1375 for dumpNum in dumpList:
1376 url ='https://'+host+'/xyz/openbmc_project/dump/entry/'+str(dumpNum)+'/action/Delete'
1377 try:
Justin Thaler27197622019-01-23 14:42:11 -06001378 r = session.post(url, headers=jsonHeader, json = {"data": []}, verify=False, timeout=baseTimeout)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001379 if r.status_code == 200:
1380 successList.append(str(dumpNum))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001381 else:
1382 failedList.append(str(dumpNum))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001383 except(requests.exceptions.Timeout):
1384 return connectionErrHandler(args.json, "Timeout", None)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001385 except(requests.exceptions.ConnectionError) as err:
1386 return connectionErrHandler(args.json, "ConnectionError", err)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001387 output = "Successfully deleted dumps: " + ', '.join(successList)
1388 if(len(failedList)>0):
1389 output+= '\nFailed to delete dumps: ' + ', '.join(failedList)
1390 return output
1391 else:
1392 return 'You must specify an entry number to delete'
1393
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001394def bmcDumpDeleteAll(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001395 """
1396 Deletes All BMC dump files from the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001397
Justin Thalere412dc22018-01-12 16:28:24 -06001398 @param host: string, the hostname or IP address of the bmc
1399 @param args: contains additional arguments used by the collectServiceData sub command
1400 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001401 @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 -06001402 """
1403 dumpResp = bmcDumpList(host, args, session)
1404 if 'FQPSPIN0000M' in dumpResp or 'FQPSPIN0001M'in dumpResp:
1405 return dumpResp
Justin Thaler3a5771b2019-01-23 14:31:52 -06001406 dumpList = dumpResp['data']
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001407 d = vars(args)
1408 dumpNums = []
1409 for dump in dumpList:
1410 if '/xyz/openbmc_project/dump/internal/manager' not in dump:
1411 dumpNums.append(int(dump.strip().split('/')[-1]))
1412 d['dumpNum'] = dumpNums
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001413
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001414 return bmcDumpDelete(host, args, session)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001415
Justin Thalere412dc22018-01-12 16:28:24 -06001416
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001417def bmcDumpCreate(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001418 """
1419 Creates a bmc dump file
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001420
Justin Thalere412dc22018-01-12 16:28:24 -06001421 @param host: string, the hostname or IP address of the bmc
1422 @param args: contains additional arguments used by the collectServiceData sub command
1423 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001424 @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 -06001425 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001426 url = 'https://'+host+'/xyz/openbmc_project/dump/action/CreateDump'
1427 try:
Justin Thaler27197622019-01-23 14:42:11 -06001428 r = session.post(url, headers=jsonHeader, json = {"data": []}, verify=False, timeout=baseTimeout)
Matt Spinlereae05b02019-01-24 12:59:34 -06001429 if(r.status_code == 200 and not args.json):
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001430 return ('Dump successfully created')
Justin Thaler3a5771b2019-01-23 14:31:52 -06001431 elif(args.json):
1432 return r.json()
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001433 else:
1434 return ('Failed to create dump')
1435 except(requests.exceptions.Timeout):
1436 return connectionErrHandler(args.json, "Timeout", None)
1437 except(requests.exceptions.ConnectionError) as err:
1438 return connectionErrHandler(args.json, "ConnectionError", err)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001439
1440
Justin Thaler666cf342019-01-23 14:44:27 -06001441def csdDumpInitiate(host, args, session):
1442 """
1443 Starts the process of getting the current list of dumps then initiates the creation of one.
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001444
Justin Thaler666cf342019-01-23 14:44:27 -06001445 @param host: string, the hostname or IP address of the bmc
1446 @param args: contains additional arguments used by the collectServiceData sub command
1447 @param session: the active session to use
1448 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1449 """
1450 errorInfo = ""
1451 dumpcount = 0
1452 try:
1453 d = vars(args)
1454 d['json'] = True
1455 except Exception as e:
1456 errorInfo += "Failed to set the json flag to True \n Exception: {eInfo}\n".format(eInfo=e)
1457
1458 try:
1459 for i in range(3):
1460 dumpInfo = bmcDumpList(host, args, session)
1461 if 'data' in dumpInfo:
1462 dumpcount = len(dumpInfo['data'])
1463 break
1464 else:
1465 errorInfo+= "Dump List Message returned: " + json.dumps(dumpInfo,indent=0, separators=(',', ':')).replace('\n','') +"\n"
1466 except Exception as e:
1467 errorInfo+= "Failed to collect the list of dumps.\nException: {eInfo}\n".format(eInfo=e)
1468
1469 #Create a user initiated dump
1470 try:
1471 for i in range(3):
1472 dumpcreated = bmcDumpCreate(host, args, session)
1473 if 'message' in dumpcreated:
1474 if 'ok' in dumpcreated['message'].lower():
1475 break
1476 else:
1477 errorInfo+= "Dump create message returned: " + json.dumps(dumpInfo,indent=0, separators=(',', ':')).replace('\n','') +"\n"
1478 else:
1479 errorInfo+= "Dump create message returned: " + json.dumps(dumpInfo,indent=0, separators=(',', ':')).replace('\n','') +"\n"
1480 except Exception as e:
1481 errorInfo+= "Dump create exception encountered: {eInfo}\n".format(eInfo=e)
1482
1483 output = {}
1484 output['errors'] = errorInfo
1485 output['dumpcount'] = dumpcount
1486 return output
1487
1488def csdInventory(host, args,session, fileDir):
1489 """
1490 Collects the BMC inventory, retrying if necessary
1491
1492 @param host: string, the hostname or IP address of the bmc
1493 @param args: contains additional arguments used by the collectServiceData sub command
1494 @param session: the active session to use
1495 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1496 @param fileDir: string representation of the path to use for putting files created
1497 """
1498 errorInfo = "===========Inventory =============\n"
1499 output={}
1500 inventoryCollected = False
1501 try:
1502 for i in range(3):
1503 frulist = fruPrint(host, args, session)
1504 if 'Hardware' in frulist:
1505 inventoryCollected = True
1506 break
1507 else:
1508 errorInfo += json.dumps(frulist, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n'
1509 except Exception as e:
1510 errorInfo += "Inventory collection exception: {eInfo}\n".format(eInfo=e)
1511 if inventoryCollected:
1512 try:
1513 with open(fileDir +os.sep+'inventory.txt', 'w') as f:
1514 f.write(json.dumps(frulist, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n')
1515 print("Inventory collected and stored in " + fileDir + os.sep + "inventory.txt")
1516 output['fileLoc'] = fileDir+os.sep+'inventory.txt'
1517 except Exception as e:
1518 print("Failed to write inventory to file.")
1519 errorInfo += "Error writing inventory to the file. Exception: {eInfo}\n".format(eInfo=e)
1520
1521 output['errors'] = errorInfo
1522
1523 return output
1524
1525def csdSensors(host, args,session, fileDir):
1526 """
1527 Collects the BMC sensor readings, retrying if necessary
1528
1529 @param host: string, the hostname or IP address of the bmc
1530 @param args: contains additional arguments used by the collectServiceData sub command
1531 @param session: the active session to use
1532 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1533 @param fileDir: string representation of the path to use for putting files created
1534 """
1535 errorInfo = "===========Sensors =============\n"
1536 sensorsCollected = False
1537 output={}
1538 try:
1539 d = vars(args)
1540 d['json'] = False
1541 except Exception as e:
1542 errorInfo += "Failed to set the json flag to False \n Exception: {eInfo}\n".format(eInfo=e)
1543
1544 try:
1545 for i in range(3):
1546 sensorReadings = sensor(host, args, session)
1547 if 'OCC0' in sensorReadings:
1548 sensorsCollected = True
1549 break
1550 else:
1551 errorInfo += sensorReadings
1552 except Exception as e:
1553 errorInfo += "Sensor reading collection exception: {eInfo}\n".format(eInfo=e)
1554 if sensorsCollected:
1555 try:
1556 with open(fileDir +os.sep+'sensorReadings.txt', 'w') as f:
1557 f.write(sensorReadings)
1558 print("Sensor readings collected and stored in " + fileDir + os.sep+ "sensorReadings.txt")
1559 output['fileLoc'] = fileDir+os.sep+'sensorReadings.txt'
1560 except Exception as e:
1561 print("Failed to write sensor readings to file system.")
1562 errorInfo += "Error writing sensor readings to the file. Exception: {eInfo}\n".format(eInfo=e)
1563
1564 output['errors'] = errorInfo
1565 return output
1566
1567def csdLEDs(host,args, session, fileDir):
1568 """
1569 Collects the BMC LED status, retrying if necessary
1570
1571 @param host: string, the hostname or IP address of the bmc
1572 @param args: contains additional arguments used by the collectServiceData sub command
1573 @param session: the active session to use
1574 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1575 @param fileDir: string representation of the path to use for putting files created
1576 """
1577 errorInfo = "===========LEDs =============\n"
1578 ledsCollected = False
1579 output={}
1580 try:
1581 d = vars(args)
1582 d['json'] = True
1583 except Exception as e:
1584 errorInfo += "Failed to set the json flag to False \n Exception: {eInfo}\n".format(eInfo=e)
1585 try:
1586 url="https://"+host+"/xyz/openbmc_project/led/enumerate"
1587 httpHeader = {'Content-Type':'application/json'}
1588 for i in range(3):
1589 try:
1590 ledRes = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
1591 if ledRes.status_code == 200:
1592 ledsCollected = True
1593 leds = ledRes.json()['data']
1594 break
1595 else:
1596 errorInfo += ledRes.text
1597 except(requests.exceptions.Timeout):
1598 errorInfo+=json.dumps( connectionErrHandler(args.json, "Timeout", None), sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n'
1599 except(requests.exceptions.ConnectionError) as err:
1600 errorInfo += json.dumps(connectionErrHandler(args.json, "ConnectionError", err), sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n'
1601 except Exception as e:
1602 errorInfo += "LED status collection exception: {eInfo}\n".format(eInfo=e)
1603
1604 if ledsCollected:
1605 try:
1606 with open(fileDir +os.sep+'ledStatus.txt', 'w') as f:
1607 f.write(json.dumps(leds, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n')
1608 print("LED status collected and stored in " + fileDir + os.sep+ "ledStatus.txt")
1609 output['fileLoc'] = fileDir+os.sep+'ledStatus.txt'
1610 except Exception as e:
1611 print("Failed to write LED status to file system.")
1612 errorInfo += "Error writing LED status to the file. Exception: {eInfo}\n".format(eInfo=e)
1613
1614 output['errors'] = errorInfo
1615 return output
1616
1617def csdSelShortList(host, args, session, fileDir):
1618 """
1619 Collects the BMC log entries, retrying if necessary
1620
1621 @param host: string, the hostname or IP address of the bmc
1622 @param args: contains additional arguments used by the collectServiceData sub command
1623 @param session: the active session to use
1624 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1625 @param fileDir: string representation of the path to use for putting files created
1626 """
1627 errorInfo = "===========SEL Short List =============\n"
1628 selsCollected = False
1629 output={}
1630 try:
1631 d = vars(args)
1632 d['json'] = False
1633 except Exception as e:
1634 errorInfo += "Failed to set the json flag to False \n Exception: {eInfo}\n".format(eInfo=e)
1635
1636 try:
1637 for i in range(3):
1638 sels = selPrint(host,args,session)
1639 if '----Active Alerts----' in sels or 'No log entries found' in sels or '----Historical Alerts----' in sels:
1640 selsCollected = True
1641 break
1642 else:
1643 errorInfo += sels + '\n'
1644 except Exception as e:
1645 errorInfo += "SEL short list collection exception: {eInfo}\n".format(eInfo=e)
1646
1647 if selsCollected:
1648 try:
1649 with open(fileDir +os.sep+'SELshortlist.txt', 'w') as f:
1650 f.write(sels)
1651 print("SEL short list collected and stored in " + fileDir + os.sep+ "SELshortlist.txt")
1652 output['fileLoc'] = fileDir+os.sep+'SELshortlist.txt'
1653 except Exception as e:
1654 print("Failed to write SEL short list to file system.")
1655 errorInfo += "Error writing SEL short list to the file. Exception: {eInfo}\n".format(eInfo=e)
1656
1657 output['errors'] = errorInfo
1658 return output
1659
1660def csdParsedSels(host, args, session, fileDir):
1661 """
1662 Collects the BMC log entries, retrying if necessary
1663
1664 @param host: string, the hostname or IP address of the bmc
1665 @param args: contains additional arguments used by the collectServiceData sub command
1666 @param session: the active session to use
1667 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1668 @param fileDir: string representation of the path to use for putting files created
1669 """
1670 errorInfo = "===========SEL Parsed List =============\n"
1671 selsCollected = False
1672 output={}
1673 try:
1674 d = vars(args)
1675 d['json'] = True
1676 d['fullEsel'] = True
1677 except Exception as e:
1678 errorInfo += "Failed to set the json flag to True \n Exception: {eInfo}\n".format(eInfo=e)
1679
1680 try:
1681 for i in range(3):
1682 parsedfullsels = json.loads(selPrint(host,args,session))
1683 if 'numAlerts' in parsedfullsels:
1684 selsCollected = True
1685 break
1686 else:
1687 errorInfo += parsedfullsels + '\n'
1688 except Exception as e:
1689 errorInfo += "Parsed full SELs collection exception: {eInfo}\n".format(eInfo=e)
1690
1691 if selsCollected:
1692 try:
1693 sortedSELs = sortSELs(parsedfullsels)
1694 with open(fileDir +os.sep+'parsedSELs.txt', 'w') as f:
1695 for log in sortedSELs[0]:
1696 esel = ""
1697 parsedfullsels[sortedSELs[1][str(log)]]['timestamp'] = datetime.datetime.fromtimestamp(int(parsedfullsels[sortedSELs[1][str(log)]]['timestamp']/1000)).strftime("%Y-%m-%d %H:%M:%S")
1698 if ('raweSEL' in parsedfullsels[sortedSELs[1][str(log)]] and args.devdebug):
1699 esel = parsedfullsels[sortedSELs[1][str(log)]]['raweSEL']
1700 del parsedfullsels[sortedSELs[1][str(log)]]['raweSEL']
1701 f.write(json.dumps(parsedfullsels[sortedSELs[1][str(log)]],sort_keys=True, indent=4, separators=(',', ': ')))
1702 if(args.devdebug and esel != ""):
1703 f.write(parseESEL(args, esel))
1704 print("Parsed SELs collected and stored in " + fileDir + os.sep+ "parsedSELs.txt")
1705 output['fileLoc'] = fileDir+os.sep+'parsedSELs.txt'
1706 except Exception as e:
1707 print("Failed to write fully parsed SELs to file system.")
1708 errorInfo += "Error writing fully parsed SELs to the file. Exception: {eInfo}\n".format(eInfo=e)
1709
1710 output['errors'] = errorInfo
1711 return output
1712
1713def csdFullEnumeration(host, args, session, fileDir):
1714 """
1715 Collects a full enumeration of /xyz/openbmc_project/, retrying if necessary
1716
1717 @param host: string, the hostname or IP address of the bmc
1718 @param args: contains additional arguments used by the collectServiceData sub command
1719 @param session: the active session to use
1720 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1721 @param fileDir: string representation of the path to use for putting files created
1722 """
1723 errorInfo = "===========BMC Full Enumeration =============\n"
1724 bmcFullCollected = False
1725 output={}
1726 try:
1727 d = vars(args)
1728 d['json'] = True
1729 except Exception as e:
1730 errorInfo += "Failed to set the json flag to False \n Exception: {eInfo}\n".format(eInfo=e)
1731 try:
1732 print("Attempting to get a full BMC enumeration")
1733 url="https://"+host+"/xyz/openbmc_project/enumerate"
1734 httpHeader = {'Content-Type':'application/json'}
1735 for i in range(3):
1736 try:
1737 bmcRes = session.get(url, headers=jsonHeader, verify=False, timeout=180)
1738 if bmcRes.status_code == 200:
1739 bmcFullCollected = True
1740 fullEnumeration = bmcRes.json()
1741 break
1742 else:
1743 errorInfo += bmcRes.text
1744 except(requests.exceptions.Timeout):
1745 errorInfo+=json.dumps( connectionErrHandler(args.json, "Timeout", None), sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n'
1746 except(requests.exceptions.ConnectionError) as err:
1747 errorInfo += json.dumps(connectionErrHandler(args.json, "ConnectionError", err), sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n'
1748 except Exception as e:
1749 errorInfo += "RAW BMC data collection exception: {eInfo}\n".format(eInfo=e)
1750
1751 if bmcFullCollected:
1752 try:
1753 with open(fileDir +os.sep+'bmcFullRaw.txt', 'w') as f:
1754 f.write(json.dumps(fullEnumeration, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n')
1755 print("RAW BMC data collected and saved into " + fileDir + os.sep+ "bmcFullRaw.txt")
1756 output['fileLoc'] = fileDir+os.sep+'bmcFullRaw.txt'
1757 except Exception as e:
1758 print("Failed to write RAW BMC data to file system.")
1759 errorInfo += "Error writing RAW BMC data collection to the file. Exception: {eInfo}\n".format(eInfo=e)
1760
1761 output['errors'] = errorInfo
1762 return output
1763
1764def csdCollectAllDumps(host, args, session, fileDir):
1765 """
1766 Collects all of the bmc dump files and stores them in fileDir
1767
1768 @param host: string, the hostname or IP address of the bmc
1769 @param args: contains additional arguments used by the collectServiceData sub command
1770 @param session: the active session to use
1771 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1772 @param fileDir: string representation of the path to use for putting files created
1773 """
1774
1775 errorInfo = "===========BMC Dump Collection =============\n"
1776 dumpListCollected = False
1777 output={}
1778 dumpList = {}
1779 try:
1780 d = vars(args)
1781 d['json'] = True
1782 d['dumpSaveLoc'] = fileDir
1783 except Exception as e:
1784 errorInfo += "Failed to set the json flag to True, or failed to set the dumpSave Location \n Exception: {eInfo}\n".format(eInfo=e)
1785
1786 print('Collecting bmc dump files')
1787
1788 try:
1789 for i in range(3):
1790 dumpResp = bmcDumpList(host, args, session)
1791 if 'message' in dumpResp:
1792 if 'ok' in dumpResp['message'].lower():
1793 dumpList = dumpResp['data']
1794 dumpListCollected = True
1795 break
1796 else:
1797 errorInfo += "Status was not OK when retrieving the list of dumps available. \n Response: \n{resp}\n".format(resp=dumpResp)
1798 else:
1799 errorInfo += "Invalid response received from the BMC while retrieving the list of dumps available.\n {resp}\n".format(resp=dumpResp)
1800 except Exception as e:
1801 errorInfo += "BMC dump list exception: {eInfo}\n".format(eInfo=e)
1802
1803 if dumpListCollected:
1804 output['fileList'] = []
1805 for dump in dumpList:
1806 try:
1807 if '/xyz/openbmc_project/dump/internal/manager' not in dump:
1808 d['dumpNum'] = int(dump.strip().split('/')[-1])
1809 print('retrieving dump file ' + str(d['dumpNum']))
1810 filename = bmcDumpRetrieve(host, args, session).split('Saved as ')[-1]
1811 output['fileList'].append(filename)
1812 except Exception as e:
1813 print("Unable to collect dump: {dumpInfo}".format(dumpInfo=dump))
1814 errorInfo += "Exception collecting a bmc dump {dumpInfo}\n {eInfo}\n".format(dumpInfo=dump, eInfo=e)
1815 output['errors'] = errorInfo
1816 return output
Justin Thalere412dc22018-01-12 16:28:24 -06001817
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001818def collectServiceData(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001819 """
1820 Collects all data needed for service from the BMC
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001821
Justin Thalere412dc22018-01-12 16:28:24 -06001822 @param host: string, the hostname or IP address of the bmc
1823 @param args: contains additional arguments used by the collectServiceData sub command
1824 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001825 @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 -06001826 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001827
Justin Thaler22b1bb52018-03-15 13:31:32 -05001828 global toolVersion
Justin Thaler666cf342019-01-23 14:44:27 -06001829 filelist = []
1830 errorInfo = ""
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001831
Justin Thaler666cf342019-01-23 14:44:27 -06001832 #get current number of bmc dumps and create a new bmc dump
1833 dumpInitdata = csdDumpInitiate(host, args, session)
1834 dumpcount = dumpInitdata['dumpcount']
1835 errorInfo += dumpInitdata['errors']
1836 #create the directory to put files
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001837 try:
1838 args.silent = True
Justin Thalercf1deae2018-05-25 19:35:21 -05001839 myDir = tempfile.gettempdir()+os.sep + host + "--" + datetime.datetime.now().strftime("%Y-%m-%d_%H.%M.%S")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001840 os.makedirs(myDir)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001841
Justin Thaler666cf342019-01-23 14:44:27 -06001842 except Exception as e:
1843 print('Unable to create the temporary directory for data collection. Ensure sufficient privileges to create temporary directory. Aborting.')
1844 return("Python exception: {eInfo}".format(eInfo = e))
1845
1846 #Collect Inventory
1847 inventoryData = csdInventory(host, args, session, myDir)
1848 if 'fileLoc' in inventoryData:
1849 filelist.append(inventoryData['fileLoc'])
1850 errorInfo += inventoryData['errors']
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001851 #Read all the sensor and OCC status
Justin Thaler666cf342019-01-23 14:44:27 -06001852 sensorData = csdSensors(host,args,session,myDir)
1853 if 'fileLoc' in sensorData:
1854 filelist.append(sensorData['fileLoc'])
1855 errorInfo += sensorData['errors']
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001856 #Collect all of the LEDs status
Justin Thaler666cf342019-01-23 14:44:27 -06001857 ledStatus = csdLEDs(host, args, session, myDir)
1858 if 'fileLoc' in ledStatus:
1859 filelist.append(ledStatus['fileLoc'])
1860 errorInfo += ledStatus['errors']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001861
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001862 #Collect the bmc logs
Justin Thaler666cf342019-01-23 14:44:27 -06001863 selShort = csdSelShortList(host, args, session, myDir)
1864 if 'fileLoc' in selShort:
1865 filelist.append(selShort['fileLoc'])
1866 errorInfo += selShort['errors']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001867
Justin Thaler666cf342019-01-23 14:44:27 -06001868 parsedSELs = csdParsedSels(host, args, session, myDir)
1869 if 'fileLoc' in parsedSELs:
1870 filelist.append(parsedSELs['fileLoc'])
1871 errorInfo += parsedSELs['errors']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001872
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001873 #collect RAW bmc enumeration
Justin Thaler666cf342019-01-23 14:44:27 -06001874 bmcRaw = csdFullEnumeration(host, args, session, myDir)
1875 if 'fileLoc' in bmcRaw:
1876 filelist.append(bmcRaw['fileLoc'])
1877 errorInfo += bmcRaw['errors']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001878
Justin Thaler666cf342019-01-23 14:44:27 -06001879 #wait for new dump to finish being created
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001880 waitingForNewDump = True
1881 count = 0;
Justin Thaler666cf342019-01-23 14:44:27 -06001882 print("Waiting for new BMC dump to finish being created.")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001883 while(waitingForNewDump):
Justin Thaler666cf342019-01-23 14:44:27 -06001884 dumpList = bmcDumpList(host, args, session)['data']
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001885 if len(dumpList) > dumpcount:
1886 waitingForNewDump = False
1887 break;
1888 elif(count>30):
1889 print("Timed out waiting for bmc to make a new dump file. Dump space may be full.")
1890 break;
1891 else:
1892 time.sleep(2)
1893 count += 1
Justin Thaler666cf342019-01-23 14:44:27 -06001894
1895 #collect all of the dump files
1896 getBMCDumps = csdCollectAllDumps(host, args, session, myDir)
1897 if 'fileList' in getBMCDumps:
1898 filelist+= getBMCDumps['fileList']
1899 errorInfo += getBMCDumps['errors']
1900
1901 #write the runtime errors to a file
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001902 try:
Justin Thaler666cf342019-01-23 14:44:27 -06001903 with open(myDir +os.sep+'openbmctoolRuntimeErrors.txt', 'w') as f:
1904 f.write(errorInfo)
1905 print("OpenBMC tool runtime errors collected and stored in " + myDir + os.sep+ "openbmctoolRuntimeErrors.txt")
1906 filelist.append(myDir+os.sep+'openbmctoolRuntimeErrors.txt')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001907 except Exception as e:
Justin Thaler666cf342019-01-23 14:44:27 -06001908 print("Failed to write OpenBMC tool runtime errors to file system.")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001909
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001910 #create the zip file
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001911 try:
Justin Thalercf1deae2018-05-25 19:35:21 -05001912 filename = myDir.split(tempfile.gettempdir()+os.sep)[-1] + "_" + toolVersion + '_openbmc.zip'
Justin Thaler666cf342019-01-23 14:44:27 -06001913 zf = zipfile.ZipFile(myDir+os.sep + filename, 'w')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001914 for myfile in filelist:
1915 zf.write(myfile, os.path.basename(myfile))
1916 zf.close()
Justin Thaler666cf342019-01-23 14:44:27 -06001917 print("Zip file with all collected data created and stored in: {fileInfo}".format(fileInfo=myDir+os.sep+filename))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001918 except Exception as e:
1919 print("Failed to create zip file with collected information")
Justin Thaler666cf342019-01-23 14:44:27 -06001920 return "data collection finished"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001921
Justin Thalere412dc22018-01-12 16:28:24 -06001922
1923def healthCheck(host, args, session):
1924 """
1925 runs a health check on the platform
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001926
Justin Thalere412dc22018-01-12 16:28:24 -06001927 @param host: string, the hostname or IP address of the bmc
1928 @param args: contains additional arguments used by the bmc sub command
1929 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001930 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1931 """
Justin Thalere412dc22018-01-12 16:28:24 -06001932 #check fru status and get as json to easily work through
1933 d = vars(args)
1934 useJson = d['json']
1935 d['json'] = True
1936 d['verbose']= False
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001937
Justin Thalere412dc22018-01-12 16:28:24 -06001938 frus = json.loads(fruStatus(host, args, session))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001939
Justin Thalere412dc22018-01-12 16:28:24 -06001940 hwStatus= "OK"
1941 performanceStatus = "OK"
1942 for key in frus:
1943 if frus[key]["Functional"] == "No" and frus[key]["Present"] == "Yes":
1944 hwStatus= "Degraded"
Justin Thalerfb9c81c2018-07-16 11:14:37 -05001945 if("power_supply" in key or "powersupply" in key):
1946 gpuCount =0
1947 for comp in frus:
Justin Thalere412dc22018-01-12 16:28:24 -06001948 if "gv100card" in comp:
1949 gpuCount +=1
1950 if gpuCount > 4:
1951 hwStatus = "Critical"
1952 performanceStatus="Degraded"
1953 break;
1954 elif("fan" in key):
1955 hwStatus = "Degraded"
1956 else:
1957 performanceStatus = "Degraded"
1958 if useJson:
1959 output = {"Hardware Status": hwStatus, "Performance": performanceStatus}
1960 output = json.dumps(output, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False)
1961 else:
1962 output = ("Hardware Status: " + hwStatus +
1963 "\nPerformance: " +performanceStatus )
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001964
1965
Justin Thalere412dc22018-01-12 16:28:24 -06001966 #SW407886: Clear the duplicate entries
1967 #collect the dups
1968 d['devdebug'] = False
1969 sels = json.loads(selPrint(host, args, session))
1970 logNums2Clr = []
1971 oldestLogNum={"logNum": "bogus" ,"key" : ""}
1972 count = 0
1973 if sels['numAlerts'] > 0:
1974 for key in sels:
1975 if "numAlerts" in key:
1976 continue
1977 try:
1978 if "slave@00:00/00:00:00:06/sbefifo1-dev0/occ1-dev0" in sels[key]['Message']:
1979 count += 1
1980 if count > 1:
1981 #preserve first occurrence
1982 if sels[key]['timestamp'] < sels[oldestLogNum['key']]['timestamp']:
1983 oldestLogNum['key']=key
1984 oldestLogNum['logNum'] = sels[key]['logNum']
1985 else:
1986 oldestLogNum['key']=key
1987 oldestLogNum['logNum'] = sels[key]['logNum']
1988 logNums2Clr.append(sels[key]['logNum'])
1989 except KeyError:
1990 continue
1991 if(count >0):
1992 logNums2Clr.remove(oldestLogNum['logNum'])
1993 #delete the dups
1994 if count >1:
Justin Thalere412dc22018-01-12 16:28:24 -06001995 data = "{\"data\": [] }"
1996 for logNum in logNums2Clr:
1997 url = "https://"+ host+ "/xyz/openbmc_project/logging/entry/"+logNum+"/action/Delete"
1998 try:
Justin Thaler27197622019-01-23 14:42:11 -06001999 session.post(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002000 except(requests.exceptions.Timeout):
2001 deleteFailed = True
2002 except(requests.exceptions.ConnectionError) as err:
2003 deleteFailed = True
2004 #End of defect resolve code
2005 d['json'] = useJson
2006 return output
2007
2008
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002009
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002010def bmc(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06002011 """
2012 handles various bmc level commands, currently bmc rebooting
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002013
Justin Thalere412dc22018-01-12 16:28:24 -06002014 @param host: string, the hostname or IP address of the bmc
2015 @param args: contains additional arguments used by the bmc sub command
2016 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002017 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
2018 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002019 if(args.type is not None):
2020 return bmcReset(host, args, session)
Justin Thalere412dc22018-01-12 16:28:24 -06002021 if(args.info):
2022 return "Not implemented at this time"
2023
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002024
Justin Thalere412dc22018-01-12 16:28:24 -06002025
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002026def bmcReset(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06002027 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002028 controls resetting the bmc. warm reset reboots the bmc, cold reset removes the configuration and reboots.
2029
Justin Thalere412dc22018-01-12 16:28:24 -06002030 @param host: string, the hostname or IP address of the bmc
2031 @param args: contains additional arguments used by the bmcReset sub command
2032 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002033 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
2034 """
Justin Thaler22b1bb52018-03-15 13:31:32 -05002035 if checkFWactivation(host, args, session):
2036 return ("BMC reset control disabled during firmware activation")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002037 if(args.type == "warm"):
2038 print("\nAttempting to reboot the BMC...:")
2039 url="https://"+host+"/xyz/openbmc_project/state/bmc0/attr/RequestedBMCTransition"
Justin Thalere412dc22018-01-12 16:28:24 -06002040 data = '{"data":"xyz.openbmc_project.State.BMC.Transition.Reboot"}'
Justin Thaler27197622019-01-23 14:42:11 -06002041 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002042 return res.text
2043 elif(args.type =="cold"):
Justin Thalere412dc22018-01-12 16:28:24 -06002044 print("\nAttempting to reboot the BMC...:")
2045 url="https://"+host+"/xyz/openbmc_project/state/bmc0/attr/RequestedBMCTransition"
Justin Thalere412dc22018-01-12 16:28:24 -06002046 data = '{"data":"xyz.openbmc_project.State.BMC.Transition.Reboot"}'
Justin Thaler27197622019-01-23 14:42:11 -06002047 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002048 return res.text
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002049 else:
2050 return "invalid command"
Justin Thalere412dc22018-01-12 16:28:24 -06002051
2052def gardClear(host, args, session):
2053 """
2054 clears the gard records from the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002055
Justin Thalere412dc22018-01-12 16:28:24 -06002056 @param host: string, the hostname or IP address of the bmc
2057 @param args: contains additional arguments used by the gardClear sub command
2058 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002059 """
Justin Thalere412dc22018-01-12 16:28:24 -06002060 url="https://"+host+"/org/open_power/control/gard/action/Reset"
Justin Thalere412dc22018-01-12 16:28:24 -06002061 data = '{"data":[]}'
2062 try:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002063
Justin Thaler27197622019-01-23 14:42:11 -06002064 res = session.post(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002065 if res.status_code == 404:
2066 return "Command not supported by this firmware version"
2067 else:
2068 return res.text
2069 except(requests.exceptions.Timeout):
2070 return connectionErrHandler(args.json, "Timeout", None)
2071 except(requests.exceptions.ConnectionError) as err:
2072 return connectionErrHandler(args.json, "ConnectionError", err)
2073
2074def activateFWImage(host, args, session):
2075 """
2076 activates a firmware image on the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002077
Justin Thalere412dc22018-01-12 16:28:24 -06002078 @param host: string, the hostname or IP address of the bmc
2079 @param args: contains additional arguments used by the fwflash sub command
2080 @param session: the active session to use
2081 @param fwID: the unique ID of the fw image to activate
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002082 """
Justin Thalere412dc22018-01-12 16:28:24 -06002083 fwID = args.imageID
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002084
Justin Thalere412dc22018-01-12 16:28:24 -06002085 #determine the existing versions
Justin Thalere412dc22018-01-12 16:28:24 -06002086 url="https://"+host+"/xyz/openbmc_project/software/enumerate"
2087 try:
Justin Thaler27197622019-01-23 14:42:11 -06002088 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002089 except(requests.exceptions.Timeout):
2090 return connectionErrHandler(args.json, "Timeout", None)
2091 except(requests.exceptions.ConnectionError) as err:
2092 return connectionErrHandler(args.json, "ConnectionError", err)
2093 existingSoftware = json.loads(resp.text)['data']
2094 altVersionID = ''
2095 versionType = ''
2096 imageKey = '/xyz/openbmc_project/software/'+fwID
2097 if imageKey in existingSoftware:
2098 versionType = existingSoftware[imageKey]['Purpose']
2099 for key in existingSoftware:
2100 if imageKey == key:
2101 continue
2102 if 'Purpose' in existingSoftware[key]:
2103 if versionType == existingSoftware[key]['Purpose']:
2104 altVersionID = key.split('/')[-1]
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002105
2106
2107
2108
Justin Thalere412dc22018-01-12 16:28:24 -06002109 url="https://"+host+"/xyz/openbmc_project/software/"+ fwID + "/attr/Priority"
2110 url1="https://"+host+"/xyz/openbmc_project/software/"+ altVersionID + "/attr/Priority"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002111 data = "{\"data\": 0}"
Justin Thalere412dc22018-01-12 16:28:24 -06002112 data1 = "{\"data\": 1 }"
2113 try:
Justin Thaler27197622019-01-23 14:42:11 -06002114 resp = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
2115 resp1 = session.put(url1, headers=jsonHeader, data=data1, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002116 except(requests.exceptions.Timeout):
2117 return connectionErrHandler(args.json, "Timeout", None)
2118 except(requests.exceptions.ConnectionError) as err:
2119 return connectionErrHandler(args.json, "ConnectionError", err)
2120 if(not args.json):
2121 if resp.status_code == 200 and resp1.status_code == 200:
Justin Thaler22b1bb52018-03-15 13:31:32 -05002122 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 -06002123 else:
2124 return "Firmware activation failed."
2125 else:
2126 return resp.text + resp1.text
Justin Thaler22b1bb52018-03-15 13:31:32 -05002127
2128def activateStatus(host, args, session):
2129 if checkFWactivation(host, args, session):
2130 return("Firmware is currently being activated. Do not reboot the BMC or start the Host OS")
2131 else:
2132 return("No firmware activations are pending")
2133
2134def extractFWimage(path, imageType):
2135 """
2136 extracts the bmc image and returns information about the package
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002137
Justin Thaler22b1bb52018-03-15 13:31:32 -05002138 @param path: the path and file name of the firmware image
2139 @param imageType: The type of image the user is trying to flash. Host or BMC
2140 @return: the image id associated with the package. returns an empty string on error.
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002141 """
Justin Thaler22b1bb52018-03-15 13:31:32 -05002142 f = tempfile.TemporaryFile()
2143 tmpDir = tempfile.gettempdir()
2144 newImageID = ""
2145 if os.path.exists(path):
2146 try:
2147 imageFile = tarfile.open(path,'r')
2148 contents = imageFile.getmembers()
2149 for tf in contents:
2150 if 'MANIFEST' in tf.name:
2151 imageFile.extract(tf.name, path=tmpDir)
2152 with open(tempfile.gettempdir() +os.sep+ tf.name, 'r') as imageInfo:
2153 for line in imageInfo:
2154 if 'purpose' in line:
2155 purpose = line.split('=')[1]
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002156 if imageType not in purpose.split('.')[-1]:
Justin Thaler22b1bb52018-03-15 13:31:32 -05002157 print('The specified image is not for ' + imageType)
2158 print('Please try again with the image for ' + imageType)
2159 return ""
2160 if 'version' == line.split('=')[0]:
2161 version = line.split('=')[1].strip().encode('utf-8')
2162 m = hashlib.sha512()
2163 m.update(version)
2164 newImageID = m.hexdigest()[:8]
2165 break
2166 try:
2167 os.remove(tempfile.gettempdir() +os.sep+ tf.name)
2168 except OSError:
2169 pass
2170 return newImageID
2171 except tarfile.ExtractError as e:
2172 print('Unable to extract information from the firmware file.')
2173 print('Ensure you have write access to the directory: ' + tmpDir)
2174 return newImageID
2175 except tarfile.TarError as e:
2176 print('This is not a valid firmware file.')
2177 return newImageID
2178 print("This is not a valid firmware file.")
2179 return newImageID
2180 else:
2181 print('The filename and path provided are not valid.')
2182 return newImageID
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002183
Justin Thaler22b1bb52018-03-15 13:31:32 -05002184def getAllFWImageIDs(fwInvDict):
2185 """
2186 gets a list of all the firmware image IDs
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002187
Justin Thaler22b1bb52018-03-15 13:31:32 -05002188 @param fwInvDict: the dictionary to search for FW image IDs
2189 @return: list containing string representation of the found image ids
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002190 """
Justin Thaler22b1bb52018-03-15 13:31:32 -05002191 idList = []
2192 for key in fwInvDict:
2193 if 'Version' in fwInvDict[key]:
2194 idList.append(key.split('/')[-1])
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002195 return idList
2196
Justin Thalere412dc22018-01-12 16:28:24 -06002197def fwFlash(host, args, session):
2198 """
2199 updates the bmc firmware and pnor firmware
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002200
Justin Thalere412dc22018-01-12 16:28:24 -06002201 @param host: string, the hostname or IP address of the bmc
2202 @param args: contains additional arguments used by the fwflash sub command
2203 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002204 """
Justin Thaler22b1bb52018-03-15 13:31:32 -05002205 d = vars(args)
Justin Thalere412dc22018-01-12 16:28:24 -06002206 if(args.type == 'bmc'):
2207 purp = 'BMC'
2208 else:
2209 purp = 'Host'
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002210
2211 #check power state of the machine. No concurrent FW updates allowed
Justin Thaler22b1bb52018-03-15 13:31:32 -05002212 d['powcmd'] = 'status'
2213 powerstate = chassisPower(host, args, session)
2214 if 'Chassis Power State: On' in powerstate:
2215 return("Aborting firmware update. Host is powered on. Please turn off the host and try again.")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002216
Justin Thaler22b1bb52018-03-15 13:31:32 -05002217 #determine the existing images on the bmc
Justin Thalere412dc22018-01-12 16:28:24 -06002218 url="https://"+host+"/xyz/openbmc_project/software/enumerate"
2219 try:
Justin Thaler27197622019-01-23 14:42:11 -06002220 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002221 except(requests.exceptions.Timeout):
2222 return connectionErrHandler(args.json, "Timeout", None)
2223 except(requests.exceptions.ConnectionError) as err:
2224 return connectionErrHandler(args.json, "ConnectionError", err)
2225 oldsoftware = json.loads(resp.text)['data']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002226
Justin Thaler22b1bb52018-03-15 13:31:32 -05002227 #Extract the tar and get information from the manifest file
2228 newversionID = extractFWimage(args.fileloc, purp)
2229 if newversionID == "":
2230 return "Unable to verify FW image."
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002231
2232
Justin Thaler22b1bb52018-03-15 13:31:32 -05002233 #check if the new image is already on the bmc
2234 if newversionID not in getAllFWImageIDs(oldsoftware):
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002235
Justin Thaler22b1bb52018-03-15 13:31:32 -05002236 #upload the file
2237 httpHeader = {'Content-Type':'application/octet-stream'}
Matt Spinler220c3c42019-01-04 15:09:29 -06002238 httpHeader.update(xAuthHeader)
Justin Thaler22b1bb52018-03-15 13:31:32 -05002239 url="https://"+host+"/upload/image"
2240 data=open(args.fileloc,'rb').read()
2241 print("Uploading file to BMC")
Justin Thalere412dc22018-01-12 16:28:24 -06002242 try:
Justin Thaler22b1bb52018-03-15 13:31:32 -05002243 resp = session.post(url, headers=httpHeader, data=data, verify=False)
Justin Thalere412dc22018-01-12 16:28:24 -06002244 except(requests.exceptions.Timeout):
2245 return connectionErrHandler(args.json, "Timeout", None)
2246 except(requests.exceptions.ConnectionError) as err:
2247 return connectionErrHandler(args.json, "ConnectionError", err)
Justin Thaler22b1bb52018-03-15 13:31:32 -05002248 if resp.status_code != 200:
2249 return "Failed to upload the file to the bmc"
Justin Thalere412dc22018-01-12 16:28:24 -06002250 else:
Justin Thaler22b1bb52018-03-15 13:31:32 -05002251 print("Upload complete.")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002252
Justin Thaler22b1bb52018-03-15 13:31:32 -05002253 #verify bmc processed the image
2254 software ={}
2255 for i in range(0, 5):
Justin Thaler22b1bb52018-03-15 13:31:32 -05002256 url="https://"+host+"/xyz/openbmc_project/software/enumerate"
2257 try:
Justin Thaler27197622019-01-23 14:42:11 -06002258 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thaler22b1bb52018-03-15 13:31:32 -05002259 except(requests.exceptions.Timeout):
2260 return connectionErrHandler(args.json, "Timeout", None)
2261 except(requests.exceptions.ConnectionError) as err:
2262 return connectionErrHandler(args.json, "ConnectionError", err)
2263 software = json.loads(resp.text)['data']
2264 #check if bmc is done processing the new image
2265 if (newversionID in getAllFWImageIDs(software)):
Justin Thalere412dc22018-01-12 16:28:24 -06002266 break
Justin Thaler22b1bb52018-03-15 13:31:32 -05002267 else:
2268 time.sleep(15)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002269
Justin Thaler22b1bb52018-03-15 13:31:32 -05002270 #activate the new image
2271 print("Activating new image: "+newversionID)
2272 url="https://"+host+"/xyz/openbmc_project/software/"+ newversionID + "/attr/RequestedActivation"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002273 data = '{"data":"xyz.openbmc_project.Software.Activation.RequestedActivations.Active"}'
Justin Thaler22b1bb52018-03-15 13:31:32 -05002274 try:
Justin Thaler27197622019-01-23 14:42:11 -06002275 resp = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thaler22b1bb52018-03-15 13:31:32 -05002276 except(requests.exceptions.Timeout):
2277 return connectionErrHandler(args.json, "Timeout", None)
2278 except(requests.exceptions.ConnectionError) as err:
2279 return connectionErrHandler(args.json, "ConnectionError", err)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002280
Justin Thaler22b1bb52018-03-15 13:31:32 -05002281 #wait for the activation to complete, timeout after ~1 hour
2282 i=0
2283 while i < 360:
2284 url="https://"+host+"/xyz/openbmc_project/software/"+ newversionID
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002285 data = '{"data":"xyz.openbmc_project.Software.Activation.RequestedActivations.Active"}'
Justin Thaler22b1bb52018-03-15 13:31:32 -05002286 try:
Justin Thaler27197622019-01-23 14:42:11 -06002287 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thaler22b1bb52018-03-15 13:31:32 -05002288 except(requests.exceptions.Timeout):
2289 return connectionErrHandler(args.json, "Timeout", None)
2290 except(requests.exceptions.ConnectionError) as err:
2291 return connectionErrHandler(args.json, "ConnectionError", err)
2292 fwInfo = json.loads(resp.text)['data']
2293 if 'Activating' not in fwInfo['Activation'] and 'Activating' not in fwInfo['RequestedActivation']:
2294 print('')
2295 break
2296 else:
2297 sys.stdout.write('.')
2298 sys.stdout.flush()
2299 time.sleep(10) #check every 10 seconds
2300 return "Firmware flash and activation completed. Please reboot the bmc and then boot the host OS for the changes to take effect. "
2301 else:
2302 print("This image has been found on the bmc. Activating image: " + newversionID)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002303
Justin Thaler22b1bb52018-03-15 13:31:32 -05002304 d['imageID'] = newversionID
2305 return activateFWImage(host, args, session)
Justin Thalere412dc22018-01-12 16:28:24 -06002306
Justin Thaler3d71d402018-07-24 14:35:39 -05002307def getFWInventoryAttributes(rawFWInvItem, ID):
2308 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002309 gets and lists all of the firmware in the system.
2310
Justin Thaler3d71d402018-07-24 14:35:39 -05002311 @return: returns a dictionary containing the image attributes
2312 """
2313 reqActivation = rawFWInvItem["RequestedActivation"].split('.')[-1]
2314 pendingActivation = ""
2315 if reqActivation == "None":
2316 pendingActivation = "No"
2317 else:
2318 pendingActivation = "Yes"
2319 firmwareAttr = {ID: {
2320 "Purpose": rawFWInvItem["Purpose"].split('.')[-1],
2321 "Version": rawFWInvItem["Version"],
2322 "RequestedActivation": pendingActivation,
2323 "ID": ID}}
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002324
Justin Thaler3d71d402018-07-24 14:35:39 -05002325 if "ExtendedVersion" in rawFWInvItem:
2326 firmwareAttr[ID]['ExtendedVersion'] = rawFWInvItem['ExtendedVersion'].split(',')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002327 else:
Justin Thaler3d71d402018-07-24 14:35:39 -05002328 firmwareAttr[ID]['ExtendedVersion'] = ""
2329 return firmwareAttr
2330
2331def parseFWdata(firmwareDict):
2332 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002333 creates a dictionary with parsed firmware data
2334
Justin Thaler3d71d402018-07-24 14:35:39 -05002335 @return: returns a dictionary containing the image attributes
2336 """
2337 firmwareInfoDict = {"Functional": {}, "Activated":{}, "NeedsActivated":{}}
2338 for key in firmwareDict['data']:
2339 #check for valid endpoint
2340 if "Purpose" in firmwareDict['data'][key]:
2341 id = key.split('/')[-1]
2342 if firmwareDict['data'][key]['Activation'].split('.')[-1] == "Active":
2343 fwActivated = True
2344 else:
2345 fwActivated = False
Justin Thalercb68e062019-03-26 19:04:52 -05002346 if 'Priority' in firmwareDict['data'][key]:
2347 if firmwareDict['data'][key]['Priority'] == 0:
2348 firmwareInfoDict['Functional'].update(getFWInventoryAttributes(firmwareDict['data'][key], id))
2349 elif firmwareDict['data'][key]['Priority'] >= 0 and fwActivated:
2350 firmwareInfoDict['Activated'].update(getFWInventoryAttributes(firmwareDict['data'][key], id))
2351 else:
2352 firmwareInfoDict['NeedsActivated'].update(getFWInventoryAttributes(firmwareDict['data'][key], id))
Justin Thaler3d71d402018-07-24 14:35:39 -05002353 else:
Justin Thalercb68e062019-03-26 19:04:52 -05002354 firmwareInfoDict['NeedsActivated'].update(getFWInventoryAttributes(firmwareDict['data'][key], id))
Justin Thaler3d71d402018-07-24 14:35:39 -05002355 emptySections = []
2356 for key in firmwareInfoDict:
2357 if len(firmwareInfoDict[key])<=0:
2358 emptySections.append(key)
2359 for key in emptySections:
2360 del firmwareInfoDict[key]
2361 return firmwareInfoDict
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002362
Justin Thaler3d71d402018-07-24 14:35:39 -05002363def displayFWInvenory(firmwareInfoDict, args):
2364 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002365 gets and lists all of the firmware in the system.
2366
Justin Thaler3d71d402018-07-24 14:35:39 -05002367 @return: returns a string containing all of the firmware information
2368 """
2369 output = ""
2370 if not args.json:
2371 for key in firmwareInfoDict:
2372 for subkey in firmwareInfoDict[key]:
2373 firmwareInfoDict[key][subkey]['ExtendedVersion'] = str(firmwareInfoDict[key][subkey]['ExtendedVersion'])
2374 if not args.verbose:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002375 output = "---Running Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002376 colNames = ["Purpose", "Version", "ID"]
2377 keylist = ["Purpose", "Version", "ID"]
2378 output += tableDisplay(keylist, colNames, firmwareInfoDict["Functional"])
2379 if "Activated" in firmwareInfoDict:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002380 output += "\n---Available Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002381 output += tableDisplay(keylist, colNames, firmwareInfoDict["Activated"])
2382 if "NeedsActivated" in firmwareInfoDict:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002383 output += "\n---Needs Activated Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002384 output += tableDisplay(keylist, colNames, firmwareInfoDict["NeedsActivated"])
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002385
Justin Thaler3d71d402018-07-24 14:35:39 -05002386 else:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002387 output = "---Running Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002388 colNames = ["Purpose", "Version", "ID", "Pending Activation", "Extended Version"]
2389 keylist = ["Purpose", "Version", "ID", "RequestedActivation", "ExtendedVersion"]
2390 output += tableDisplay(keylist, colNames, firmwareInfoDict["Functional"])
2391 if "Activated" in firmwareInfoDict:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002392 output += "\n---Available Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002393 output += tableDisplay(keylist, colNames, firmwareInfoDict["Activated"])
2394 if "NeedsActivated" in firmwareInfoDict:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002395 output += "\n---Needs Activated Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002396 output += tableDisplay(keylist, colNames, firmwareInfoDict["NeedsActivated"])
2397 return output
2398 else:
2399 return str(json.dumps(firmwareInfoDict, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False))
2400
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002401def firmwareList(host, args, session):
Justin Thaler3d71d402018-07-24 14:35:39 -05002402 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002403 gets and lists all of the firmware in the system.
2404
Justin Thaler3d71d402018-07-24 14:35:39 -05002405 @return: returns a string containing all of the firmware information
2406 """
Justin Thaler3d71d402018-07-24 14:35:39 -05002407 url="https://{hostname}/xyz/openbmc_project/software/enumerate".format(hostname=host)
2408 try:
Justin Thaler27197622019-01-23 14:42:11 -06002409 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thaler3d71d402018-07-24 14:35:39 -05002410 except(requests.exceptions.Timeout):
2411 return(connectionErrHandler(args.json, "Timeout", None))
2412 firmwareDict = json.loads(res.text)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002413
Justin Thaler3d71d402018-07-24 14:35:39 -05002414 #sort the received information
2415 firmwareInfoDict = parseFWdata(firmwareDict)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002416
Justin Thaler3d71d402018-07-24 14:35:39 -05002417 #display the information
2418 return displayFWInvenory(firmwareInfoDict, args)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002419
2420
Adriana Kobylak5af2fad2018-11-08 12:33:43 -06002421def deleteFWVersion(host, args, session):
2422 """
2423 deletes a firmware version on the BMC
2424
2425 @param host: string, the hostname or IP address of the BMC
2426 @param args: contains additional arguments used by the fwflash sub command
2427 @param session: the active session to use
2428 @param fwID: the unique ID of the fw version to delete
2429 """
2430 fwID = args.versionID
2431
2432 print("Deleting version: "+fwID)
2433 url="https://"+host+"/xyz/openbmc_project/software/"+ fwID + "/action/Delete"
Adriana Kobylak5af2fad2018-11-08 12:33:43 -06002434 data = "{\"data\": [] }"
2435
2436 try:
Justin Thaler27197622019-01-23 14:42:11 -06002437 res = session.post(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Adriana Kobylak5af2fad2018-11-08 12:33:43 -06002438 except(requests.exceptions.Timeout):
2439 return(connectionErrHandler(args.json, "Timeout", None))
2440 if res.status_code == 200:
2441 return ('The firmware version has been deleted')
2442 else:
2443 return ('Unable to delete the specified firmware version')
2444
2445
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05002446def restLogging(host, args, session):
2447 """
2448 Called by the logging function. Turns REST API logging on/off.
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002449
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05002450 @param host: string, the hostname or IP address of the bmc
2451 @param args: contains additional arguments used by the logging sub command
2452 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002453 @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 -05002454 """
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05002455 url="https://"+host+"/xyz/openbmc_project/logging/rest_api_logs/attr/Enabled"
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05002456
2457 if(args.rest_logging == 'on'):
2458 data = '{"data": 1}'
2459 elif(args.rest_logging == 'off'):
2460 data = '{"data": 0}'
2461 else:
2462 return "Invalid logging rest_api command"
2463
2464 try:
Justin Thaler27197622019-01-23 14:42:11 -06002465 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05002466 except(requests.exceptions.Timeout):
2467 return(connectionErrHandler(args.json, "Timeout", None))
2468 return res.text
2469
2470
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002471def remoteLogging(host, args, session):
2472 """
2473 Called by the logging function. View config information for/disable remote logging (rsyslog).
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002474
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002475 @param host: string, the hostname or IP address of the bmc
2476 @param args: contains additional arguments used by the logging sub command
2477 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002478 @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 -05002479 """
2480
2481 url="https://"+host+"/xyz/openbmc_project/logging/config/remote"
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002482
2483 try:
2484 if(args.remote_logging == 'view'):
Justin Thaler27197622019-01-23 14:42:11 -06002485 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002486 elif(args.remote_logging == 'disable'):
Justin Thaler27197622019-01-23 14:42:11 -06002487 res = session.put(url + '/attr/Port', headers=jsonHeader, json = {"data": 0}, verify=False, timeout=baseTimeout)
2488 res = session.put(url + '/attr/Address', headers=jsonHeader, json = {"data": ""}, verify=False, timeout=baseTimeout)
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002489 else:
2490 return "Invalid logging remote_logging command"
2491 except(requests.exceptions.Timeout):
2492 return(connectionErrHandler(args.json, "Timeout", None))
2493 return res.text
2494
2495
2496def remoteLoggingConfig(host, args, session):
2497 """
2498 Called by the logging function. Configures remote logging (rsyslog).
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002499
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002500 @param host: string, the hostname or IP address of the bmc
2501 @param args: contains additional arguments used by the logging sub command
2502 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002503 @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 -05002504 """
2505
2506 url="https://"+host+"/xyz/openbmc_project/logging/config/remote"
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002507
2508 try:
Justin Thaler27197622019-01-23 14:42:11 -06002509 res = session.put(url + '/attr/Port', headers=jsonHeader, json = {"data": args.port}, verify=False, timeout=baseTimeout)
2510 res = session.put(url + '/attr/Address', headers=jsonHeader, json = {"data": args.address}, verify=False, timeout=baseTimeout)
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002511 except(requests.exceptions.Timeout):
2512 return(connectionErrHandler(args.json, "Timeout", None))
2513 return res.text
2514
Marri Devender Rao82590dc2019-06-06 04:54:22 -05002515def redfishSupportPresent(host, session):
2516 url = "https://" + host + "/redfish/v1"
2517 try:
2518 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
2519 except(requests.exceptions.Timeout):
2520 return False
2521 except(requests.exceptions.ConnectionError) as err:
2522 return False
2523 if resp.status_code != 200:
2524 return False
2525 else:
2526 return True
Ratan Gupta9166cd22018-10-01 18:09:40 +05302527
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002528def certificateUpdate(host, args, session):
2529 """
2530 Called by certificate management function. update server/client/authority certificates
2531 Example:
2532 certificate update server https -f cert.pem
2533 certificate update authority ldap -f Root-CA.pem
2534 certificate update client ldap -f cert.pem
2535 @param host: string, the hostname or IP address of the bmc
2536 @param args: contains additional arguments used by the certificate update sub command
2537 @param session: the active session to use
2538 """
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002539 httpHeader = {'Content-Type': 'application/octet-stream'}
Matt Spinler220c3c42019-01-04 15:09:29 -06002540 httpHeader.update(xAuthHeader)
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002541 data = open(args.fileloc, 'rb').read()
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002542 try:
Marri Devender Rao82590dc2019-06-06 04:54:22 -05002543 if redfishSupportPresent(host, session):
2544 url = "";
2545 if(args.type.lower() == 'server'):
2546 url = "https://" + host + \
2547 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"
2548 elif(args.type.lower() == 'client'):
2549 url = "https://" + host + \
2550 "/redfish/v1/AccountService/LDAP/Certificates"
2551 elif(args.type.lower() == 'authority'):
2552 url = "https://" + host + \
2553 "/redfish/v1/Managers/bmc/Truststore/Certificates"
2554 else:
2555 return "Unsupported certificate type"
2556 resp = session.post(url, headers=httpHeader, data=data,
2557 verify=False)
2558 else:
2559 url = "https://" + host + "/xyz/openbmc_project/certs/" + \
2560 args.type.lower() + "/" + args.service.lower()
2561 resp = session.put(url, headers=httpHeader, data=data, verify=False)
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002562 except(requests.exceptions.Timeout):
2563 return(connectionErrHandler(args.json, "Timeout", None))
2564 except(requests.exceptions.ConnectionError) as err:
2565 return connectionErrHandler(args.json, "ConnectionError", err)
2566 if resp.status_code != 200:
2567 print(resp.text)
2568 return "Failed to update the certificate"
2569 else:
Marri Devender Rao82590dc2019-06-06 04:54:22 -05002570 print("Update complete.")
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002571
2572def certificateDelete(host, args, session):
2573 """
2574 Called by certificate management function to delete certificate
2575 Example:
2576 certificate delete server https
2577 certificate delete authority ldap
2578 certificate delete client ldap
2579 @param host: string, the hostname or IP address of the bmc
2580 @param args: contains additional arguments used by the certificate delete sub command
2581 @param session: the active session to use
2582 """
Marri Devender Rao77e78682019-07-17 03:18:35 -05002583 if redfishSupportPresent(host, session):
2584 return "Not supported, please use certificate replace instead";
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002585 httpHeader = {'Content-Type': 'multipart/form-data'}
Matt Spinler220c3c42019-01-04 15:09:29 -06002586 httpHeader.update(xAuthHeader)
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002587 url = "https://" + host + "/xyz/openbmc_project/certs/" + args.type.lower() + "/" + args.service.lower()
2588 print("Deleting certificate url=" + url)
2589 try:
2590 resp = session.delete(url, headers=httpHeader)
2591 except(requests.exceptions.Timeout):
2592 return(connectionErrHandler(args.json, "Timeout", None))
2593 except(requests.exceptions.ConnectionError) as err:
2594 return connectionErrHandler(args.json, "ConnectionError", err)
2595 if resp.status_code != 200:
2596 print(resp.text)
2597 return "Failed to delete the certificate"
2598 else:
Marri Devender Rao77e78682019-07-17 03:18:35 -05002599 print("Delete complete.")
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002600
Marri Devender Raodfe81ad2019-07-01 05:38:09 -05002601def certificateReplace(host, args, session):
2602 """
2603 Called by certificate management function. replace server/client/
2604 authority certificates
2605 Example:
2606 certificate replace server https -f cert.pem
2607 certificate replace authority ldap -f Root-CA.pem
2608 certificate replace client ldap -f cert.pem
2609 @param host: string, the hostname or IP address of the bmc
2610 @param args: contains additional arguments used by the certificate
2611 replace sub command
2612 @param session: the active session to use
2613 """
2614 cert = open(args.fileloc, 'rb').read()
2615 try:
2616 if redfishSupportPresent(host, session):
2617 httpHeader = {'Content-Type': 'application/json'}
2618 httpHeader.update(xAuthHeader)
2619 url = "";
2620 if(args.type.lower() == 'server'):
2621 url = "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/1"
2622 elif(args.type.lower() == 'client'):
2623 url = "/redfish/v1/AccountService/LDAP/Certificates/1"
2624 elif(args.type.lower() == 'authority'):
2625 url = "/redfish/v1/Managers/bmc/Truststore/Certificates/1"
2626 replaceUrl = "https://" + host + \
2627 "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate"
2628 data ={"CertificateUri":{"@odata.id":url}, "CertificateType":"PEM",
2629 "CertificateString":cert}
2630 resp = session.post(replaceUrl, headers=httpHeader, json=data, verify=False)
2631 else:
2632 httpHeader = {'Content-Type': 'application/octet-stream'}
2633 httpHeader.update(xAuthHeader)
2634 url = "https://" + host + "/xyz/openbmc_project/certs/" + \
2635 args.type.lower() + "/" + args.service.lower()
2636 resp = session.delete(url, headers=httpHeader)
2637 resp = session.put(url, headers=httpHeader, data=cert, verify=False)
2638 except(requests.exceptions.Timeout):
2639 return(connectionErrHandler(args.json, "Timeout", None))
2640 except(requests.exceptions.ConnectionError) as err:
2641 return connectionErrHandler(args.json, "ConnectionError", err)
2642 if resp.status_code != 200:
2643 print(resp.text)
2644 return "Failed to replace the certificate"
2645 else:
2646 print("Replace complete.")
2647 return resp.text
2648
Marri Devender Rao34646402019-07-01 05:46:03 -05002649def certificateDisplay(host, args, session):
2650 """
2651 Called by certificate management function. display server/client/
2652 authority certificates
2653 Example:
2654 certificate display server
2655 certificate display authority
2656 certificate display client
2657 @param host: string, the hostname or IP address of the bmc
2658 @param args: contains additional arguments used by the certificate
2659 display sub command
2660 @param session: the active session to use
2661 """
2662 if not redfishSupportPresent(host, session):
2663 return "Not supported";
2664
2665 httpHeader = {'Content-Type': 'application/octet-stream'}
2666 httpHeader.update(xAuthHeader)
2667 if(args.type.lower() == 'server'):
2668 url = "https://" + host + \
2669 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/1"
2670 elif(args.type.lower() == 'client'):
2671 url = "https://" + host + \
2672 "/redfish/v1/AccountService/LDAP/Certificates/1"
2673 elif(args.type.lower() == 'authority'):
2674 url = "https://" + host + \
2675 "/redfish/v1/Managers/bmc/Truststore/Certificates/1"
2676 try:
2677 resp = session.get(url, headers=httpHeader, verify=False)
2678 except(requests.exceptions.Timeout):
2679 return(connectionErrHandler(args.json, "Timeout", None))
2680 except(requests.exceptions.ConnectionError) as err:
2681 return connectionErrHandler(args.json, "ConnectionError", err)
2682 if resp.status_code != 200:
2683 print(resp.text)
2684 return "Failed to display the certificate"
2685 else:
2686 print("Display complete.")
2687 return resp.text
2688
Marri Devender Raoa208ff82019-07-01 05:51:27 -05002689def certificateList(host, args, session):
2690 """
2691 Called by certificate management function.
2692 Example:
2693 certificate list
2694 @param host: string, the hostname or IP address of the bmc
2695 @param args: contains additional arguments used by the certificate
2696 list sub command
2697 @param session: the active session to use
2698 """
2699 if not redfishSupportPresent(host, session):
2700 return "Not supported";
2701
2702 httpHeader = {'Content-Type': 'application/octet-stream'}
2703 httpHeader.update(xAuthHeader)
2704 url = "https://" + host + \
2705 "/redfish/v1/CertificateService/CertificateLocations/"
2706 try:
2707 resp = session.get(url, headers=httpHeader, verify=False)
2708 except(requests.exceptions.Timeout):
2709 return(connectionErrHandler(args.json, "Timeout", None))
2710 except(requests.exceptions.ConnectionError) as err:
2711 return connectionErrHandler(args.json, "ConnectionError", err)
2712 if resp.status_code != 200:
2713 print(resp.text)
2714 return "Failed to list certificates"
2715 else:
2716 print("List certificates complete.")
2717 return resp.text
2718
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05002719def certificateGenerateCSR(host, args, session):
2720 """
2721 Called by certificate management function. Generate CSR for server/
2722 client certificates
2723 Example:
2724 certificate generatecsr server NJ w3.ibm.com US IBM IBM-UNIT NY EC 2048 prime256v1 cp abc.com an.com,bm.com gn sn un in ClientAuthentication,CodeSigning
2725 certificate generatecsr client NJ w3.ibm.com US IBM IBM-UNIT NY EC 2048 prime256v1 cp abc.com an.com,bm.com gn sn un in ClientAuthentication,CodeSigning
2726 @param host: string, the hostname or IP address of the bmc
2727 @param args: contains additional arguments used by the certificate replace sub command
2728 @param session: the active session to use
2729 """
2730 if not redfishSupportPresent(host, session):
2731 return "Not supported";
2732
2733 httpHeader = {'Content-Type': 'application/octet-stream'}
2734 httpHeader.update(xAuthHeader)
2735 url = "";
2736 if(args.type.lower() == 'server'):
2737 url = "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/"
2738 elif(args.type.lower() == 'client'):
2739 url = "/redfish/v1/AccountService/LDAP/Certificates/"
2740 elif(args.type.lower() == 'authority'):
2741 url = "/redfish/v1/Managers/bmc/Truststore/Certificates/"
2742 print("Generating CSR url=" + url)
2743 generateCSRUrl = "https://" + host + \
2744 "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR"
2745 try:
2746 usage_list = args.keyUsage.split(",")
2747 alt_name_list = args.alternativeNames.split(",")
2748 data ={"CertificateCollection":{"@odata.id":url},
2749 "CommonName":args.commonName, "City":args.city,
2750 "Country":args.country, "Organization":args.organization,
2751 "OrganizationalUnit":args.organizationUnit, "State":args.state,
2752 "KeyPairAlgorithm":args.keyPairAlgorithm,
2753 "KeyBitLength":int(args.keyBitLength), "KeyCurveId":args.keyCurveId,
2754 "AlternativeNames":alt_name_list, "ContactPerson":args.contactPerson,
2755 "Email":args.email, "GivenName":args.givenname, "Initials":args.initials,
2756 "KeyUsage":usage_list, "Surname":args.surname,
2757 "UnstructuredName":args.unstructuredname}
2758 resp = session.post(generateCSRUrl, headers=httpHeader,
2759 json=data, verify=False)
2760 except(requests.exceptions.Timeout):
2761 return(connectionErrHandler(args.json, "Timeout", None))
2762 except(requests.exceptions.ConnectionError) as err:
2763 return connectionErrHandler(args.json, "ConnectionError", err)
2764 if resp.status_code != 200:
2765 print(resp.text)
2766 return "Failed to generate CSR"
2767 else:
2768 print("GenerateCSR complete.")
2769 return resp.text
2770
Ratan Gupta9166cd22018-10-01 18:09:40 +05302771def enableLDAP(host, args, session):
2772 """
2773 Called by the ldap function. Configures LDAP.
2774
2775 @param host: string, the hostname or IP address of the bmc
2776 @param args: contains additional arguments used by the ldap subcommand
2777 @param session: the active session to use
2778 @param args.json: boolean, if this flag is set to true, the output will
2779 be provided in json format for programmatic consumption
2780 """
2781
2782 url='https://'+host+'/xyz/openbmc_project/user/ldap/action/CreateConfig'
Ratan Gupta9166cd22018-10-01 18:09:40 +05302783 scope = {
2784 'sub' : 'xyz.openbmc_project.User.Ldap.Create.SearchScope.sub',
2785 'one' : 'xyz.openbmc_project.User.Ldap.Create.SearchScope.one',
2786 'base': 'xyz.openbmc_project.User.Ldap.Create.SearchScope.base'
2787 }
2788
2789 serverType = {
2790 'ActiveDirectory' : 'xyz.openbmc_project.User.Ldap.Create.Type.ActiveDirectory',
2791 'OpenLDAP' : 'xyz.openbmc_project.User.Ldap.Create.Type.OpenLdap'
2792 }
2793
2794 data = {"data": [args.uri, args.bindDN, args.baseDN, args.bindPassword, scope[args.scope], serverType[args.serverType]]}
2795
2796 try:
Justin Thaler27197622019-01-23 14:42:11 -06002797 res = session.post(url, headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
Ratan Gupta9166cd22018-10-01 18:09:40 +05302798 except(requests.exceptions.Timeout):
2799 return(connectionErrHandler(args.json, "Timeout", None))
2800 except(requests.exceptions.ConnectionError) as err:
2801 return connectionErrHandler(args.json, "ConnectionError", err)
2802
2803 return res.text
2804
2805
2806def disableLDAP(host, args, session):
2807 """
2808 Called by the ldap function. Deletes the LDAP Configuration.
2809
2810 @param host: string, the hostname or IP address of the bmc
2811 @param args: contains additional arguments used by the ldap subcommand
2812 @param session: the active session to use
2813 @param args.json: boolean, if this flag is set to true, the output
2814 will be provided in json format for programmatic consumption
2815 """
2816
2817 url='https://'+host+'/xyz/openbmc_project/user/ldap/config/action/delete'
Ratan Gupta9166cd22018-10-01 18:09:40 +05302818 data = {"data": []}
2819
2820 try:
Justin Thaler27197622019-01-23 14:42:11 -06002821 res = session.post(url, headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
Ratan Gupta9166cd22018-10-01 18:09:40 +05302822 except(requests.exceptions.Timeout):
2823 return(connectionErrHandler(args.json, "Timeout", None))
2824 except(requests.exceptions.ConnectionError) as err:
2825 return connectionErrHandler(args.json, "ConnectionError", err)
2826
2827 return res.text
2828
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06002829
2830def enableDHCP(host, args, session):
2831
2832 """
2833 Called by the network function. Enables DHCP.
2834
2835 @param host: string, the hostname or IP address of the bmc
2836 @param args: contains additional arguments used by the ldap subcommand
2837 args.json: boolean, if this flag is set to true, the output
2838 will be provided in json format for programmatic consumption
2839 @param session: the active session to use
2840 """
2841
2842 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
2843 "/attr/DHCPEnabled"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06002844 data = "{\"data\": 1 }"
2845 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06002846 res = session.put(url, headers=jsonHeader, data=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06002847 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06002848
2849 except(requests.exceptions.Timeout):
2850 return(connectionErrHandler(args.json, "Timeout", None))
2851 except(requests.exceptions.ConnectionError) as err:
2852 return connectionErrHandler(args.json, "ConnectionError", err)
2853 if res.status_code == 403:
2854 return "The specified Interface"+"("+args.Interface+")"+\
2855 " doesn't exist"
2856
2857 return res.text
2858
2859
2860def disableDHCP(host, args, session):
2861 """
2862 Called by the network function. Disables DHCP.
2863
2864 @param host: string, the hostname or IP address of the bmc
2865 @param args: contains additional arguments used by the ldap subcommand
2866 args.json: boolean, if this flag is set to true, the output
2867 will be provided in json format for programmatic consumption
2868 @param session: the active session to use
2869 """
2870
2871 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
2872 "/attr/DHCPEnabled"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06002873 data = "{\"data\": 0 }"
2874 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06002875 res = session.put(url, headers=jsonHeader, data=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06002876 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06002877 except(requests.exceptions.Timeout):
2878 return(connectionErrHandler(args.json, "Timeout", None))
2879 except(requests.exceptions.ConnectionError) as err:
2880 return connectionErrHandler(args.json, "ConnectionError", err)
2881 if res.status_code == 403:
2882 return "The specified Interface"+"("+args.Interface+")"+\
2883 " doesn't exist"
2884 return res.text
2885
2886
2887def getHostname(host, args, session):
2888
2889 """
2890 Called by the network function. Prints out the Hostname.
2891
2892 @param host: string, the hostname or IP address of the bmc
2893 @param args: contains additional arguments used by the ldap subcommand
2894 args.json: boolean, if this flag is set to true, the output
2895 will be provided in json format for programmatic consumption
2896 @param session: the active session to use
2897 """
2898
2899 url = "https://"+host+"/xyz/openbmc_project/network/config/attr/HostName"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06002900
2901 try:
Justin Thaler27197622019-01-23 14:42:11 -06002902 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06002903 except(requests.exceptions.Timeout):
2904 return(connectionErrHandler(args.json, "Timeout", None))
2905 except(requests.exceptions.ConnectionError) as err:
2906 return connectionErrHandler(args.json, "ConnectionError", err)
2907
2908 return res.text
2909
2910
2911def setHostname(host, args, session):
2912 """
2913 Called by the network function. Sets the Hostname.
2914
2915 @param host: string, the hostname or IP address of the bmc
2916 @param args: contains additional arguments used by the ldap subcommand
2917 args.json: boolean, if this flag is set to true, the output
2918 will be provided in json format for programmatic consumption
2919 @param session: the active session to use
2920 """
2921
2922 url = "https://"+host+"/xyz/openbmc_project/network/config/attr/HostName"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06002923
2924 data = {"data": args.HostName}
2925
2926 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06002927 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06002928 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06002929 except(requests.exceptions.Timeout):
2930 return(connectionErrHandler(args.json, "Timeout", None))
2931 except(requests.exceptions.ConnectionError) as err:
2932 return connectionErrHandler(args.json, "ConnectionError", err)
2933
2934 return res.text
2935
2936
2937def getDomainName(host, args, session):
2938
2939 """
2940 Called by the network function. Prints out the DomainName.
2941
2942 @param host: string, the hostname or IP address of the bmc
2943 @param args: contains additional arguments used by the ldap subcommand
2944 args.json: boolean, if this flag is set to true, the output
2945 will be provided in json format for programmatic consumption
2946 @param session: the active session to use
2947 """
2948
2949 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
2950 "/attr/DomainName"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06002951
2952 try:
Justin Thaler27197622019-01-23 14:42:11 -06002953 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06002954 except(requests.exceptions.Timeout):
2955 return(connectionErrHandler(args.json, "Timeout", None))
2956 except(requests.exceptions.ConnectionError) as err:
2957 return connectionErrHandler(args.json, "ConnectionError", err)
2958 if res.status_code == 404:
2959 return "The specified Interface"+"("+args.Interface+")"+\
2960 " doesn't exist"
2961
2962 return res.text
2963
2964
2965def setDomainName(host, args, session):
2966 """
2967 Called by the network function. Sets the DomainName.
2968
2969 @param host: string, the hostname or IP address of the bmc
2970 @param args: contains additional arguments used by the ldap subcommand
2971 args.json: boolean, if this flag is set to true, the output
2972 will be provided in json format for programmatic consumption
2973 @param session: the active session to use
2974 """
2975
2976 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
2977 "/attr/DomainName"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06002978
2979 data = {"data": args.DomainName.split(",")}
2980
2981 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06002982 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06002983 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06002984 except(requests.exceptions.Timeout):
2985 return(connectionErrHandler(args.json, "Timeout", None))
2986 except(requests.exceptions.ConnectionError) as err:
2987 return connectionErrHandler(args.json, "ConnectionError", err)
2988 if res.status_code == 403:
2989 return "The specified Interface"+"("+args.Interface+")"+\
2990 " doesn't exist"
2991
2992 return res.text
2993
2994
2995def getMACAddress(host, args, session):
2996
2997 """
2998 Called by the network function. Prints out the MACAddress.
2999
3000 @param host: string, the hostname or IP address of the bmc
3001 @param args: contains additional arguments used by the ldap subcommand
3002 args.json: boolean, if this flag is set to true, the output
3003 will be provided in json format for programmatic consumption
3004 @param session: the active session to use
3005 """
3006
3007 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3008 "/attr/MACAddress"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003009
3010 try:
Justin Thaler27197622019-01-23 14:42:11 -06003011 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003012 except(requests.exceptions.Timeout):
3013 return(connectionErrHandler(args.json, "Timeout", None))
3014 except(requests.exceptions.ConnectionError) as err:
3015 return connectionErrHandler(args.json, "ConnectionError", err)
3016 if res.status_code == 404:
3017 return "The specified Interface"+"("+args.Interface+")"+\
3018 " doesn't exist"
3019
3020 return res.text
3021
3022
3023def setMACAddress(host, args, session):
3024 """
3025 Called by the network function. Sets the MACAddress.
3026
3027 @param host: string, the hostname or IP address of the bmc
3028 @param args: contains additional arguments used by the ldap subcommand
3029 args.json: boolean, if this flag is set to true, the output
3030 will be provided in json format for programmatic consumption
3031 @param session: the active session to use
3032 """
3033
3034 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3035 "/attr/MACAddress"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003036
3037 data = {"data": args.MACAddress}
3038
3039 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003040 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003041 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003042 except(requests.exceptions.Timeout):
3043 return(connectionErrHandler(args.json, "Timeout", None))
3044 except(requests.exceptions.ConnectionError) as err:
3045 return connectionErrHandler(args.json, "ConnectionError", err)
3046 if res.status_code == 403:
3047 return "The specified Interface"+"("+args.Interface+")"+\
3048 " doesn't exist"
3049
3050 return res.text
3051
3052
3053def getDefaultGateway(host, args, session):
3054
3055 """
3056 Called by the network function. Prints out the DefaultGateway.
3057
3058 @param host: string, the hostname or IP address of the bmc
3059 @param args: contains additional arguments used by the ldap subcommand
3060 args.json: boolean, if this flag is set to true, the output
3061 will be provided in json format for programmatic consumption
3062 @param session: the active session to use
3063 """
3064
3065 url = "https://"+host+"/xyz/openbmc_project/network/config/attr/DefaultGateway"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003066
3067 try:
Justin Thaler27197622019-01-23 14:42:11 -06003068 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003069 except(requests.exceptions.Timeout):
3070 return(connectionErrHandler(args.json, "Timeout", None))
3071 except(requests.exceptions.ConnectionError) as err:
3072 return connectionErrHandler(args.json, "ConnectionError", err)
3073 if res.status_code == 404:
3074 return "Failed to get Default Gateway info!!"
3075
3076 return res.text
3077
3078
3079def setDefaultGateway(host, args, session):
3080 """
3081 Called by the network function. Sets the DefaultGateway.
3082
3083 @param host: string, the hostname or IP address of the bmc
3084 @param args: contains additional arguments used by the ldap subcommand
3085 args.json: boolean, if this flag is set to true, the output
3086 will be provided in json format for programmatic consumption
3087 @param session: the active session to use
3088 """
3089
3090 url = "https://"+host+"/xyz/openbmc_project/network/config/attr/DefaultGateway"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003091
3092 data = {"data": args.DefaultGW}
3093
3094 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003095 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003096 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003097 except(requests.exceptions.Timeout):
3098 return(connectionErrHandler(args.json, "Timeout", None))
3099 except(requests.exceptions.ConnectionError) as err:
3100 return connectionErrHandler(args.json, "ConnectionError", err)
3101 if res.status_code == 403:
3102 return "Failed to set Default Gateway!!"
3103
3104 return res.text
3105
3106
3107def viewNWConfig(host, args, session):
3108 """
3109 Called by the ldap function. Prints out network configured properties
3110
3111 @param host: string, the hostname or IP address of the bmc
3112 @param args: contains additional arguments used by the ldap subcommand
3113 args.json: boolean, if this flag is set to true, the output
3114 will be provided in json format for programmatic consumption
3115 @param session: the active session to use
3116 @return returns LDAP's configured properties.
3117 """
3118 url = "https://"+host+"/xyz/openbmc_project/network/enumerate"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003119 try:
Justin Thaler27197622019-01-23 14:42:11 -06003120 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003121 except(requests.exceptions.Timeout):
3122 return(connectionErrHandler(args.json, "Timeout", None))
3123 except(requests.exceptions.ConnectionError) as err:
3124 return connectionErrHandler(args.json, "ConnectionError", err)
3125 except(requests.exceptions.RequestException) as err:
3126 return connectionErrHandler(args.json, "RequestException", err)
3127 if res.status_code == 404:
3128 return "LDAP server config has not been created"
3129 return res.text
3130
3131
3132def getDNS(host, args, session):
3133
3134 """
3135 Called by the network function. Prints out DNS servers on the interface
3136
3137 @param host: string, the hostname or IP address of the bmc
3138 @param args: contains additional arguments used by the ldap subcommand
3139 args.json: boolean, if this flag is set to true, the output
3140 will be provided in json format for programmatic consumption
3141 @param session: the active session to use
3142 """
3143
3144 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
3145 + "/attr/Nameservers"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003146
3147 try:
Justin Thaler27197622019-01-23 14:42:11 -06003148 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003149 except(requests.exceptions.Timeout):
3150 return(connectionErrHandler(args.json, "Timeout", None))
3151 except(requests.exceptions.ConnectionError) as err:
3152 return connectionErrHandler(args.json, "ConnectionError", err)
3153 if res.status_code == 404:
3154 return "The specified Interface"+"("+args.Interface+")" + \
3155 " doesn't exist"
3156
3157 return res.text
3158
3159
3160def setDNS(host, args, session):
3161 """
3162 Called by the network function. Sets DNS servers on the interface.
3163
3164 @param host: string, the hostname or IP address of the bmc
3165 @param args: contains additional arguments used by the ldap subcommand
3166 args.json: boolean, if this flag is set to true, the output
3167 will be provided in json format for programmatic consumption
3168 @param session: the active session to use
3169 """
3170
3171 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
3172 + "/attr/Nameservers"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003173
3174 data = {"data": args.DNSServers.split(",")}
3175
3176 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003177 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003178 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003179 except(requests.exceptions.Timeout):
3180 return(connectionErrHandler(args.json, "Timeout", None))
3181 except(requests.exceptions.ConnectionError) as err:
3182 return connectionErrHandler(args.json, "ConnectionError", err)
3183 if res.status_code == 403:
3184 return "The specified Interface"+"("+args.Interface+")" +\
3185 " doesn't exist"
3186
3187 return res.text
3188
3189
3190def getNTP(host, args, session):
3191
3192 """
3193 Called by the network function. Prints out NTP servers on the interface
3194
3195 @param host: string, the hostname or IP address of the bmc
3196 @param args: contains additional arguments used by the ldap subcommand
3197 args.json: boolean, if this flag is set to true, the output
3198 will be provided in json format for programmatic consumption
3199 @param session: the active session to use
3200 """
3201
3202 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
3203 + "/attr/NTPServers"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003204
3205 try:
Justin Thaler27197622019-01-23 14:42:11 -06003206 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003207 except(requests.exceptions.Timeout):
3208 return(connectionErrHandler(args.json, "Timeout", None))
3209 except(requests.exceptions.ConnectionError) as err:
3210 return connectionErrHandler(args.json, "ConnectionError", err)
3211 if res.status_code == 404:
3212 return "The specified Interface"+"("+args.Interface+")" + \
3213 " doesn't exist"
3214
3215 return res.text
3216
3217
3218def setNTP(host, args, session):
3219 """
3220 Called by the network function. Sets NTP servers on the interface.
3221
3222 @param host: string, the hostname or IP address of the bmc
3223 @param args: contains additional arguments used by the ldap subcommand
3224 args.json: boolean, if this flag is set to true, the output
3225 will be provided in json format for programmatic consumption
3226 @param session: the active session to use
3227 """
3228
3229 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
3230 + "/attr/NTPServers"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003231
3232 data = {"data": args.NTPServers.split(",")}
3233
3234 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003235 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003236 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003237 except(requests.exceptions.Timeout):
3238 return(connectionErrHandler(args.json, "Timeout", None))
3239 except(requests.exceptions.ConnectionError) as err:
3240 return connectionErrHandler(args.json, "ConnectionError", err)
3241 if res.status_code == 403:
3242 return "The specified Interface"+"("+args.Interface+")" +\
3243 " doesn't exist"
3244
3245 return res.text
3246
3247
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003248def addIP(host, args, session):
3249 """
3250 Called by the network function. Configures IP address on given interface
3251
3252 @param host: string, the hostname or IP address of the bmc
3253 @param args: contains additional arguments used by the ldap subcommand
3254 args.json: boolean, if this flag is set to true, the output
3255 will be provided in json format for programmatic consumption
3256 @param session: the active session to use
3257 """
3258
3259 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
3260 + "/action/IP"
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003261 protocol = {
3262 'ipv4': 'xyz.openbmc_project.Network.IP.Protocol.IPv4',
3263 'ipv6': 'xyz.openbmc_project.Network.IP.Protocol.IPv6'
3264 }
3265
3266 data = {"data": [protocol[args.type], args.address, int(args.prefixLength),
3267 args.gateway]}
3268
3269 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003270 res = session.post(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003271 timeout=baseTimeout)
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003272 except(requests.exceptions.Timeout):
3273 return(connectionErrHandler(args.json, "Timeout", None))
3274 except(requests.exceptions.ConnectionError) as err:
3275 return connectionErrHandler(args.json, "ConnectionError", err)
3276 if res.status_code == 404:
3277 return "The specified Interface" + "(" + args.Interface + ")" +\
3278 " doesn't exist"
3279
3280 return res.text
3281
3282
3283def getIP(host, args, session):
3284 """
3285 Called by the network function. Prints out IP address of given interface
3286
3287 @param host: string, the hostname or IP address of the bmc
3288 @param args: contains additional arguments used by the ldap subcommand
3289 args.json: boolean, if this flag is set to true, the output
3290 will be provided in json format for programmatic consumption
3291 @param session: the active session to use
3292 """
3293
3294 url = "https://" + host+"/xyz/openbmc_project/network/" + args.Interface +\
3295 "/enumerate"
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003296 try:
Justin Thaler27197622019-01-23 14:42:11 -06003297 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003298 except(requests.exceptions.Timeout):
3299 return(connectionErrHandler(args.json, "Timeout", None))
3300 except(requests.exceptions.ConnectionError) as err:
3301 return connectionErrHandler(args.json, "ConnectionError", err)
3302 if res.status_code == 404:
3303 return "The specified Interface" + "(" + args.Interface + ")" +\
3304 " doesn't exist"
3305
3306 return res.text
3307
3308
3309def deleteIP(host, args, session):
3310 """
3311 Called by the network function. Deletes the IP address from given Interface
3312
3313 @param host: string, the hostname or IP address of the bmc
3314 @param args: contains additional arguments used by the ldap subcommand
3315 @param session: the active session to use
3316 @param args.json: boolean, if this flag is set to true, the output
3317 will be provided in json format for programmatic consumption
3318 """
3319
3320 url = "https://"+host+"/xyz/openbmc_project/network/" + args.Interface+\
3321 "/enumerate"
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003322 data = {"data": []}
3323 try:
Justin Thaler27197622019-01-23 14:42:11 -06003324 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003325 except(requests.exceptions.Timeout):
3326 return(connectionErrHandler(args.json, "Timeout", None))
3327 except(requests.exceptions.ConnectionError) as err:
3328 return connectionErrHandler(args.json, "ConnectionError", err)
3329 if res.status_code == 404:
3330 return "The specified Interface" + "(" + args.Interface + ")" +\
3331 " doesn't exist"
3332 objDict = json.loads(res.text)
3333 if not objDict['data']:
3334 return "No object found for given address on given Interface"
3335
3336 for obj in objDict['data']:
3337 if args.address in objDict['data'][obj]['Address']:
3338 url = "https://"+host+obj+"/action/delete"
3339 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003340 res = session.post(url, headers=jsonHeader, json=data,
Justin Thaler27197622019-01-23 14:42:11 -06003341 verify=False, timeout=baseTimeout)
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003342 except(requests.exceptions.Timeout):
3343 return(connectionErrHandler(args.json, "Timeout", None))
3344 except(requests.exceptions.ConnectionError) as err:
3345 return connectionErrHandler(args.json, "ConnectionError", err)
3346 return res.text
3347 else:
3348 continue
3349 return "No object found for given address on given Interface"
3350
3351
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003352def addVLAN(host, args, session):
3353 """
3354 Called by the network function. Creates VLAN on given interface.
3355
3356 @param host: string, the hostname or IP address of the bmc
3357 @param args: contains additional arguments used by the ldap subcommand
3358 args.json: boolean, if this flag is set to true, the output
3359 will be provided in json format for programmatic consumption
3360 @param session: the active session to use
3361 """
3362
3363 url = "https://" + host+"/xyz/openbmc_project/network/action/VLAN"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003364
3365 data = {"data": [args.Interface,args.Identifier]}
3366
3367 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003368 res = session.post(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003369 timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003370 except(requests.exceptions.Timeout):
3371 return(connectionErrHandler(args.json, "Timeout", None))
3372 except(requests.exceptions.ConnectionError) as err:
3373 return connectionErrHandler(args.json, "ConnectionError", err)
3374 if res.status_code == 400:
3375 return "The specified Interface" + "(" + args.Interface + ")" +\
3376 " doesn't exist"
3377
3378 return res.text
3379
3380
3381def deleteVLAN(host, args, session):
3382 """
3383 Called by the network function. Creates VLAN on given interface.
3384
3385 @param host: string, the hostname or IP address of the bmc
3386 @param args: contains additional arguments used by the ldap subcommand
3387 args.json: boolean, if this flag is set to true, the output
3388 will be provided in json format for programmatic consumption
3389 @param session: the active session to use
3390 """
3391
3392 url = "https://" + host+"/xyz/openbmc_project/network/"+args.Interface+"/action/delete"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003393 data = {"data": []}
3394
3395 try:
Justin Thaler27197622019-01-23 14:42:11 -06003396 res = session.post(url, headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003397 except(requests.exceptions.Timeout):
3398 return(connectionErrHandler(args.json, "Timeout", None))
3399 except(requests.exceptions.ConnectionError) as err:
3400 return connectionErrHandler(args.json, "ConnectionError", err)
3401 if res.status_code == 404:
3402 return "The specified VLAN"+"("+args.Interface+"_"+args.Identifier\
3403 +")" +" doesn't exist"
3404
3405 return res.text
3406
3407
3408def viewDHCPConfig(host, args, session):
3409 """
3410 Called by the network function. Shows DHCP configured Properties.
3411
3412 @param host: string, the hostname or IP address of the bmc
3413 @param args: contains additional arguments used by the ldap subcommand
3414 args.json: boolean, if this flag is set to true, the output
3415 will be provided in json format for programmatic consumption
3416 @param session: the active session to use
3417 """
3418
3419 url="https://"+host+"/xyz/openbmc_project/network/config/dhcp"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003420
3421 try:
Justin Thaler27197622019-01-23 14:42:11 -06003422 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003423 except(requests.exceptions.Timeout):
3424 return(connectionErrHandler(args.json, "Timeout", None))
3425 except(requests.exceptions.ConnectionError) as err:
3426 return connectionErrHandler(args.json, "ConnectionError", err)
3427
3428 return res.text
3429
3430
3431def configureDHCP(host, args, session):
3432 """
3433 Called by the network function. Configures/updates DHCP Properties.
3434
3435 @param host: string, the hostname or IP address of the bmc
3436 @param args: contains additional arguments used by the ldap subcommand
3437 args.json: boolean, if this flag is set to true, the output
3438 will be provided in json format for programmatic consumption
3439 @param session: the active session to use
3440 """
3441
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003442
3443 try:
3444 url="https://"+host+"/xyz/openbmc_project/network/config/dhcp"
3445 if(args.DNSEnabled == True):
3446 data = '{"data": 1}'
3447 else:
3448 data = '{"data": 0}'
Matt Spinler220c3c42019-01-04 15:09:29 -06003449 res = session.put(url + '/attr/DNSEnabled', headers=jsonHeader,
Justin Thaler27197622019-01-23 14:42:11 -06003450 data=data, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003451 if(args.HostNameEnabled == True):
3452 data = '{"data": 1}'
3453 else:
3454 data = '{"data": 0}'
Matt Spinler220c3c42019-01-04 15:09:29 -06003455 res = session.put(url + '/attr/HostNameEnabled', headers=jsonHeader,
Justin Thaler27197622019-01-23 14:42:11 -06003456 data=data, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003457 if(args.NTPEnabled == True):
3458 data = '{"data": 1}'
3459 else:
3460 data = '{"data": 0}'
Matt Spinler220c3c42019-01-04 15:09:29 -06003461 res = session.put(url + '/attr/NTPEnabled', headers=jsonHeader,
Justin Thaler27197622019-01-23 14:42:11 -06003462 data=data, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003463 if(args.SendHostNameEnabled == True):
3464 data = '{"data": 1}'
3465 else:
3466 data = '{"data": 0}'
Matt Spinler220c3c42019-01-04 15:09:29 -06003467 res = session.put(url + '/attr/SendHostNameEnabled', headers=jsonHeader,
Justin Thaler27197622019-01-23 14:42:11 -06003468 data=data, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003469 except(requests.exceptions.Timeout):
3470 return(connectionErrHandler(args.json, "Timeout", None))
3471 except(requests.exceptions.ConnectionError) as err:
3472 return connectionErrHandler(args.json, "ConnectionError", err)
3473
3474 return res.text
3475
3476
3477def nwReset(host, args, session):
3478
3479 """
3480 Called by the network function. Resets networks setting to factory defaults.
3481
3482 @param host: string, the hostname or IP address of the bmc
3483 @param args: contains additional arguments used by the ldap subcommand
3484 args.json: boolean, if this flag is set to true, the output
3485 will be provided in json format for programmatic consumption
3486 @param session: the active session to use
3487 """
3488
3489 url = "https://"+host+"/xyz/openbmc_project/network/action/Reset"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003490 data = '{"data":[] }'
3491 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003492 res = session.post(url, headers=jsonHeader, data=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003493 timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003494
3495 except(requests.exceptions.Timeout):
3496 return(connectionErrHandler(args.json, "Timeout", None))
3497 except(requests.exceptions.ConnectionError) as err:
3498 return connectionErrHandler(args.json, "ConnectionError", err)
3499
3500 return res.text
3501
3502
Ratan Guptafeee6372018-10-17 23:25:51 +05303503def createPrivilegeMapping(host, args, session):
3504 """
3505 Called by the ldap function. Creates the group and the privilege mapping.
3506
3507 @param host: string, the hostname or IP address of the bmc
3508 @param args: contains additional arguments used by the ldap subcommand
3509 @param session: the active session to use
3510 @param args.json: boolean, if this flag is set to true, the output
3511 will be provided in json format for programmatic consumption
3512 """
3513
3514 url = 'https://'+host+'/xyz/openbmc_project/user/ldap/action/Create'
Ratan Guptafeee6372018-10-17 23:25:51 +05303515
3516 data = {"data": [args.groupName,args.privilege]}
3517
3518 try:
Justin Thaler27197622019-01-23 14:42:11 -06003519 res = session.post(url, headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
Ratan Guptafeee6372018-10-17 23:25:51 +05303520 except(requests.exceptions.Timeout):
3521 return(connectionErrHandler(args.json, "Timeout", None))
3522 except(requests.exceptions.ConnectionError) as err:
3523 return connectionErrHandler(args.json, "ConnectionError", err)
3524 return res.text
3525
3526def listPrivilegeMapping(host, args, session):
3527 """
3528 Called by the ldap function. Lists the group and the privilege mapping.
3529
3530 @param host: string, the hostname or IP address of the bmc
3531 @param args: contains additional arguments used by the ldap subcommand
3532 @param session: the active session to use
3533 @param args.json: boolean, if this flag is set to true, the output
3534 will be provided in json format for programmatic consumption
3535 """
3536 url = 'https://'+host+'/xyz/openbmc_project/user/ldap/enumerate'
Ratan Guptafeee6372018-10-17 23:25:51 +05303537 data = {"data": []}
3538
3539 try:
Justin Thaler27197622019-01-23 14:42:11 -06003540 res = session.get(url, headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
Ratan Guptafeee6372018-10-17 23:25:51 +05303541 except(requests.exceptions.Timeout):
3542 return(connectionErrHandler(args.json, "Timeout", None))
3543 except(requests.exceptions.ConnectionError) as err:
3544 return connectionErrHandler(args.json, "ConnectionError", err)
3545 return res.text
3546
3547def deletePrivilegeMapping(host, args, session):
3548 """
3549 Called by the ldap function. Deletes the mapping associated with the group.
3550
3551 @param host: string, the hostname or IP address of the bmc
3552 @param args: contains additional arguments used by the ldap subcommand
3553 @param session: the active session to use
3554 @param args.json: boolean, if this flag is set to true, the output
3555 will be provided in json format for programmatic consumption
3556 """
3557 (ldapNameSpaceObjects) = listPrivilegeMapping(host, args, session)
3558 ldapNameSpaceObjects = json.loads(ldapNameSpaceObjects)["data"]
3559 path = ''
3560
3561 # not interested in the config objet
3562 ldapNameSpaceObjects.pop('/xyz/openbmc_project/user/ldap/config', None)
3563
3564 # search for the object having the mapping for the given group
3565 for key,value in ldapNameSpaceObjects.items():
3566 if value['GroupName'] == args.groupName:
3567 path = key
3568 break
3569
3570 if path == '':
3571 return "No privilege mapping found for this group."
3572
3573 # delete the object
3574 url = 'https://'+host+path+'/action/delete'
Ratan Guptafeee6372018-10-17 23:25:51 +05303575 data = {"data": []}
3576
3577 try:
Justin Thaler27197622019-01-23 14:42:11 -06003578 res = session.post(url, headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
Ratan Guptafeee6372018-10-17 23:25:51 +05303579 except(requests.exceptions.Timeout):
3580 return(connectionErrHandler(args.json, "Timeout", None))
3581 except(requests.exceptions.ConnectionError) as err:
3582 return connectionErrHandler(args.json, "ConnectionError", err)
3583 return res.text
Ratan Gupta9166cd22018-10-01 18:09:40 +05303584
Sivas SRR78835272018-11-27 05:27:19 -06003585def deleteAllPrivilegeMapping(host, args, session):
3586 """
3587 Called by the ldap function. Deletes all the privilege mapping and group defined.
3588 @param host: string, the hostname or IP address of the bmc
3589 @param args: contains additional arguments used by the ldap subcommand
3590 @param session: the active session to use
3591 @param args.json: boolean, if this flag is set to true, the output
3592 will be provided in json format for programmatic consumption
3593 """
3594 ldapNameSpaceObjects = listPrivilegeMapping(host, args, session)
3595 ldapNameSpaceObjects = json.loads(ldapNameSpaceObjects)["data"]
3596 path = ''
3597
3598 # Remove the config object.
3599 ldapNameSpaceObjects.pop('/xyz/openbmc_project/user/ldap/config', None)
Sivas SRR78835272018-11-27 05:27:19 -06003600 data = {"data": []}
3601
3602 try:
3603 # search for GroupName property and delete if it is available.
3604 for path in ldapNameSpaceObjects.keys():
3605 # delete the object
3606 url = 'https://'+host+path+'/action/delete'
Justin Thaler27197622019-01-23 14:42:11 -06003607 res = session.post(url, headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
Sivas SRR78835272018-11-27 05:27:19 -06003608 except(requests.exceptions.Timeout):
3609 return(connectionErrHandler(args.json, "Timeout", None))
3610 except(requests.exceptions.ConnectionError) as err:
3611 return connectionErrHandler(args.json, "ConnectionError", err)
3612 return res.text
3613
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06003614def viewLDAPConfig(host, args, session):
3615 """
3616 Called by the ldap function. Prints out LDAP's configured properties
3617
3618 @param host: string, the hostname or IP address of the bmc
3619 @param args: contains additional arguments used by the ldap subcommand
3620 args.json: boolean, if this flag is set to true, the output
3621 will be provided in json format for programmatic consumption
3622 @param session: the active session to use
3623 @return returns LDAP's configured properties.
3624 """
3625 url = "https://"+host+"/xyz/openbmc_project/user/ldap/config"
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06003626 try:
Justin Thaler27197622019-01-23 14:42:11 -06003627 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06003628 except(requests.exceptions.Timeout):
3629 return(connectionErrHandler(args.json, "Timeout", None))
3630 except(requests.exceptions.ConnectionError) as err:
3631 return connectionErrHandler(args.json, "ConnectionError", err)
3632 except(requests.exceptions.RequestException) as err:
3633 return connectionErrHandler(args.json, "RequestException", err)
3634 if res.status_code == 404:
3635 return "LDAP server config has not been created"
3636 return res.text
3637
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003638def str2bool(v):
3639 if v.lower() in ('yes', 'true', 't', 'y', '1'):
3640 return True
3641 elif v.lower() in ('no', 'false', 'f', 'n', '0'):
3642 return False
3643 else:
3644 raise argparse.ArgumentTypeError('Boolean value expected.')
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06003645
Matt Spinler7d426c22018-09-24 14:42:07 -05003646def localUsers(host, args, session):
3647 """
3648 Enables and disables local BMC users.
3649
3650 @param host: string, the hostname or IP address of the bmc
3651 @param args: contains additional arguments used by the logging sub command
3652 @param session: the active session to use
3653 """
3654
Matt Spinler7d426c22018-09-24 14:42:07 -05003655 url="https://{hostname}/xyz/openbmc_project/user/enumerate".format(hostname=host)
3656 try:
Justin Thaler27197622019-01-23 14:42:11 -06003657 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Matt Spinler7d426c22018-09-24 14:42:07 -05003658 except(requests.exceptions.Timeout):
3659 return(connectionErrHandler(args.json, "Timeout", None))
3660 usersDict = json.loads(res.text)
3661
3662 if not usersDict['data']:
3663 return "No users found"
3664
3665 output = ""
3666 for user in usersDict['data']:
Matt Spinler015adc22018-10-23 14:30:19 -05003667
3668 # Skip LDAP and another non-local users
3669 if 'UserEnabled' not in usersDict['data'][user]:
3670 continue
3671
Matt Spinler7d426c22018-09-24 14:42:07 -05003672 name = user.split('/')[-1]
3673 url = "https://{hostname}{user}/attr/UserEnabled".format(hostname=host, user=user)
3674
3675 if args.local_users == "queryenabled":
3676 try:
Justin Thaler27197622019-01-23 14:42:11 -06003677 res = session.get(url, headers=jsonHeader,verify=False, timeout=baseTimeout)
Matt Spinler7d426c22018-09-24 14:42:07 -05003678 except(requests.exceptions.Timeout):
3679 return(connectionErrHandler(args.json, "Timeout", None))
3680
3681 result = json.loads(res.text)
3682 output += ("User: {name} Enabled: {result}\n").format(name=name, result=result['data'])
3683
3684 elif args.local_users in ["enableall", "disableall"]:
3685 action = ""
3686 if args.local_users == "enableall":
3687 data = '{"data": true}'
3688 action = "Enabling"
3689 else:
3690 data = '{"data": false}'
3691 action = "Disabling"
3692
3693 output += "{action} {name}\n".format(action=action, name=name)
3694
3695 try:
Justin Thaler27197622019-01-23 14:42:11 -06003696 resp = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Matt Spinler7d426c22018-09-24 14:42:07 -05003697 except(requests.exceptions.Timeout):
3698 return connectionErrHandler(args.json, "Timeout", None)
3699 except(requests.exceptions.ConnectionError) as err:
3700 return connectionErrHandler(args.json, "ConnectionError", err)
3701 else:
3702 return "Invalid local users argument"
3703
3704 return output
3705
Marri Devender Rao2c2a5162018-11-05 08:57:11 -06003706def setPassword(host, args, session):
3707 """
3708 Set local user password
3709 @param host: string, the hostname or IP address of the bmc
3710 @param args: contains additional arguments used by the logging sub
3711 command
3712 @param session: the active session to use
3713 @param args.json: boolean, if this flag is set to true, the output
3714 will be provided in json format for programmatic consumption
3715 @return: Session object
3716 """
Marri Devender Rao2c2a5162018-11-05 08:57:11 -06003717 try:
Sunitha Harishc99faba2019-07-19 06:55:22 -05003718 if(isRedfishSupport):
3719 url = "https://" + host + "/redfish/v1/AccountService/Accounts/"+ \
3720 args.user
3721 data = {"Password":args.password}
3722 res = session.patch(url, headers=jsonHeader, json=data,
3723 verify=False, timeout=baseTimeout)
3724 else:
3725 url = "https://" + host + "/xyz/openbmc_project/user/" + args.user + \
3726 "/action/SetPassword"
3727 res = session.post(url, headers=jsonHeader,
Marri Devender Rao2c2a5162018-11-05 08:57:11 -06003728 json={"data": [args.password]}, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003729 timeout=baseTimeout)
Marri Devender Rao2c2a5162018-11-05 08:57:11 -06003730 except(requests.exceptions.Timeout):
3731 return(connectionErrHandler(args.json, "Timeout", None))
3732 except(requests.exceptions.ConnectionError) as err:
3733 return connectionErrHandler(args.json, "ConnectionError", err)
3734 except(requests.exceptions.RequestException) as err:
3735 return connectionErrHandler(args.json, "RequestException", err)
Sunitha Harishc99faba2019-07-19 06:55:22 -05003736 return res.status_code
Matthew Barth368e83c2019-02-01 13:48:25 -06003737
3738def getThermalZones(host, args, session):
3739 """
3740 Get the available thermal control zones
3741 @param host: string, the hostname or IP address of the bmc
3742 @param args: contains additional arguments used to get the thermal
3743 control zones
3744 @param session: the active session to use
3745 @return: Session object
3746 """
3747 url = "https://" + host + "/xyz/openbmc_project/control/thermal/enumerate"
3748
3749 try:
3750 res = session.get(url, headers=jsonHeader, verify=False, timeout=30)
3751 except(requests.exceptions.Timeout):
3752 return(connectionErrHandler(args.json, "Timeout", None))
3753 except(requests.exceptions.ConnectionError) as err:
3754 return connectionErrHandler(args.json, "ConnectionError", err)
3755 except(requests.exceptions.RequestException) as err:
3756 return connectionErrHandler(args.json, "RequestException", err)
3757
3758 if (res.status_code == 404):
3759 return "No thermal control zones found or system is in a" + \
3760 " powered off state"
3761
3762 zonesDict = json.loads(res.text)
3763 if not zonesDict['data']:
3764 return "No thermal control zones found"
3765 for zone in zonesDict['data']:
3766 z = ",".join(str(zone.split('/')[-1]) for zone in zonesDict['data'])
3767
3768 return "Zones: [ " + z + " ]"
3769
3770
3771def getThermalMode(host, args, session):
3772 """
3773 Get thermal control mode
3774 @param host: string, the hostname or IP address of the bmc
3775 @param args: contains additional arguments used to get the thermal
3776 control mode
3777 @param session: the active session to use
3778 @param args.zone: the zone to get the mode on
3779 @return: Session object
3780 """
3781 url = "https://" + host + "/xyz/openbmc_project/control/thermal/" + \
3782 args.zone
3783
3784 try:
3785 res = session.get(url, headers=jsonHeader, verify=False, timeout=30)
3786 except(requests.exceptions.Timeout):
3787 return(connectionErrHandler(args.json, "Timeout", None))
3788 except(requests.exceptions.ConnectionError) as err:
3789 return connectionErrHandler(args.json, "ConnectionError", err)
3790 except(requests.exceptions.RequestException) as err:
3791 return connectionErrHandler(args.json, "RequestException", err)
3792
3793 if (res.status_code == 404):
3794 return "Thermal control zone(" + args.zone + ") not found or" + \
3795 " system is in a powered off state"
3796
3797 propsDict = json.loads(res.text)
3798 if not propsDict['data']:
3799 return "No thermal control properties found on zone(" + args.zone + ")"
3800 curMode = "Current"
3801 supModes = "Supported"
3802 result = "\n"
3803 for prop in propsDict['data']:
3804 if (prop.casefold() == curMode.casefold()):
3805 result += curMode + " Mode: " + propsDict['data'][curMode] + "\n"
3806 if (prop.casefold() == supModes.casefold()):
3807 s = ", ".join(str(sup) for sup in propsDict['data'][supModes])
3808 result += supModes + " Modes: [ " + s + " ]\n"
3809
3810 return result
3811
3812def setThermalMode(host, args, session):
3813 """
3814 Set thermal control mode
3815 @param host: string, the hostname or IP address of the bmc
3816 @param args: contains additional arguments used for setting the thermal
3817 control mode
3818 @param session: the active session to use
3819 @param args.zone: the zone to set the mode on
3820 @param args.mode: the mode to enable
3821 @return: Session object
3822 """
3823 url = "https://" + host + "/xyz/openbmc_project/control/thermal/" + \
3824 args.zone + "/attr/Current"
3825
3826 # Check args.mode against supported modes using `getThermalMode` output
3827 modes = getThermalMode(host, args, session)
3828 modes = os.linesep.join([m for m in modes.splitlines() if m])
3829 modes = modes.replace("\n", ";").strip()
3830 modesDict = dict(m.split(': ') for m in modes.split(';'))
3831 sModes = ''.join(s for s in modesDict['Supported Modes'] if s not in '[ ]')
3832 if args.mode.casefold() not in \
3833 (m.casefold() for m in sModes.split(',')) or not args.mode:
3834 result = ("Unsupported mode('" + args.mode + "') given, " +
3835 "select a supported mode: \n" +
3836 getThermalMode(host, args, session))
3837 return result
3838
3839 data = '{"data":"' + args.mode + '"}'
3840 try:
3841 res = session.get(url, headers=jsonHeader, verify=False, timeout=30)
3842 except(requests.exceptions.Timeout):
3843 return(connectionErrHandler(args.json, "Timeout", None))
3844 except(requests.exceptions.ConnectionError) as err:
3845 return connectionErrHandler(args.json, "ConnectionError", err)
3846 except(requests.exceptions.RequestException) as err:
3847 return connectionErrHandler(args.json, "RequestException", err)
3848
3849 if (data and res.status_code != 404):
3850 try:
3851 res = session.put(url, headers=jsonHeader,
3852 data=data, verify=False,
3853 timeout=30)
3854 except(requests.exceptions.Timeout):
3855 return(connectionErrHandler(args.json, "Timeout", None))
3856 except(requests.exceptions.ConnectionError) as err:
3857 return connectionErrHandler(args.json, "ConnectionError", err)
3858 except(requests.exceptions.RequestException) as err:
3859 return connectionErrHandler(args.json, "RequestException", err)
3860
3861 if res.status_code == 403:
3862 return "The specified thermal control zone(" + args.zone + ")" + \
3863 " does not exist"
3864
3865 return res.text
3866 else:
3867 return "Setting thermal control mode(" + args.mode + ")" + \
3868 " not supported or operation not available(system powered off?)"
3869
3870
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003871def createCommandParser():
Justin Thalere412dc22018-01-12 16:28:24 -06003872 """
3873 creates the parser for the command line along with help for each command and subcommand
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003874
Justin Thalere412dc22018-01-12 16:28:24 -06003875 @return: returns the parser for the command line
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003876 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003877 parser = argparse.ArgumentParser(description='Process arguments')
Justin Thalere412dc22018-01-12 16:28:24 -06003878 parser.add_argument("-H", "--host", help='A hostname or IP for the BMC')
3879 parser.add_argument("-U", "--user", help='The username to login with')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003880 group = parser.add_mutually_exclusive_group()
3881 group.add_argument("-A", "--askpw", action='store_true', help='prompt for password')
3882 group.add_argument("-P", "--PW", help='Provide the password in-line')
Joseph Reynoldsa2d54c52019-06-11 22:02:57 -05003883 group.add_argument("-E", "--PWenvvar", action='store_true', help='Get password from envvar OPENBMCTOOL_PASSWORD')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003884 parser.add_argument('-j', '--json', action='store_true', help='output json data only')
3885 parser.add_argument('-t', '--policyTableLoc', help='The location of the policy table to parse alerts')
3886 parser.add_argument('-c', '--CerFormat', action='store_true', help=argparse.SUPPRESS)
3887 parser.add_argument('-T', '--procTime', action='store_true', help= argparse.SUPPRESS)
Justin Thalere412dc22018-01-12 16:28:24 -06003888 parser.add_argument('-V', '--version', action='store_true', help='Display the version number of the openbmctool')
3889 subparsers = parser.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003890
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003891 #fru command
3892 parser_inv = subparsers.add_parser("fru", help='Work with platform inventory')
Justin Thalere412dc22018-01-12 16:28:24 -06003893 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 -05003894 inv_subparser.required = True
3895 #fru print
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003896 inv_print = inv_subparser.add_parser("print", help="prints out a list of all FRUs")
3897 inv_print.set_defaults(func=fruPrint)
3898 #fru list [0....n]
3899 inv_list = inv_subparser.add_parser("list", help="print out details on selected FRUs. Specifying no items will list the entire inventory")
3900 inv_list.add_argument('items', nargs='?', help="print out details on selected FRUs. Specifying no items will list the entire inventory")
3901 inv_list.set_defaults(func=fruList)
3902 #fru status
3903 inv_status = inv_subparser.add_parser("status", help="prints out the status of all FRUs")
Justin Thalere412dc22018-01-12 16:28:24 -06003904 inv_status.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003905 inv_status.set_defaults(func=fruStatus)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003906
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003907 #sensors command
3908 parser_sens = subparsers.add_parser("sensors", help="Work with platform sensors")
Justin Thalere412dc22018-01-12 16:28:24 -06003909 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 -05003910 sens_subparser.required = True
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003911 #sensor print
3912 sens_print= sens_subparser.add_parser('print', help="prints out a list of all Sensors.")
3913 sens_print.set_defaults(func=sensor)
3914 #sensor list[0...n]
3915 sens_list=sens_subparser.add_parser("list", help="Lists all Sensors in the platform. Specify a sensor for full details. ")
3916 sens_list.add_argument("sensNum", nargs='?', help="The Sensor number to get full details on" )
3917 sens_list.set_defaults(func=sensor)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003918
Matthew Barth368e83c2019-02-01 13:48:25 -06003919 #thermal control commands
3920 parser_therm = subparsers.add_parser("thermal", help="Work with thermal control parameters")
3921 therm_subparser=parser_therm.add_subparsers(title='subcommands', description='Thermal control actions to work with', help='Valid thermal control actions to work with', dest='command')
3922 #thermal control zones
3923 parser_thermZones = therm_subparser.add_parser("zones", help="Get a list of available thermal control zones")
3924 parser_thermZones.set_defaults(func=getThermalZones)
3925 #thermal control modes
3926 parser_thermMode = therm_subparser.add_parser("modes", help="Work with thermal control modes")
3927 thermMode_sub = parser_thermMode.add_subparsers(title='subactions', description='Work with thermal control modes', help="Work with thermal control modes")
3928 #get thermal control mode
3929 parser_getThermMode = thermMode_sub.add_parser("get", help="Get current and supported thermal control modes")
3930 parser_getThermMode.add_argument('-z', '--zone', required=True, help='Thermal zone to work with')
3931 parser_getThermMode.set_defaults(func=getThermalMode)
3932 #set thermal control mode
3933 parser_setThermMode = thermMode_sub.add_parser("set", help="Set the thermal control mode")
3934 parser_setThermMode.add_argument('-z', '--zone', required=True, help='Thermal zone to work with')
3935 parser_setThermMode.add_argument('-m', '--mode', required=True, help='The supported thermal control mode')
3936 parser_setThermMode.set_defaults(func=setThermalMode)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003937
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003938 #sel command
3939 parser_sel = subparsers.add_parser("sel", help="Work with platform alerts")
Justin Thalere412dc22018-01-12 16:28:24 -06003940 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 -05003941 sel_subparser.required = True
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003942 #sel print
3943 sel_print = sel_subparser.add_parser("print", help="prints out a list of all sels in a condensed list")
3944 sel_print.add_argument('-d', '--devdebug', action='store_true', help=argparse.SUPPRESS)
3945 sel_print.add_argument('-v', '--verbose', action='store_true', help="Changes the output to being very verbose")
3946 sel_print.add_argument('-f', '--fileloc', help='Parse a file instead of the BMC output')
3947 sel_print.set_defaults(func=selPrint)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003948
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003949 #sel list
3950 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")
3951 sel_list.add_argument("selNum", nargs='?', type=int, help="The SEL entry to get details on")
3952 sel_list.set_defaults(func=selList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003953
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003954 sel_get = sel_subparser.add_parser("get", help="Gets the verbose details of a specified SEL entry")
3955 sel_get.add_argument('selNum', type=int, help="the number of the SEL entry to get")
3956 sel_get.set_defaults(func=selList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003957
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003958 sel_clear = sel_subparser.add_parser("clear", help="Clears all entries from the SEL")
3959 sel_clear.set_defaults(func=selClear)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003960
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003961 sel_setResolved = sel_subparser.add_parser("resolve", help="Sets the sel entry to resolved")
Justin Thalere412dc22018-01-12 16:28:24 -06003962 sel_setResolved.add_argument('-n', '--selNum', type=int, help="the number of the SEL entry to resolve")
3963 sel_ResolveAll_sub = sel_setResolved.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
3964 sel_ResolveAll = sel_ResolveAll_sub.add_parser('all', help='Resolve all SEL entries')
3965 sel_ResolveAll.set_defaults(func=selResolveAll)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003966 sel_setResolved.set_defaults(func=selSetResolved)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003967
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003968 parser_chassis = subparsers.add_parser("chassis", help="Work with chassis power and status")
Justin Thalere412dc22018-01-12 16:28:24 -06003969 chas_sub = parser_chassis.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003970
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003971 parser_chassis.add_argument('status', action='store_true', help='Returns the current status of the platform')
3972 parser_chassis.set_defaults(func=chassis)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003973
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003974 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 -06003975 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 -06003976 parser_chasPower.set_defaults(func=chassisPower)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003977
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003978 #control the chassis identify led
3979 parser_chasIdent = chas_sub.add_parser("identify", help="Control the chassis identify led")
3980 parser_chasIdent.add_argument('identcmd', choices=['on', 'off', 'status'], help='The control option for the led: on, off, blink, status')
3981 parser_chasIdent.set_defaults(func=chassisIdent)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003982
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003983 #collect service data
3984 parser_servData = subparsers.add_parser("collect_service_data", help="Collect all bmc data needed for service")
3985 parser_servData.add_argument('-d', '--devdebug', action='store_true', help=argparse.SUPPRESS)
3986 parser_servData.set_defaults(func=collectServiceData)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003987
Justin Thalere412dc22018-01-12 16:28:24 -06003988 #system quick health check
3989 parser_healthChk = subparsers.add_parser("health_check", help="Work with platform sensors")
3990 parser_healthChk.set_defaults(func=healthCheck)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003991
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003992 #work with bmc dumps
3993 parser_bmcdump = subparsers.add_parser("dump", help="Work with bmc dump files")
Justin Thalere412dc22018-01-12 16:28:24 -06003994 bmcDump_sub = parser_bmcdump.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Justin Thaler53bf2f12018-07-16 14:05:32 -05003995 bmcDump_sub.required = True
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003996 dump_Create = bmcDump_sub.add_parser('create', help="Create a bmc dump")
3997 dump_Create.set_defaults(func=bmcDumpCreate)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003998
Justin Thalerf9aee3e2017-12-05 12:11:09 -06003999 dump_list = bmcDump_sub.add_parser('list', help="list all bmc dump files")
4000 dump_list.set_defaults(func=bmcDumpList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004001
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004002 parserdumpdelete = bmcDump_sub.add_parser('delete', help="Delete bmc dump files")
4003 parserdumpdelete.add_argument("-n", "--dumpNum", nargs='*', type=int, help="The Dump entry to delete")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004004 parserdumpdelete.set_defaults(func=bmcDumpDelete)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004005
Justin Thalere412dc22018-01-12 16:28:24 -06004006 bmcDumpDelsub = parserdumpdelete.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004007 deleteAllDumps = bmcDumpDelsub.add_parser('all', help='Delete all bmc dump files')
4008 deleteAllDumps.set_defaults(func=bmcDumpDeleteAll)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004009
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004010 parser_dumpretrieve = bmcDump_sub.add_parser('retrieve', help='Retrieve a dump file')
4011 parser_dumpretrieve.add_argument("dumpNum", type=int, help="The Dump entry to delete")
4012 parser_dumpretrieve.add_argument("-s", "--dumpSaveLoc", help="The location to save the bmc dump file")
4013 parser_dumpretrieve.set_defaults(func=bmcDumpRetrieve)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004014
Justin Thaler22b1bb52018-03-15 13:31:32 -05004015 #bmc command for reseting the bmc
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004016 parser_bmc = subparsers.add_parser('bmc', help="Work with the bmc")
Justin Thalere412dc22018-01-12 16:28:24 -06004017 bmc_sub = parser_bmc.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004018 parser_BMCReset = bmc_sub.add_parser('reset', help='Reset the bmc' )
4019 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 -06004020 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.")
4021 parser_bmc.set_defaults(func=bmc)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004022
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004023 #add alias to the bmc command
4024 parser_mc = subparsers.add_parser('mc', help="Work with the management controller")
Justin Thalere412dc22018-01-12 16:28:24 -06004025 mc_sub = parser_mc.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004026 parser_MCReset = mc_sub.add_parser('reset', help='Reset the bmc' )
4027 parser_MCReset.add_argument('type', choices=['warm','cold'], help="Reboot the BMC")
4028 #parser_MCReset.add_argument('cold', action='store_true', help="Reboot the BMC and CLEAR the configuration")
4029 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 -06004030 parser_MCReset.set_defaults(func=bmcReset)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004031 parser_mc.set_defaults(func=bmc)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004032
Justin Thalere412dc22018-01-12 16:28:24 -06004033 #gard clear
4034 parser_gc = subparsers.add_parser("gardclear", help="Used to clear gard records")
4035 parser_gc.set_defaults(func=gardClear)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004036
Justin Thalere412dc22018-01-12 16:28:24 -06004037 #firmware_flash
4038 parser_fw = subparsers.add_parser("firmware", help="Work with the system firmware")
4039 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 -05004040 fwflash_subproc.required = True
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004041
Justin Thalere412dc22018-01-12 16:28:24 -06004042 fwflash = fwflash_subproc.add_parser('flash', help="Flash the system firmware")
4043 fwflash.add_argument('type', choices=['bmc', 'pnor'], help="image type to flash")
4044 fwflash.add_argument('-f', '--fileloc', required=True, help="The absolute path to the firmware image")
4045 fwflash.set_defaults(func=fwFlash)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004046
Justin Thaler22b1bb52018-03-15 13:31:32 -05004047 fwActivate = fwflash_subproc.add_parser('activate', help="Activate existing image on the bmc")
Justin Thalere412dc22018-01-12 16:28:24 -06004048 fwActivate.add_argument('imageID', help="The image ID to activate from the firmware list. Ex: 63c95399")
4049 fwActivate.set_defaults(func=activateFWImage)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004050
Justin Thaler22b1bb52018-03-15 13:31:32 -05004051 fwActivateStatus = fwflash_subproc.add_parser('activation_status', help="Check Status of activations")
4052 fwActivateStatus.set_defaults(func=activateStatus)
4053
Justin Thaler3d71d402018-07-24 14:35:39 -05004054 fwList = fwflash_subproc.add_parser('list', help="List all of the installed firmware")
4055 fwList.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
4056 fwList.set_defaults(func=firmwareList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004057
Justin Thaler3d71d402018-07-24 14:35:39 -05004058 fwprint = fwflash_subproc.add_parser('print', help="List all of the installed firmware")
4059 fwprint.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
4060 fwprint.set_defaults(func=firmwareList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004061
Adriana Kobylak5af2fad2018-11-08 12:33:43 -06004062 fwDelete = fwflash_subproc.add_parser('delete', help="Delete an existing firmware version")
4063 fwDelete.add_argument('versionID', help="The version ID to delete from the firmware list. Ex: 63c95399")
4064 fwDelete.set_defaults(func=deleteFWVersion)
4065
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05004066 #logging
4067 parser_logging = subparsers.add_parser("logging", help="logging controls")
4068 logging_sub = parser_logging.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004069
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05004070 #turn rest api logging on/off
4071 parser_rest_logging = logging_sub.add_parser("rest_api", help="turn rest api logging on/off")
4072 parser_rest_logging.add_argument('rest_logging', choices=['on', 'off'], help='The control option for rest logging: on, off')
4073 parser_rest_logging.set_defaults(func=restLogging)
Deepak Kodihalli02d53282018-09-18 06:53:31 -05004074
4075 #remote logging
4076 parser_remote_logging = logging_sub.add_parser("remote_logging", help="Remote logging (rsyslog) commands")
4077 parser_remote_logging.add_argument('remote_logging', choices=['view', 'disable'], help='Remote logging (rsyslog) commands')
4078 parser_remote_logging.set_defaults(func=remoteLogging)
4079
4080 #configure remote logging
4081 parser_remote_logging_config = logging_sub.add_parser("remote_logging_config", help="Configure remote logging (rsyslog)")
4082 parser_remote_logging_config.add_argument("-a", "--address", required=True, help="Set IP address of rsyslog server")
4083 parser_remote_logging_config.add_argument("-p", "--port", required=True, type=int, help="Set Port of rsyslog server")
4084 parser_remote_logging_config.set_defaults(func=remoteLoggingConfig)
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05004085
4086 #certificate management
4087 parser_cert = subparsers.add_parser("certificate", help="Certificate management")
4088 certMgmt_subproc = parser_cert.add_subparsers(title='subcommands', description='valid certificate commands', help='sub-command help', dest='command')
4089
4090 certUpdate = certMgmt_subproc.add_parser('update', help="Update the certificate")
4091 certUpdate.add_argument('type', choices=['server', 'client', 'authority'], help="certificate type to update")
4092 certUpdate.add_argument('service', choices=['https', 'ldap'], help="Service to update")
4093 certUpdate.add_argument('-f', '--fileloc', required=True, help="The absolute path to the certificate file")
4094 certUpdate.set_defaults(func=certificateUpdate)
4095
4096 certDelete = certMgmt_subproc.add_parser('delete', help="Delete the certificate")
4097 certDelete.add_argument('type', choices=['server', 'client', 'authority'], help="certificate type to delete")
4098 certDelete.add_argument('service', choices=['https', 'ldap'], help="Service to delete the certificate")
4099 certDelete.set_defaults(func=certificateDelete)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004100
Marri Devender Raodfe81ad2019-07-01 05:38:09 -05004101 certReplace = certMgmt_subproc.add_parser('replace',
4102 help="Replace the certificate")
4103 certReplace.add_argument('type', choices=['server', 'client', 'authority'],
4104 help="certificate type to replace")
4105 certReplace.add_argument('service', choices=['https', 'ldap'],
4106 help="Service to replace the certificate")
4107 certReplace.add_argument('-f', '--fileloc', required=True,
4108 help="The absolute path to the certificate file")
4109 certReplace.set_defaults(func=certificateReplace)
4110
Marri Devender Rao34646402019-07-01 05:46:03 -05004111 certDisplay = certMgmt_subproc.add_parser('display',
4112 help="Print the certificate")
4113 certDisplay.add_argument('type', choices=['server', 'client', 'authority'],
4114 help="certificate type to display")
4115 certDisplay.set_defaults(func=certificateDisplay)
4116
Marri Devender Raoa208ff82019-07-01 05:51:27 -05004117 certList = certMgmt_subproc.add_parser('list',
4118 help="Certificate list")
4119 certList.set_defaults(func=certificateList)
4120
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05004121 certGenerateCSR = certMgmt_subproc.add_parser('generatecsr', help="Generate CSR")
4122 certGenerateCSR.add_argument('type', choices=['server', 'client', 'authority'],
4123 help="Generate CSR")
4124 certGenerateCSR.add_argument('city',
4125 help="The city or locality of the organization making the request")
4126 certGenerateCSR.add_argument('commonName',
4127 help="The fully qualified domain name of the component that is being secured.")
4128 certGenerateCSR.add_argument('country',
4129 help="The country of the organization making the request")
4130 certGenerateCSR.add_argument('organization',
4131 help="The name of the organization making the request.")
4132 certGenerateCSR.add_argument('organizationUnit',
4133 help="The name of the unit or division of the organization making the request.")
4134 certGenerateCSR.add_argument('state',
4135 help="The state, province, or region of the organization making the request.")
4136 certGenerateCSR.add_argument('keyPairAlgorithm', choices=['RSA', 'EC'],
4137 help="The type of key pair for use with signing algorithms.")
4138 certGenerateCSR.add_argument('keyBitLength', choices=['2048'],
4139 help="The length of the key in bits, if needed based on the value of the 'KeyPairAlgorithm' parameter.")
4140 certGenerateCSR.add_argument('keyCurveId',
4141 help="The curve ID to be used with the key, if needed based on the value of the 'KeyPairAlgorithm' parameter.")
4142 certGenerateCSR.add_argument('contactPerson',
4143 help="The name of the user making the request")
4144 certGenerateCSR.add_argument('email',
4145 help="The email address of the contact within the organization")
4146 certGenerateCSR.add_argument('alternativeNames',
4147 help="Additional hostnames of the component that is being secured")
4148 certGenerateCSR.add_argument('givenname',
4149 help="The given name of the user making the request")
4150 certGenerateCSR.add_argument('surname',
4151 help="The surname of the user making the request")
4152 certGenerateCSR.add_argument('unstructuredname',
4153 help="he unstructured name of the subject")
4154 certGenerateCSR.add_argument('initials',
4155 help="The initials of the user making the request")
4156 certGenerateCSR.add_argument('keyUsage', help="The usage of the key contained in the certificate")
4157
4158 certGenerateCSR.set_defaults(func=certificateGenerateCSR)
4159
Matt Spinler7d426c22018-09-24 14:42:07 -05004160 # local users
4161 parser_users = subparsers.add_parser("local_users", help="Work with local users")
4162 parser_users.add_argument('local_users', choices=['disableall','enableall', 'queryenabled'], help="Disable, enable or query local user accounts")
4163 parser_users.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
4164 parser_users.set_defaults(func=localUsers)
4165
Ratan Gupta9166cd22018-10-01 18:09:40 +05304166 #LDAP
4167 parser_ldap = subparsers.add_parser("ldap", help="LDAP controls")
4168 ldap_sub = parser_ldap.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
4169
4170 #configure and enable LDAP
4171 parser_ldap_config = ldap_sub.add_parser("enable", help="Configure and enables the LDAP")
4172 parser_ldap_config.add_argument("-a", "--uri", required=True, help="Set LDAP server URI")
4173 parser_ldap_config.add_argument("-B", "--bindDN", required=True, help="Set the bind DN of the LDAP server")
4174 parser_ldap_config.add_argument("-b", "--baseDN", required=True, help="Set the base DN of the LDAP server")
4175 parser_ldap_config.add_argument("-p", "--bindPassword", required=True, help="Set the bind password of the LDAP server")
4176 parser_ldap_config.add_argument("-S", "--scope", choices=['sub','one', 'base'],
4177 help='Specifies the search scope:subtree, one level or base object.')
4178 parser_ldap_config.add_argument("-t", "--serverType", choices=['ActiveDirectory','OpenLDAP'],
4179 help='Specifies the configured server is ActiveDirectory(AD) or OpenLdap')
4180 parser_ldap_config.set_defaults(func=enableLDAP)
4181
4182 # disable LDAP
4183 parser_disable_ldap = ldap_sub.add_parser("disable", help="disables the LDAP")
4184 parser_disable_ldap.set_defaults(func=disableLDAP)
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06004185 # view-config
4186 parser_ldap_config = \
4187 ldap_sub.add_parser("view-config", help="prints out a list of all \
4188 LDAPS's configured properties")
4189 parser_ldap_config.set_defaults(func=viewLDAPConfig)
Ratan Gupta9166cd22018-10-01 18:09:40 +05304190
Ratan Guptafeee6372018-10-17 23:25:51 +05304191 #create group privilege mapping
4192 parser_ldap_mapper = ldap_sub.add_parser("privilege-mapper", help="LDAP group privilege controls")
4193 parser_ldap_mapper_sub = parser_ldap_mapper.add_subparsers(title='subcommands', description='valid subcommands',
4194 help="sub-command help", dest='command')
4195
4196 parser_ldap_mapper_create = parser_ldap_mapper_sub.add_parser("create", help="Create mapping of ldap group and privilege")
4197 parser_ldap_mapper_create.add_argument("-g","--groupName",required=True,help="Group Name")
4198 parser_ldap_mapper_create.add_argument("-p","--privilege",choices=['priv-admin','priv-user'],required=True,help="Privilege")
4199 parser_ldap_mapper_create.set_defaults(func=createPrivilegeMapping)
4200
4201 #list group privilege mapping
4202 parser_ldap_mapper_list = parser_ldap_mapper_sub.add_parser("list",help="List privilege mapping")
4203 parser_ldap_mapper_list.set_defaults(func=listPrivilegeMapping)
4204
4205 #delete group privilege mapping
4206 parser_ldap_mapper_delete = parser_ldap_mapper_sub.add_parser("delete",help="Delete privilege mapping")
4207 parser_ldap_mapper_delete.add_argument("-g","--groupName",required=True,help="Group Name")
4208 parser_ldap_mapper_delete.set_defaults(func=deletePrivilegeMapping)
4209
Sivas SRR78835272018-11-27 05:27:19 -06004210 #deleteAll group privilege mapping
4211 parser_ldap_mapper_delete = parser_ldap_mapper_sub.add_parser("purge",help="Delete All privilege mapping")
4212 parser_ldap_mapper_delete.set_defaults(func=deleteAllPrivilegeMapping)
4213
Marri Devender Rao2c2a5162018-11-05 08:57:11 -06004214 # set local user password
4215 parser_set_password = subparsers.add_parser("set_password",
4216 help="Set password of local user")
4217 parser_set_password.add_argument( "-p", "--password", required=True,
4218 help="Password of local user")
4219 parser_set_password.set_defaults(func=setPassword)
4220
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004221 # network
4222 parser_nw = subparsers.add_parser("network", help="network controls")
4223 nw_sub = parser_nw.add_subparsers(title='subcommands',
4224 description='valid subcommands',
4225 help="sub-command help",
4226 dest='command')
4227
4228 # enable DHCP
4229 parser_enable_dhcp = nw_sub.add_parser("enableDHCP",
4230 help="enables the DHCP on given "
4231 "Interface")
4232 parser_enable_dhcp.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004233 help="Name of the ethernet interface(it can"
4234 "be obtained by the "
4235 "command:network view-config)"
4236 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004237 parser_enable_dhcp.set_defaults(func=enableDHCP)
4238
4239 # disable DHCP
4240 parser_disable_dhcp = nw_sub.add_parser("disableDHCP",
4241 help="disables the DHCP on given "
4242 "Interface")
4243 parser_disable_dhcp.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004244 help="Name of the ethernet interface(it can"
4245 "be obtained by the "
4246 "command:network view-config)"
4247 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004248 parser_disable_dhcp.set_defaults(func=disableDHCP)
4249
4250 # get HostName
4251 parser_gethostname = nw_sub.add_parser("getHostName",
4252 help="prints out HostName")
4253 parser_gethostname.set_defaults(func=getHostname)
4254
4255 # set HostName
4256 parser_sethostname = nw_sub.add_parser("setHostName", help="sets HostName")
4257 parser_sethostname.add_argument("-H", "--HostName", required=True,
4258 help="A HostName for the BMC")
4259 parser_sethostname.set_defaults(func=setHostname)
4260
4261 # get domainname
4262 parser_getdomainname = nw_sub.add_parser("getDomainName",
4263 help="prints out DomainName of "
4264 "given Interface")
4265 parser_getdomainname.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004266 help="Name of the ethernet interface(it "
4267 "can be obtained by the "
4268 "command:network view-config)"
4269 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004270 parser_getdomainname.set_defaults(func=getDomainName)
4271
4272 # set domainname
4273 parser_setdomainname = nw_sub.add_parser("setDomainName",
4274 help="sets DomainName of given "
4275 "Interface")
4276 parser_setdomainname.add_argument("-D", "--DomainName", required=True,
4277 help="Ex: DomainName=Domain1,Domain2,...")
4278 parser_setdomainname.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004279 help="Name of the ethernet interface(it "
4280 "can be obtained by the "
4281 "command:network view-config)"
4282 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004283 parser_setdomainname.set_defaults(func=setDomainName)
4284
4285 # get MACAddress
4286 parser_getmacaddress = nw_sub.add_parser("getMACAddress",
4287 help="prints out MACAddress the "
4288 "given Interface")
4289 parser_getmacaddress.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004290 help="Name of the ethernet interface(it "
4291 "can be obtained by the "
4292 "command:network view-config)"
4293 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004294 parser_getmacaddress.set_defaults(func=getMACAddress)
4295
4296 # set MACAddress
4297 parser_setmacaddress = nw_sub.add_parser("setMACAddress",
4298 help="sets MACAddress")
4299 parser_setmacaddress.add_argument("-MA", "--MACAddress", required=True,
4300 help="A MACAddress for the given "
4301 "Interface")
4302 parser_setmacaddress.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004303 help="Name of the ethernet interface(it can"
4304 "be obtained by the "
4305 "command:network view-config)"
4306 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004307 parser_setmacaddress.set_defaults(func=setMACAddress)
4308
4309 # get DefaultGW
4310 parser_getdefaultgw = nw_sub.add_parser("getDefaultGW",
4311 help="prints out DefaultGateway "
4312 "the BMC")
4313 parser_getdefaultgw.set_defaults(func=getDefaultGateway)
4314
4315 # set DefaultGW
4316 parser_setdefaultgw = nw_sub.add_parser("setDefaultGW",
4317 help="sets DefaultGW")
4318 parser_setdefaultgw.add_argument("-GW", "--DefaultGW", required=True,
4319 help="A DefaultGateway for the BMC")
4320 parser_setdefaultgw.set_defaults(func=setDefaultGateway)
4321
4322 # view network Config
4323 parser_ldap_config = nw_sub.add_parser("view-config", help="prints out a "
4324 "list of all network's configured "
4325 "properties")
4326 parser_ldap_config.set_defaults(func=viewNWConfig)
4327
4328 # get DNS
4329 parser_getDNS = nw_sub.add_parser("getDNS",
4330 help="prints out DNS servers on the "
4331 "given interface")
4332 parser_getDNS.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004333 help="Name of the ethernet interface(it can"
4334 "be obtained by the "
4335 "command:network view-config)"
4336 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004337 parser_getDNS.set_defaults(func=getDNS)
4338
4339 # set DNS
4340 parser_setDNS = nw_sub.add_parser("setDNS",
4341 help="sets DNS servers on the given "
4342 "interface")
4343 parser_setDNS.add_argument("-d", "--DNSServers", required=True,
4344 help="Ex: DNSSERVERS=DNS1,DNS2,...")
4345 parser_setDNS.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004346 help="Name of the ethernet interface(it can"
4347 "be obtained by the "
4348 "command:network view-config)"
4349 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004350 parser_setDNS.set_defaults(func=setDNS)
4351
4352 # get NTP
4353 parser_getNTP = nw_sub.add_parser("getNTP",
4354 help="prints out NTP servers on the "
4355 "given interface")
4356 parser_getNTP.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004357 help="Name of the ethernet interface(it can"
4358 "be obtained by the "
4359 "command:network view-config)"
4360 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004361 parser_getNTP.set_defaults(func=getNTP)
4362
4363 # set NTP
4364 parser_setNTP = nw_sub.add_parser("setNTP",
4365 help="sets NTP servers on the given "
4366 "interface")
4367 parser_setNTP.add_argument("-N", "--NTPServers", required=True,
4368 help="Ex: NTPSERVERS=NTP1,NTP2,...")
4369 parser_setNTP.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004370 help="Name of the ethernet interface(it can"
4371 "be obtained by the "
4372 "command:network view-config)"
4373 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004374 parser_setNTP.set_defaults(func=setNTP)
4375
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004376 # configure IP
4377 parser_ip_config = nw_sub.add_parser("addIP", help="Sets IP address to"
4378 "given interface")
4379 parser_ip_config.add_argument("-a", "--address", required=True,
4380 help="IP address of given interface")
4381 parser_ip_config.add_argument("-gw", "--gateway", required=False, default='',
4382 help="The gateway for given interface")
4383 parser_ip_config.add_argument("-l", "--prefixLength", required=True,
4384 help="The prefixLength of IP address")
4385 parser_ip_config.add_argument("-p", "--type", choices=['ipv4', 'ipv6'],
4386 help="The protocol type of the given"
4387 "IP address")
4388 parser_ip_config.add_argument("-I", "--Interface", required=True,
4389 help="Name of the ethernet interface(it can"
4390 "be obtained by the "
4391 "command:network view-config)"
4392 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
4393 parser_ip_config.set_defaults(func=addIP)
4394
4395 # getIP
4396 parser_getIP = nw_sub.add_parser("getIP", help="prints out IP address"
4397 "of given interface")
4398 parser_getIP.add_argument("-I", "--Interface", required=True,
4399 help="Name of the ethernet interface(it can"
4400 "be obtained by the command:network view-config)"
4401 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
4402 parser_getIP.set_defaults(func=getIP)
4403
4404 # rmIP
4405 parser_rmIP = nw_sub.add_parser("rmIP", help="deletes IP address"
4406 "of given interface")
4407 parser_rmIP.add_argument("-a", "--address", required=True,
4408 help="IP address to remove form given Interface")
4409 parser_rmIP.add_argument("-I", "--Interface", required=True,
4410 help="Name of the ethernet interface(it can"
4411 "be obtained by the command:network view-config)"
4412 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
4413 parser_rmIP.set_defaults(func=deleteIP)
4414
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004415 # add VLAN
4416 parser_create_vlan = nw_sub.add_parser("addVLAN", help="enables VLAN "
4417 "on given interface with given "
4418 "VLAN Identifier")
4419 parser_create_vlan.add_argument("-I", "--Interface", required=True,
4420 choices=['eth0', 'eth1'],
4421 help="Name of the ethernet interface")
4422 parser_create_vlan.add_argument("-n", "--Identifier", required=True,
4423 help="VLAN Identifier")
4424 parser_create_vlan.set_defaults(func=addVLAN)
4425
4426 # delete VLAN
4427 parser_delete_vlan = nw_sub.add_parser("deleteVLAN", help="disables VLAN "
4428 "on given interface with given "
4429 "VLAN Identifier")
4430 parser_delete_vlan.add_argument("-I", "--Interface", required=True,
4431 help="Name of the ethernet interface(it can"
4432 "be obtained by the "
4433 "command:network view-config)"
4434 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
4435 parser_delete_vlan.set_defaults(func=deleteVLAN)
4436
4437 # viewDHCPConfig
4438 parser_viewDHCPConfig = nw_sub.add_parser("viewDHCPConfig",
4439 help="Shows DHCP configured "
4440 "Properties")
4441 parser_viewDHCPConfig.set_defaults(func=viewDHCPConfig)
4442
4443 # configureDHCP
4444 parser_configDHCP = nw_sub.add_parser("configureDHCP",
4445 help="Configures/updates DHCP "
4446 "Properties")
4447 parser_configDHCP.add_argument("-d", "--DNSEnabled", type=str2bool,
4448 required=True, help="Sets DNSEnabled property")
4449 parser_configDHCP.add_argument("-n", "--HostNameEnabled", type=str2bool,
4450 required=True,
4451 help="Sets HostNameEnabled property")
4452 parser_configDHCP.add_argument("-t", "--NTPEnabled", type=str2bool,
4453 required=True,
4454 help="Sets NTPEnabled property")
4455 parser_configDHCP.add_argument("-s", "--SendHostNameEnabled", type=str2bool,
4456 required=True,
4457 help="Sets SendHostNameEnabled property")
4458 parser_configDHCP.set_defaults(func=configureDHCP)
4459
4460 # network factory reset
4461 parser_nw_reset = nw_sub.add_parser("nwReset",
4462 help="Resets networks setting to "
4463 "factory defaults. "
4464 "note:Reset settings will be applied "
4465 "after BMC reboot")
4466 parser_nw_reset.set_defaults(func=nwReset)
4467
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004468 return parser
4469
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004470def main(argv=None):
Justin Thalere412dc22018-01-12 16:28:24 -06004471 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004472 main function for running the command line utility as a sub application
4473 """
4474 global toolVersion
Marri Devender Rao82590dc2019-06-06 04:54:22 -05004475 toolVersion = "1.15"
Sunitha Harishc99faba2019-07-19 06:55:22 -05004476 global isRedfishSupport
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004477 parser = createCommandParser()
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004478 args = parser.parse_args(argv)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004479
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004480 totTimeStart = int(round(time.time()*1000))
4481
4482 if(sys.version_info < (3,0)):
4483 urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
4484 if sys.version_info >= (3,0):
4485 requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)
Justin Thalere412dc22018-01-12 16:28:24 -06004486 if (args.version):
Justin Thaler22b1bb52018-03-15 13:31:32 -05004487 print("Version: "+ toolVersion)
Justin Thalere412dc22018-01-12 16:28:24 -06004488 sys.exit(0)
4489 if (hasattr(args, 'fileloc') and args.fileloc is not None and 'print' in args.command):
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004490 mysess = None
Justin Thalere412dc22018-01-12 16:28:24 -06004491 print(selPrint('N/A', args, mysess))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004492 else:
Justin Thalere412dc22018-01-12 16:28:24 -06004493 if(hasattr(args, 'host') and hasattr(args,'user')):
4494 if (args.askpw):
4495 pw = getpass.getpass()
4496 elif(args.PW is not None):
4497 pw = args.PW
Joseph Reynoldsa2d54c52019-06-11 22:02:57 -05004498 elif(args.PWenvvar):
4499 pw = os.environ['OPENBMCTOOL_PASSWORD']
Justin Thalere412dc22018-01-12 16:28:24 -06004500 else:
4501 print("You must specify a password")
4502 sys.exit()
4503 logintimeStart = int(round(time.time()*1000))
4504 mysess = login(args.host, args.user, pw, args.json)
Justin Thalera9415b42018-05-25 19:40:13 -05004505 if(sys.version_info < (3,0)):
4506 if isinstance(mysess, basestring):
4507 print(mysess)
4508 sys.exit(1)
4509 elif sys.version_info >= (3,0):
4510 if isinstance(mysess, str):
4511 print(mysess)
4512 sys.exit(1)
Justin Thalere412dc22018-01-12 16:28:24 -06004513 logintimeStop = int(round(time.time()*1000))
Sunitha Harishc99faba2019-07-19 06:55:22 -05004514 isRedfishSupport = redfishSupportPresent(args.host,mysess)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004515 commandTimeStart = int(round(time.time()*1000))
Justin Thalere412dc22018-01-12 16:28:24 -06004516 output = args.func(args.host, args, mysess)
4517 commandTimeStop = int(round(time.time()*1000))
Justin Thaler761484a2019-03-26 19:20:23 -05004518 if isinstance(output, dict):
4519 print(json.dumps(output, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False))
4520 else:
4521 print(output)
Justin Thalere412dc22018-01-12 16:28:24 -06004522 if (mysess is not None):
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004523 logout(args.host, args.user, pw, mysess, args.json)
4524 if(args.procTime):
Justin Thalere412dc22018-01-12 16:28:24 -06004525 print("Total time: " + str(int(round(time.time()*1000))- totTimeStart))
4526 print("loginTime: " + str(logintimeStop - logintimeStart))
4527 print("command Time: " + str(commandTimeStop - commandTimeStart))
4528 else:
Joseph Reynoldsa2d54c52019-06-11 22:02:57 -05004529 print("usage:\n"
4530 " OPENBMCTOOL_PASSWORD=secret # if using -E\n"
4531 " openbmctool.py [-h] -H HOST -U USER {-A | -P PW | -E} [-j]\n" +
Justin Thalere412dc22018-01-12 16:28:24 -06004532 "\t[-t POLICYTABLELOC] [-V]\n" +
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05004533 "\t{fru,sensors,sel,chassis,collect_service_data, \
4534 health_check,dump,bmc,mc,gardclear,firmware,logging}\n" +
Justin Thalere412dc22018-01-12 16:28:24 -06004535 "\t...\n" +
4536 "openbmctool.py: error: the following arguments are required: -H/--host, -U/--user")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004537 sys.exit()
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004538
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004539if __name__ == '__main__':
Justin Thalere412dc22018-01-12 16:28:24 -06004540 """
4541 main function when called from the command line
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004542
4543 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004544 import sys
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004545
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004546 isTTY = sys.stdout.isatty()
4547 assert sys.version_info >= (2,7)
4548 main()