blob: 715284fcbf2168de87ce1c2b3e02486207499742 [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
Alvin Wangbf99c582019-10-29 16:40:05 +080019import simplejson
Justin Thalerf9aee3e2017-12-05 12:11:09 -060020import getpass
21import json
22import os
23import urllib3
24import time, datetime
Justin Thalerf9aee3e2017-12-05 12:11:09 -060025import binascii
26import subprocess
27import platform
28import zipfile
Justin Thaler22b1bb52018-03-15 13:31:32 -050029import tarfile
30import tempfile
31import hashlib
Justin Thalera6b5df72018-07-16 11:10:07 -050032import re
Justin Thaler24d4efa2018-11-08 22:48:10 -060033import uuid
Justin Thalerf9aee3e2017-12-05 12:11:09 -060034
Matt Spinler220c3c42019-01-04 15:09:29 -060035jsonHeader = {'Content-Type' : 'application/json'}
36xAuthHeader = {}
Justin Thaler27197622019-01-23 14:42:11 -060037baseTimeout = 60
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -050038serverTypeMap = {
39 'ActiveDirectory' : 'active_directory',
40 'OpenLDAP' : 'openldap'
41 }
Matt Spinler220c3c42019-01-04 15:09:29 -060042
Justin Thalerf9aee3e2017-12-05 12:11:09 -060043def hilight(textToColor, color, bold):
Justin Thalere412dc22018-01-12 16:28:24 -060044 """
45 Used to add highlights to various text for displaying in a terminal
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -060046
Justin Thalere412dc22018-01-12 16:28:24 -060047 @param textToColor: string, the text to be colored
48 @param color: string, used to color the text red or green
49 @param bold: boolean, used to bold the textToColor
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -060050 @return: Buffered reader containing the modified string.
51 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -060052 if(sys.platform.__contains__("win")):
53 if(color == "red"):
54 os.system('color 04')
55 elif(color == "green"):
56 os.system('color 02')
57 else:
58 os.system('color') #reset to default
59 return textToColor
60 else:
61 attr = []
62 if(color == "red"):
63 attr.append('31')
64 elif(color == "green"):
65 attr.append('32')
66 else:
67 attr.append('0')
68 if bold:
69 attr.append('1')
70 else:
71 attr.append('0')
72 return '\x1b[%sm%s\x1b[0m' % (';'.join(attr),textToColor)
73
Justin Thalerf9aee3e2017-12-05 12:11:09 -060074def connectionErrHandler(jsonFormat, errorStr, err):
Justin Thalere412dc22018-01-12 16:28:24 -060075 """
76 Error handler various connection errors to bmcs
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -060077
78 @param jsonFormat: boolean, used to output in json format with an error code.
Justin Thalere412dc22018-01-12 16:28:24 -060079 @param errorStr: string, used to color the text red or green
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -060080 @param err: string, the text from the exception
81 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -060082 if errorStr == "Timeout":
83 if not jsonFormat:
84 return("FQPSPIN0000M: Connection timed out. Ensure you have network connectivity to the bmc")
85 else:
Justin Thaler115bca72018-05-25 19:29:08 -050086 conerror = {}
87 conerror['CommonEventID'] = 'FQPSPIN0000M'
88 conerror['sensor']="N/A"
89 conerror['state']="N/A"
90 conerror['additionalDetails'] = "N/A"
91 conerror['Message']="Connection timed out. Ensure you have network connectivity to the BMC"
92 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."
93 conerror['Serviceable']="Yes"
94 conerror['CallHomeCandidate']= "No"
95 conerror['Severity'] = "Critical"
96 conerror['EventType'] = "Communication Failure/Timeout"
97 conerror['VMMigrationFlag'] = "Yes"
98 conerror["AffectedSubsystem"] = "Interconnect (Networking)"
99 conerror["timestamp"] = str(int(time.time()))
100 conerror["UserAction"] = "Verify network connectivity between the two systems and the bmc is functional."
101 eventdict = {}
102 eventdict['event0'] = conerror
103 eventdict['numAlerts'] = '1'
Justin Thaler115bca72018-05-25 19:29:08 -0500104 errorMessageStr = errorMessageStr = json.dumps(eventdict, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600105 return(errorMessageStr)
106 elif errorStr == "ConnectionError":
107 if not jsonFormat:
108 return("FQPSPIN0001M: " + str(err))
109 else:
Justin Thaler115bca72018-05-25 19:29:08 -0500110 conerror = {}
111 conerror['CommonEventID'] = 'FQPSPIN0001M'
112 conerror['sensor']="N/A"
113 conerror['state']="N/A"
114 conerror['additionalDetails'] = str(err)
115 conerror['Message']="Connection Error. View additional details for more information"
116 conerror['LengthyDescription'] = "A connection error to the specified BMC occurred and additional details are provided. Review these details to resolve the issue."
117 conerror['Serviceable']="Yes"
118 conerror['CallHomeCandidate']= "No"
119 conerror['Severity'] = "Critical"
120 conerror['EventType'] = "Communication Failure/Timeout"
121 conerror['VMMigrationFlag'] = "Yes"
122 conerror["AffectedSubsystem"] = "Interconnect (Networking)"
123 conerror["timestamp"] = str(int(time.time()))
124 conerror["UserAction"] = "Correct the issue highlighted in additional details and try again"
125 eventdict = {}
126 eventdict['event0'] = conerror
127 eventdict['numAlerts'] = '1'
Justin Thaler115bca72018-05-25 19:29:08 -0500128 errorMessageStr = json.dumps(eventdict, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600129 return(errorMessageStr)
Justin Thaler115bca72018-05-25 19:29:08 -0500130
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600131 else:
132 return("Unknown Error: "+ str(err))
133
Justin Thalere412dc22018-01-12 16:28:24 -0600134
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600135def setColWidth(keylist, numCols, dictForOutput, colNames):
Justin Thalere412dc22018-01-12 16:28:24 -0600136 """
137 Sets the output width of the columns to display
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600138
139 @param keylist: list, list of strings representing the keys for the dictForOutput
Justin Thalere412dc22018-01-12 16:28:24 -0600140 @param numcols: the total number of columns in the final output
141 @param dictForOutput: dictionary, contains the information to print to the screen
142 @param colNames: list, The strings to use for the column headings, in order of the keylist
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600143 @return: A list of the column widths for each respective column.
Justin Thalere412dc22018-01-12 16:28:24 -0600144 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600145 colWidths = []
146 for x in range(0, numCols):
147 colWidths.append(0)
148 for key in dictForOutput:
149 for x in range(0, numCols):
150 colWidths[x] = max(colWidths[x], len(str(dictForOutput[key][keylist[x]])))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600151
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600152 for x in range(0, numCols):
153 colWidths[x] = max(colWidths[x], len(colNames[x])) +2
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600154
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600155 return colWidths
156
157def loadPolicyTable(pathToPolicyTable):
Justin Thalere412dc22018-01-12 16:28:24 -0600158 """
159 loads a json based policy table into a dictionary
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600160
Justin Thalere412dc22018-01-12 16:28:24 -0600161 @param value: boolean, the value to convert
162 @return: A string of "Yes" or "No"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600163 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600164 policyTable = {}
165 if(os.path.exists(pathToPolicyTable)):
166 with open(pathToPolicyTable, 'r') as stream:
167 try:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600168 contents =json.load(stream)
169 policyTable = contents['events']
Justin Thalere412dc22018-01-12 16:28:24 -0600170 except Exception as err:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600171 print(err)
172 return policyTable
173
Justin Thalere412dc22018-01-12 16:28:24 -0600174
175def boolToString(value):
176 """
177 converts a boolean value to a human readable string value
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600178
Justin Thalere412dc22018-01-12 16:28:24 -0600179 @param value: boolean, the value to convert
180 @return: A string of "Yes" or "No"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600181 """
Justin Thalere412dc22018-01-12 16:28:24 -0600182 if(value):
183 return "Yes"
184 else:
185 return "No"
186
Justin Thalera6b5df72018-07-16 11:10:07 -0500187def stringToInt(text):
188 """
189 returns an integer if the string can be converted, otherwise returns the string
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600190
Justin Thalera6b5df72018-07-16 11:10:07 -0500191 @param text: the string to try to convert to an integer
192 """
193 if text.isdigit():
194 return int(text)
195 else:
196 return text
Justin Thalere412dc22018-01-12 16:28:24 -0600197
Justin Thalera6b5df72018-07-16 11:10:07 -0500198def naturalSort(text):
199 """
200 provides a way to naturally sort a list
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600201
Justin Thalera6b5df72018-07-16 11:10:07 -0500202 @param text: the key to convert for sorting
203 @return list containing the broken up string parts by integers and strings
204 """
205 stringPartList = []
206 for c in re.split('(\d+)', text):
207 stringPartList.append(stringToInt(c))
208 return stringPartList
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600209
Justin Thalere412dc22018-01-12 16:28:24 -0600210def tableDisplay(keylist, colNames, output):
211 """
212 Logs into the BMC and creates a session
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600213
Justin Thalere412dc22018-01-12 16:28:24 -0600214 @param keylist: list, keys for the output dictionary, ordered by colNames
215 @param colNames: Names for the Table of the columns
216 @param output: The dictionary of data to display
217 @return: Session object
218 """
219 colWidth = setColWidth(keylist, len(colNames), output, colNames)
220 row = ""
221 outputText = ""
222 for i in range(len(colNames)):
223 if (i != 0): row = row + "| "
224 row = row + colNames[i].ljust(colWidth[i])
225 outputText += row + "\n"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600226
Justin Thalera6b5df72018-07-16 11:10:07 -0500227 output_keys = list(output.keys())
228 output_keys.sort(key=naturalSort)
229 for key in output_keys:
Justin Thalere412dc22018-01-12 16:28:24 -0600230 row = ""
Justin Thaler8fe0c732018-07-24 14:32:35 -0500231 for i in range(len(keylist)):
Justin Thalere412dc22018-01-12 16:28:24 -0600232 if (i != 0): row = row + "| "
233 row = row + output[key][keylist[i]].ljust(colWidth[i])
234 outputText += row + "\n"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600235
Justin Thalere412dc22018-01-12 16:28:24 -0600236 return outputText
237
Justin Thaler22b1bb52018-03-15 13:31:32 -0500238def checkFWactivation(host, args, session):
239 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600240 Checks the software inventory for an image that is being activated.
241
Justin Thaler22b1bb52018-03-15 13:31:32 -0500242 @return: True if an image is being activated, false is no activations are happening
243 """
244 url="https://"+host+"/xyz/openbmc_project/software/enumerate"
Justin Thaler22b1bb52018-03-15 13:31:32 -0500245 try:
Justin Thaler27197622019-01-23 14:42:11 -0600246 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thaler22b1bb52018-03-15 13:31:32 -0500247 except(requests.exceptions.Timeout):
248 print(connectionErrHandler(args.json, "Timeout", None))
249 return(True)
250 except(requests.exceptions.ConnectionError) as err:
251 print( connectionErrHandler(args.json, "ConnectionError", err))
252 return True
Justin Thaler3a5771b2019-01-23 14:31:52 -0600253 fwInfo = resp.json()['data']
Justin Thaler22b1bb52018-03-15 13:31:32 -0500254 for key in fwInfo:
255 if 'Activation' in fwInfo[key]:
256 if 'Activating' in fwInfo[key]['Activation'] or 'Activating' in fwInfo[key]['RequestedActivation']:
257 return True
258 return False
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600259
Joy Onyerikwu182c3a32019-10-15 08:33:59 -0500260def login(host, username, pw,jsonFormat, allowExpiredPassword):
Justin Thalere412dc22018-01-12 16:28:24 -0600261 """
262 Logs into the BMC and creates a session
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600263
Justin Thalere412dc22018-01-12 16:28:24 -0600264 @param host: string, the hostname or IP address of the bmc to log into
265 @param username: The user name for the bmc to log into
266 @param pw: The password for the BMC to log into
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600267 @param jsonFormat: boolean, flag that will only allow relevant data from user command to be display. This function becomes silent when set to true.
Joy Onyerikwu182c3a32019-10-15 08:33:59 -0500268 @param allowExpiredPassword: true, if the requested operation should
269 be allowed when the password is expired
Justin Thalere412dc22018-01-12 16:28:24 -0600270 @return: Session object
271 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600272 if(jsonFormat==False):
273 print("Attempting login...")
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600274 mysess = requests.session()
275 try:
Justin Thaler27197622019-01-23 14:42:11 -0600276 r = mysess.post('https://'+host+'/login', headers=jsonHeader, json = {"data": [username, pw]}, verify=False, timeout=baseTimeout)
Sunitha Harish336cda22019-07-23 02:02:52 -0500277 if r.status_code == 200:
278 cookie = r.headers['Set-Cookie']
279 match = re.search('SESSION=(\w+);', cookie)
280 if match:
281 xAuthHeader['X-Auth-Token'] = match.group(1)
282 jsonHeader.update(xAuthHeader)
283 loginMessage = json.loads(r.text)
284 if (loginMessage['status'] != "ok"):
285 print(loginMessage["data"]["description"].encode('utf-8'))
286 sys.exit(1)
Joy Onyerikwu182c3a32019-10-15 08:33:59 -0500287 if (('extendedMessage' in r.json()) and
288 ('The password for this account must be changed' in r.json()['extendedMessage'])):
289 if not allowExpiredPassword:
290 print("The password for this system has expired and must be changed"+
291 "\nsee openbmctool.py set_password --help")
292 logout(host, username, pw, mysess, jsonFormat)
293 sys.exit(1)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600294# if(sys.version_info < (3,0)):
295# urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
296# if sys.version_info >= (3,0):
297# requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)
Sunitha Harish336cda22019-07-23 02:02:52 -0500298 return mysess
299 else:
300 return None
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600301 except(requests.exceptions.Timeout):
Justin Thaler115bca72018-05-25 19:29:08 -0500302 return (connectionErrHandler(jsonFormat, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600303 except(requests.exceptions.ConnectionError) as err:
Justin Thaler115bca72018-05-25 19:29:08 -0500304 return (connectionErrHandler(jsonFormat, "ConnectionError", err))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600305
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600306
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600307def logout(host, username, pw, session, jsonFormat):
Justin Thalere412dc22018-01-12 16:28:24 -0600308 """
309 Logs out of the bmc and terminates the session
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600310
Justin Thalere412dc22018-01-12 16:28:24 -0600311 @param host: string, the hostname or IP address of the bmc to log out of
312 @param username: The user name for the bmc to log out of
313 @param pw: The password for the BMC to log out of
314 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600315 @param jsonFormat: boolean, flag that will only allow relevant data from user command to be display. This function becomes silent when set to true.
316 """
Justin Thalere412dc22018-01-12 16:28:24 -0600317 try:
Justin Thaler27197622019-01-23 14:42:11 -0600318 r = session.post('https://'+host+'/logout', headers=jsonHeader,json = {"data": [username, pw]}, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600319 except(requests.exceptions.Timeout):
320 print(connectionErrHandler(jsonFormat, "Timeout", None))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600321
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600322 if(jsonFormat==False):
Matt Spinlereae05b02019-01-24 12:59:34 -0600323 if r.status_code == 200:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600324 print('User ' +username + ' has been logged out')
325
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600326
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600327def fru(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -0600328 """
329 prints out the system inventory. deprecated see fruPrint and fruList
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600330
Justin Thalere412dc22018-01-12 16:28:24 -0600331 @param host: string, the hostname or IP address of the bmc
332 @param args: contains additional arguments used by the fru sub command
333 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600334 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
335 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600336 #url="https://"+host+"/org/openbmc/inventory/system/chassis/enumerate"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600337
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600338 #print(url)
339 #res = session.get(url, headers=httpHeader, verify=False)
340 #print(res.text)
341 #sample = res.text
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600342
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600343 #inv_list = json.loads(sample)["data"]
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600344
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600345 url="https://"+host+"/xyz/openbmc_project/inventory/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600346 try:
Justin Thaler27197622019-01-23 14:42:11 -0600347 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600348 except(requests.exceptions.Timeout):
349 return(connectionErrHandler(args.json, "Timeout", None))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600350
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600351 sample = res.text
352# inv_list.update(json.loads(sample)["data"])
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600353#
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600354# #determine column width's
355# colNames = ["FRU Name", "FRU Type", "Has Fault", "Is FRU", "Present", "Version"]
356# colWidths = setColWidth(["FRU Name", "fru_type", "fault", "is_fru", "present", "version"], 6, inv_list, colNames)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600357#
358# 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 -0600359# "Present".ljust(colWidths[4]) + "Version".ljust(colWidths[5]))
360# format the output
361# for key in sorted(inv_list.keys()):
362# keyParts = key.split("/")
363# isFRU = "True" if (inv_list[key]["is_fru"]==1) else "False"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600364#
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600365# fruEntry = (keyParts[len(keyParts) - 1].ljust(colWidths[0]) + inv_list[key]["fru_type"].ljust(colWidths[1])+
366# inv_list[key]["fault"].ljust(colWidths[2])+isFRU.ljust(colWidths[3])+
367# inv_list[key]["present"].ljust(colWidths[4])+ inv_list[key]["version"].ljust(colWidths[5]))
368# if(isTTY):
369# if(inv_list[key]["is_fru"] == 1):
370# color = "green"
371# bold = True
372# else:
373# color='black'
374# bold = False
375# fruEntry = hilight(fruEntry, color, bold)
376# print (fruEntry)
377 return sample
Justin Thalere412dc22018-01-12 16:28:24 -0600378
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600379def fruPrint(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -0600380 """
381 prints out all inventory
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600382
Justin Thalere412dc22018-01-12 16:28:24 -0600383 @param host: string, the hostname or IP address of the bmc
384 @param args: contains additional arguments used by the fru sub command
385 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600386 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
387 @return returns the total fru list.
388 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600389 url="https://"+host+"/xyz/openbmc_project/inventory/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600390 try:
Justin Thaler27197622019-01-23 14:42:11 -0600391 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600392 except(requests.exceptions.Timeout):
393 return(connectionErrHandler(args.json, "Timeout", None))
394
Justin Thaler3a5771b2019-01-23 14:31:52 -0600395 frulist={}
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600396# print(res.text)
Justin Thaler3a5771b2019-01-23 14:31:52 -0600397 if res.status_code==200:
398 frulist['Hardware'] = res.json()['data']
399 else:
400 if not args.json:
401 return "Error retrieving the system inventory. BMC message: {msg}".format(msg=res.json()['message'])
402 else:
403 return res.json()
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600404 url="https://"+host+"/xyz/openbmc_project/software/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600405 try:
Justin Thaler27197622019-01-23 14:42:11 -0600406 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600407 except(requests.exceptions.Timeout):
408 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600409# print(res.text)
Justin Thaler3a5771b2019-01-23 14:31:52 -0600410 if res.status_code==200:
411 frulist['Software'] = res.json()['data']
412 else:
413 if not args.json():
414 return "Error retrieving the system inventory. BMC message: {msg}".format(msg=res.json()['message'])
415 else:
416 return res.json()
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600417 return frulist
418
Justin Thalere412dc22018-01-12 16:28:24 -0600419
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600420def fruList(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -0600421 """
422 prints out all inventory or only a specific specified item
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 Thalerf9aee3e2017-12-05 12:11:09 -0600429 if(args.items==True):
430 return fruPrint(host, args, session)
431 else:
Justin Thalere412dc22018-01-12 16:28:24 -0600432 return fruPrint(host, args, session)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600433
434
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600435
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600436def fruStatus(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -0600437 """
438 prints out the status of all FRUs
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600439
Justin Thalere412dc22018-01-12 16:28:24 -0600440 @param host: string, the hostname or IP address of the bmc
441 @param args: contains additional arguments used by the fru sub command
442 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600443 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
444 """
Justin Thalere412dc22018-01-12 16:28:24 -0600445 url="https://"+host+"/xyz/openbmc_project/inventory/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600446 try:
Matt Spinler220c3c42019-01-04 15:09:29 -0600447 res = session.get(url, headers=jsonHeader, verify=False)
Justin Thalere412dc22018-01-12 16:28:24 -0600448 except(requests.exceptions.Timeout):
449 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600450# print(res.text)
Justin Thaler3a5771b2019-01-23 14:31:52 -0600451 frulist = res.json()['data']
Justin Thalere412dc22018-01-12 16:28:24 -0600452 frus = {}
453 for key in frulist:
454 component = frulist[key]
455 isFru = False
456 present = False
457 func = False
458 hasSels = False
459 keyPieces = key.split('/')
460 fruName = keyPieces[-1]
461 if 'core' in fruName: #associate cores to cpus
462 fruName = keyPieces[-2] + '-' + keyPieces[-1]
463 if 'Functional' in component:
464 if('Present' in component):
Justin Thalere412dc22018-01-12 16:28:24 -0600465 if 'FieldReplaceable' in component:
466 if component['FieldReplaceable'] == 1:
467 isFru = True
468 if "fan" in fruName:
469 isFru = True;
470 if component['Present'] == 1:
471 present = True
472 if component['Functional'] == 1:
473 func = True
474 if ((key + "/fault") in frulist):
475 hasSels = True;
476 if args.verbose:
477 if hasSels:
478 loglist = []
479 faults = frulist[key+"/fault"]['endpoints']
480 for item in faults:
481 loglist.append(item.split('/')[-1])
482 frus[fruName] = {"compName": fruName, "Functional": boolToString(func), "Present":boolToString(present), "IsFru": boolToString(isFru), "selList": ', '.join(loglist).strip() }
483 else:
484 frus[fruName] = {"compName": fruName, "Functional": boolToString(func), "Present":boolToString(present), "IsFru": boolToString(isFru), "selList": "None" }
485 else:
486 frus[fruName] = {"compName": fruName, "Functional": boolToString(func), "Present":boolToString(present), "IsFru": boolToString(isFru), "hasSEL": boolToString(hasSels) }
Justin Thalerfb9c81c2018-07-16 11:14:37 -0500487 elif "power_supply" in fruName or "powersupply" in fruName:
Justin Thalere412dc22018-01-12 16:28:24 -0600488 if component['Present'] ==1:
489 present = True
490 isFru = True
491 if ((key + "/fault") in frulist):
492 hasSels = True;
493 if args.verbose:
494 if hasSels:
495 loglist = []
496 faults = frulist[key+"/fault"]['endpoints']
Obihörnchenff8035f2018-12-05 21:07:37 +0100497 for item in faults:
498 loglist.append(item.split('/')[-1])
Justin Thalere412dc22018-01-12 16:28:24 -0600499 frus[fruName] = {"compName": fruName, "Functional": "No", "Present":boolToString(present), "IsFru": boolToString(isFru), "selList": ', '.join(loglist).strip() }
500 else:
501 frus[fruName] = {"compName": fruName, "Functional": "Yes", "Present":boolToString(present), "IsFru": boolToString(isFru), "selList": "None" }
502 else:
503 frus[fruName] = {"compName": fruName, "Functional": boolToString(not hasSels), "Present":boolToString(present), "IsFru": boolToString(isFru), "hasSEL": boolToString(hasSels) }
504 if not args.json:
505 if not args.verbose:
506 colNames = ["Component", "Is a FRU", "Present", "Functional", "Has Logs"]
507 keylist = ["compName", "IsFru", "Present", "Functional", "hasSEL"]
508 else:
509 colNames = ["Component", "Is a FRU", "Present", "Functional", "Assoc. Log Number(s)"]
510 keylist = ["compName", "IsFru", "Present", "Functional", "selList"]
511 return tableDisplay(keylist, colNames, frus)
512 else:
513 return str(json.dumps(frus, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600514
Justin Thalere412dc22018-01-12 16:28:24 -0600515def sensor(host, args, session):
516 """
517 prints out all sensors
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600518
Justin Thalere412dc22018-01-12 16:28:24 -0600519 @param host: string, the hostname or IP address of the bmc
520 @param args: contains additional arguments used by the sensor sub command
521 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600522 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
523 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600524 url="https://"+host+"/xyz/openbmc_project/sensors/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600525 try:
Justin Thaler27197622019-01-23 14:42:11 -0600526 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600527 except(requests.exceptions.Timeout):
528 return(connectionErrHandler(args.json, "Timeout", None))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600529
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600530 #Get OCC status
531 url="https://"+host+"/org/open_power/control/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600532 try:
Justin Thaler27197622019-01-23 14:42:11 -0600533 occres = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600534 except(requests.exceptions.Timeout):
535 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600536 if not args.json:
537 colNames = ['sensor', 'type', 'units', 'value', 'target']
Justin Thaler3a5771b2019-01-23 14:31:52 -0600538 sensors = res.json()["data"]
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600539 output = {}
540 for key in sensors:
541 senDict = {}
542 keyparts = key.split("/")
Matt Spinler596ef742019-09-20 08:54:36 -0500543
544 # Associations like the following also show up here:
545 # /xyz/openbmc_project/sensors/<type>/<name>/<assoc-name>
546 # Skip them.
547 # Note: keyparts[0] = '' which is why there are 7 segments.
548 if len(keyparts) > 6:
549 continue
550
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600551 senDict['sensorName'] = keyparts[-1]
552 senDict['type'] = keyparts[-2]
Justin Thalere412dc22018-01-12 16:28:24 -0600553 try:
554 senDict['units'] = sensors[key]['Unit'].split('.')[-1]
555 except KeyError:
Justin Thaler22b1bb52018-03-15 13:31:32 -0500556 senDict['units'] = "N/A"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600557 if('Scale' in sensors[key]):
558 scale = 10 ** sensors[key]['Scale']
559 else:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600560 scale = 1
Justin Thaler22b1bb52018-03-15 13:31:32 -0500561 try:
562 senDict['value'] = str(sensors[key]['Value'] * scale)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600563 except KeyError:
Justin Thaler22b1bb52018-03-15 13:31:32 -0500564 if 'value' in sensors[key]:
565 senDict['value'] = sensors[key]['value']
566 else:
567 senDict['value'] = "N/A"
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600568 if 'Target' in sensors[key]:
569 senDict['target'] = str(sensors[key]['Target'])
570 else:
571 senDict['target'] = 'N/A'
572 output[senDict['sensorName']] = senDict
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600573
Justin Thaler3a5771b2019-01-23 14:31:52 -0600574 occstatus = occres.json()["data"]
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600575 if '/org/open_power/control/occ0' in occstatus:
576 occ0 = occstatus["/org/open_power/control/occ0"]['OccActive']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600577 if occ0 == 1:
578 occ0 = 'Active'
579 else:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600580 occ0 = 'Inactive'
581 output['OCC0'] = {'sensorName':'OCC0', 'type': 'Discrete', 'units': 'N/A', 'value': occ0, 'target': 'Active'}
582 occ1 = occstatus["/org/open_power/control/occ1"]['OccActive']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600583 if occ1 == 1:
584 occ1 = 'Active'
585 else:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600586 occ1 = 'Inactive'
587 output['OCC1'] = {'sensorName':'OCC1', 'type': 'Discrete', 'units': 'N/A', 'value': occ0, 'target': 'Active'}
588 else:
589 output['OCC0'] = {'sensorName':'OCC0', 'type': 'Discrete', 'units': 'N/A', 'value': 'Inactive', 'target': 'Inactive'}
590 output['OCC1'] = {'sensorName':'OCC1', 'type': 'Discrete', 'units': 'N/A', 'value': 'Inactive', 'target': 'Inactive'}
591 keylist = ['sensorName', 'type', 'units', 'value', 'target']
Justin Thalere412dc22018-01-12 16:28:24 -0600592
593 return tableDisplay(keylist, colNames, output)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600594 else:
595 return res.text + occres.text
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600596
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600597def sel(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -0600598 """
599 prints out the bmc alerts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600600
Justin Thalere412dc22018-01-12 16:28:24 -0600601 @param host: string, the hostname or IP address of the bmc
602 @param args: contains additional arguments used by the sel sub command
603 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600604 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
605 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600606
607 url="https://"+host+"/xyz/openbmc_project/logging/entry/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600608 try:
Justin Thaler27197622019-01-23 14:42:11 -0600609 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600610 except(requests.exceptions.Timeout):
611 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600612 return res.text
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600613
614
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600615def parseESEL(args, eselRAW):
Justin Thalere412dc22018-01-12 16:28:24 -0600616 """
617 parses the esel data and gets predetermined search terms
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600618
Justin Thalere412dc22018-01-12 16:28:24 -0600619 @param eselRAW: string, the raw esel string from the bmc
620 @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 -0600621 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600622 eselParts = {}
623 esel_bin = binascii.unhexlify(''.join(eselRAW.split()[16:]))
624 #search terms contains the search term as the key and the return dictionary key as it's value
625 searchTerms = { 'Signature Description':'signatureDescription', 'devdesc':'devdesc',
Justin Thaler22b1bb52018-03-15 13:31:32 -0500626 'Callout type': 'calloutType', 'Procedure':'procedure', 'Sensor Type': 'sensorType'}
Justin Thaler24d4efa2018-11-08 22:48:10 -0600627 uniqueID = str(uuid.uuid4())
628 eselBinPath = tempfile.gettempdir() + os.sep + uniqueID + 'esel.bin'
Justin Thalercf1deae2018-05-25 19:35:21 -0500629 with open(eselBinPath, 'wb') as f:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600630 f.write(esel_bin)
631 errlPath = ""
632 #use the right errl file for the machine architecture
633 arch = platform.machine()
634 if(arch =='x86_64' or arch =='AMD64'):
635 if os.path.exists('/opt/ibm/ras/bin/x86_64/errl'):
636 errlPath = '/opt/ibm/ras/bin/x86_64/errl'
637 elif os.path.exists('errl/x86_64/errl'):
638 errlPath = 'errl/x86_64/errl'
639 else:
640 errlPath = 'x86_64/errl'
641 elif (platform.machine()=='ppc64le'):
642 if os.path.exists('/opt/ibm/ras/bin/ppc64le/errl'):
643 errlPath = '/opt/ibm/ras/bin/ppc64le/errl'
644 elif os.path.exists('errl/ppc64le/errl'):
645 errlPath = 'errl/ppc64le/errl'
646 else:
647 errlPath = 'ppc64le/errl'
648 else:
649 print("machine architecture not supported for parsing eSELs")
650 return eselParts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600651
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600652 if(os.path.exists(errlPath)):
Justin Thalercf1deae2018-05-25 19:35:21 -0500653 output= subprocess.check_output([errlPath, '-d', '--file='+eselBinPath]).decode('utf-8')
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600654# output = proc.communicate()[0]
655 lines = output.split('\n')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600656
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600657 if(hasattr(args, 'fullEsel')):
658 return output
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600659
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600660 for i in range(0, len(lines)):
661 lineParts = lines[i].split(':')
662 if(len(lineParts)>1): #ignore multi lines, output formatting lines, and other information
663 for term in searchTerms:
664 if(term in lineParts[0]):
665 temp = lines[i][lines[i].find(':')+1:].strip()[:-1].strip()
666 if lines[i+1].find(':') != -1:
667 if (len(lines[i+1].split(':')[0][1:].strip())==0):
668 while(len(lines[i][:lines[i].find(':')].strip())>2):
Justin Thaler43030422018-11-08 22:50:21 -0600669 #has multiple lines, process and update line counter
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600670 if((i+1) <= len(lines)):
671 i+=1
672 else:
673 i=i-1
674 break
Justin Thaler43030422018-11-08 22:50:21 -0600675 #Append the content from the next line removing the pretty display characters
676 #Finds the first colon then starts 2 characters after, then removes all whitespace
677 temp = temp + lines[i][lines[i].find(':')+2:].strip()[:-1].strip()[:-1].strip()
Justin Thaler22b1bb52018-03-15 13:31:32 -0500678 if(searchTerms[term] in eselParts):
679 eselParts[searchTerms[term]] = eselParts[searchTerms[term]] + ", " + temp
680 else:
681 eselParts[searchTerms[term]] = temp
Justin Thalercf1deae2018-05-25 19:35:21 -0500682 os.remove(eselBinPath)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600683 else:
684 print("errl file cannot be found")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600685
686 return eselParts
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600687
Justin Thalere412dc22018-01-12 16:28:24 -0600688
Matt Spinler02d0dff2018-08-29 13:19:25 -0500689def getESELSeverity(esel):
690 """
691 Finds the severity type in an eSEL from the User Header section.
692 @param esel - the eSEL data
693 @return severity - e.g. 'Critical'
694 """
695
696 # everything but 1 and 2 are Critical
697 # '1': 'recovered',
698 # '2': 'predictive',
699 # '4': 'unrecoverable',
700 # '5': 'critical',
701 # '6': 'diagnostic',
702 # '7': 'symptom'
703 severities = {
704 '1': 'Informational',
705 '2': 'Warning'
706 }
707
708 try:
709 headerPosition = esel.index('55 48') # 'UH'
710 # The severity is the last byte in the 8 byte section (a byte is ' bb')
711 severity = esel[headerPosition:headerPosition+32].split(' ')[-1]
712 type = severity[0]
713 except ValueError:
714 print("Could not find severity value in UH section in eSEL")
715 type = 'x';
716
717 return severities.get(type, 'Critical')
718
719
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600720def sortSELs(events):
Justin Thalere412dc22018-01-12 16:28:24 -0600721 """
722 sorts the sels by timestamp, then log entry number
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600723
Justin Thalere412dc22018-01-12 16:28:24 -0600724 @param events: Dictionary containing events
725 @return: list containing a list of the ordered log entries, and dictionary of keys
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600726 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600727 logNumList = []
728 timestampList = []
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600729 eventKeyDict = {}
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600730 eventsWithTimestamp = {}
731 logNum2events = {}
732 for key in events:
733 if key == 'numAlerts': continue
734 if 'callout' in key: continue
735 timestamp = (events[key]['timestamp'])
736 if timestamp not in timestampList:
737 eventsWithTimestamp[timestamp] = [events[key]['logNum']]
738 else:
739 eventsWithTimestamp[timestamp].append(events[key]['logNum'])
740 #map logNumbers to the event dictionary keys
741 eventKeyDict[str(events[key]['logNum'])] = key
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600742
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600743 timestampList = list(eventsWithTimestamp.keys())
744 timestampList.sort()
745 for ts in timestampList:
746 if len(eventsWithTimestamp[ts]) > 1:
747 tmplist = eventsWithTimestamp[ts]
748 tmplist.sort()
749 logNumList = logNumList + tmplist
750 else:
751 logNumList = logNumList + eventsWithTimestamp[ts]
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600752
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600753 return [logNumList, eventKeyDict]
754
Justin Thalere412dc22018-01-12 16:28:24 -0600755
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600756def parseAlerts(policyTable, selEntries, args):
Justin Thalere412dc22018-01-12 16:28:24 -0600757 """
758 parses alerts in the IBM CER format, using an IBM policy Table
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600759
Justin Thalere412dc22018-01-12 16:28:24 -0600760 @param policyTable: dictionary, the policy table entries
761 @param selEntries: dictionary, the alerts retrieved from the bmc
762 @return: A dictionary of the parsed entries, in chronological order
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600763 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600764 eventDict = {}
765 eventNum =""
766 count = 0
767 esel = ""
768 eselParts = {}
769 i2cdevice= ""
Matt Spinler02d0dff2018-08-29 13:19:25 -0500770 eselSeverity = None
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600771
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600772 'prepare and sort the event entries'
773 for key in selEntries:
774 if 'callout' not in key:
775 selEntries[key]['logNum'] = key.split('/')[-1]
776 selEntries[key]['timestamp'] = selEntries[key]['Timestamp']
777 sortedEntries = sortSELs(selEntries)
778 logNumList = sortedEntries[0]
779 eventKeyDict = sortedEntries[1]
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600780
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600781 for logNum in logNumList:
782 key = eventKeyDict[logNum]
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600783 hasEsel=False
784 i2creadFail = False
785 if 'callout' in key:
786 continue
787 else:
788 messageID = str(selEntries[key]['Message'])
789 addDataPiece = selEntries[key]['AdditionalData']
790 calloutIndex = 0
791 calloutFound = False
792 for i in range(len(addDataPiece)):
793 if("CALLOUT_INVENTORY_PATH" in addDataPiece[i]):
794 calloutIndex = i
795 calloutFound = True
796 fruCallout = str(addDataPiece[calloutIndex]).split('=')[1]
797 if("CALLOUT_DEVICE_PATH" in addDataPiece[i]):
798 i2creadFail = True
Matt Spinlerd178a472018-08-31 09:48:52 -0500799
800 fruCallout = str(addDataPiece[calloutIndex]).split('=')[1]
801
802 # Fall back to "I2C"/"FSI" if dev path isn't in policy table
803 if (messageID + '||' + fruCallout) not in policyTable:
804 i2cdevice = str(addDataPiece[i]).strip().split('=')[1]
805 i2cdevice = '/'.join(i2cdevice.split('/')[-4:])
806 if 'fsi' in str(addDataPiece[calloutIndex]).split('=')[1]:
807 fruCallout = 'FSI'
808 else:
809 fruCallout = 'I2C'
Justin Thalere34c43a2018-05-25 19:37:55 -0500810 calloutFound = True
811 if("CALLOUT_GPIO_NUM" in addDataPiece[i]):
812 if not calloutFound:
813 fruCallout = 'GPIO'
814 calloutFound = True
815 if("CALLOUT_IIC_BUS" in addDataPiece[i]):
816 if not calloutFound:
817 fruCallout = "I2C"
818 calloutFound = True
819 if("CALLOUT_IPMI_SENSOR_NUM" in addDataPiece[i]):
820 if not calloutFound:
821 fruCallout = "IPMI"
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600822 calloutFound = True
823 if("ESEL" in addDataPiece[i]):
824 esel = str(addDataPiece[i]).strip().split('=')[1]
Matt Spinler02d0dff2018-08-29 13:19:25 -0500825 eselSeverity = getESELSeverity(esel)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600826 if args.devdebug:
827 eselParts = parseESEL(args, esel)
828 hasEsel=True
829 if("GPU" in addDataPiece[i]):
830 fruCallout = '/xyz/openbmc_project/inventory/system/chassis/motherboard/gpu' + str(addDataPiece[i]).strip()[-1]
831 calloutFound = True
832 if("PROCEDURE" in addDataPiece[i]):
833 fruCallout = str(hex(int(str(addDataPiece[i]).split('=')[1])))[2:]
834 calloutFound = True
Justin Thalere412dc22018-01-12 16:28:24 -0600835 if("RAIL_NAME" in addDataPiece[i]):
836 calloutFound=True
837 fruCallout = str(addDataPiece[i]).split('=')[1].strip()
838 if("INPUT_NAME" in addDataPiece[i]):
839 calloutFound=True
840 fruCallout = str(addDataPiece[i]).split('=')[1].strip()
841 if("SENSOR_TYPE" in addDataPiece[i]):
842 calloutFound=True
843 fruCallout = str(addDataPiece[i]).split('=')[1].strip()
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600844
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600845 if(calloutFound):
Justin Thaler22b1bb52018-03-15 13:31:32 -0500846 if fruCallout != "":
847 policyKey = messageID +"||" + fruCallout
Matt Spinler02d0dff2018-08-29 13:19:25 -0500848
849 # Also use the severity for hostboot errors
850 if eselSeverity and messageID == 'org.open_power.Host.Error.Event':
851 policyKey += '||' + eselSeverity
852
853 # if not in the table, fall back to the original key
854 if policyKey not in policyTable:
855 policyKey = policyKey.replace('||'+eselSeverity, '')
856
Justin Thalere34c43a2018-05-25 19:37:55 -0500857 if policyKey not in policyTable:
858 policyKey = messageID
Justin Thaler22b1bb52018-03-15 13:31:32 -0500859 else:
860 policyKey = messageID
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600861 else:
862 policyKey = messageID
863 event = {}
864 eventNum = str(count)
865 if policyKey in policyTable:
866 for pkey in policyTable[policyKey]:
867 if(type(policyTable[policyKey][pkey])== bool):
868 event[pkey] = boolToString(policyTable[policyKey][pkey])
869 else:
870 if (i2creadFail and pkey == 'Message'):
871 event[pkey] = policyTable[policyKey][pkey] + ' ' +i2cdevice
872 else:
873 event[pkey] = policyTable[policyKey][pkey]
874 event['timestamp'] = selEntries[key]['Timestamp']
875 event['resolved'] = bool(selEntries[key]['Resolved'])
876 if(hasEsel):
877 if args.devdebug:
878 event['eselParts'] = eselParts
879 event['raweSEL'] = esel
880 event['logNum'] = key.split('/')[-1]
881 eventDict['event' + eventNum] = event
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600882
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600883 else:
884 severity = str(selEntries[key]['Severity']).split('.')[-1]
885 if severity == 'Error':
886 severity = 'Critical'
887 eventDict['event'+eventNum] = {}
888 eventDict['event' + eventNum]['error'] = "error: Not found in policy table: " + policyKey
889 eventDict['event' + eventNum]['timestamp'] = selEntries[key]['Timestamp']
890 eventDict['event' + eventNum]['Severity'] = severity
891 if(hasEsel):
892 if args.devdebug:
893 eventDict['event' +eventNum]['eselParts'] = eselParts
894 eventDict['event' +eventNum]['raweSEL'] = esel
895 eventDict['event' +eventNum]['logNum'] = key.split('/')[-1]
896 eventDict['event' +eventNum]['resolved'] = bool(selEntries[key]['Resolved'])
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600897 count += 1
898 return eventDict
899
900
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600901def selDisplay(events, args):
Justin Thalere412dc22018-01-12 16:28:24 -0600902 """
903 displays alerts in human readable format
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600904
Justin Thalere412dc22018-01-12 16:28:24 -0600905 @param events: Dictionary containing events
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600906 @return:
907 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600908 activeAlerts = []
909 historyAlerts = []
910 sortedEntries = sortSELs(events)
911 logNumList = sortedEntries[0]
912 eventKeyDict = sortedEntries[1]
913 keylist = ['Entry', 'ID', 'Timestamp', 'Serviceable', 'Severity','Message']
914 if(args.devdebug):
915 colNames = ['Entry', 'ID', 'Timestamp', 'Serviceable', 'Severity','Message', 'eSEL contents']
916 keylist.append('eSEL')
917 else:
918 colNames = ['Entry', 'ID', 'Timestamp', 'Serviceable', 'Severity', 'Message']
919 for log in logNumList:
920 selDict = {}
921 alert = events[eventKeyDict[str(log)]]
922 if('error' in alert):
923 selDict['Entry'] = alert['logNum']
924 selDict['ID'] = 'Unknown'
925 selDict['Timestamp'] = datetime.datetime.fromtimestamp(int(alert['timestamp']/1000)).strftime("%Y-%m-%d %H:%M:%S")
926 msg = alert['error']
927 polMsg = msg.split("policy table:")[0]
928 msg = msg.split("policy table:")[1]
929 msgPieces = msg.split("||")
930 err = msgPieces[0]
931 if(err.find("org.open_power.")!=-1):
932 err = err.split("org.open_power.")[1]
933 elif(err.find("xyz.openbmc_project.")!=-1):
934 err = err.split("xyz.openbmc_project.")[1]
935 else:
936 err = msgPieces[0]
937 callout = ""
938 if len(msgPieces) >1:
939 callout = msgPieces[1]
940 if(callout.find("/org/open_power/")!=-1):
941 callout = callout.split("/org/open_power/")[1]
942 elif(callout.find("/xyz/openbmc_project/")!=-1):
943 callout = callout.split("/xyz/openbmc_project/")[1]
944 else:
945 callout = msgPieces[1]
946 selDict['Message'] = polMsg +"policy table: "+ err + "||" + callout
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600947 selDict['Serviceable'] = 'Unknown'
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600948 selDict['Severity'] = alert['Severity']
949 else:
950 selDict['Entry'] = alert['logNum']
951 selDict['ID'] = alert['CommonEventID']
952 selDict['Timestamp'] = datetime.datetime.fromtimestamp(int(alert['timestamp']/1000)).strftime("%Y-%m-%d %H:%M:%S")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600953 selDict['Message'] = alert['Message']
954 selDict['Serviceable'] = alert['Serviceable']
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600955 selDict['Severity'] = alert['Severity']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600956
957
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600958 eselOrder = ['refCode','signatureDescription', 'eselType', 'devdesc', 'calloutType', 'procedure']
959 if ('eselParts' in alert and args.devdebug):
960 eselOutput = ""
961 for item in eselOrder:
962 if item in alert['eselParts']:
963 eselOutput = eselOutput + item + ": " + alert['eselParts'][item] + " | "
964 selDict['eSEL'] = eselOutput
965 else:
966 if args.devdebug:
967 selDict['eSEL'] = "None"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600968
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600969 if not alert['resolved']:
970 activeAlerts.append(selDict)
971 else:
972 historyAlerts.append(selDict)
973 mergedOutput = activeAlerts + historyAlerts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600974 colWidth = setColWidth(keylist, len(colNames), dict(enumerate(mergedOutput)), colNames)
975
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600976 output = ""
977 if(len(activeAlerts)>0):
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600978 row = ""
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600979 output +="----Active Alerts----\n"
980 for i in range(0, len(colNames)):
981 if i!=0: row =row + "| "
982 row = row + colNames[i].ljust(colWidth[i])
983 output += row + "\n"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600984
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600985 for i in range(0,len(activeAlerts)):
986 row = ""
987 for j in range(len(activeAlerts[i])):
988 if (j != 0): row = row + "| "
989 row = row + activeAlerts[i][keylist[j]].ljust(colWidth[j])
990 output += row + "\n"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600991
992 if(len(historyAlerts)>0):
993 row = ""
994 output+= "----Historical Alerts----\n"
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600995 for i in range(len(colNames)):
996 if i!=0: row =row + "| "
997 row = row + colNames[i].ljust(colWidth[i])
998 output += row + "\n"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600999
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001000 for i in range(0, len(historyAlerts)):
1001 row = ""
1002 for j in range(len(historyAlerts[i])):
1003 if (j != 0): row = row + "| "
1004 row = row + historyAlerts[i][keylist[j]].ljust(colWidth[j])
1005 output += row + "\n"
1006# print(events[eventKeyDict[str(log)]])
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001007 return output
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001008
Justin Thalere412dc22018-01-12 16:28:24 -06001009
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001010def selPrint(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001011 """
1012 prints out all bmc alerts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001013
Justin Thalere412dc22018-01-12 16:28:24 -06001014 @param host: string, the hostname or IP address of the bmc
1015 @param args: contains additional arguments used by the fru sub command
1016 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001017 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1018 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001019 if(args.policyTableLoc is None):
1020 if os.path.exists('policyTable.json'):
1021 ptableLoc = "policyTable.json"
1022 elif os.path.exists('/opt/ibm/ras/lib/policyTable.json'):
1023 ptableLoc = '/opt/ibm/ras/lib/policyTable.json'
1024 else:
1025 ptableLoc = 'lib/policyTable.json'
1026 else:
1027 ptableLoc = args.policyTableLoc
1028 policyTable = loadPolicyTable(ptableLoc)
1029 rawselEntries = ""
1030 if(hasattr(args, 'fileloc') and args.fileloc is not None):
1031 if os.path.exists(args.fileloc):
1032 with open(args.fileloc, 'r') as selFile:
1033 selLines = selFile.readlines()
1034 rawselEntries = ''.join(selLines)
1035 else:
1036 print("Error: File not found")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001037 sys.exit(1)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001038 else:
1039 rawselEntries = sel(host, args, session)
1040 loadFailed = False
1041 try:
1042 selEntries = json.loads(rawselEntries)
1043 except ValueError:
1044 loadFailed = True
1045 if loadFailed:
1046 cleanSels = json.dumps(rawselEntries).replace('\\n', '')
1047 #need to load json twice as original content was string escaped a second time
1048 selEntries = json.loads(json.loads(cleanSels))
1049 selEntries = selEntries['data']
Justin Thalere412dc22018-01-12 16:28:24 -06001050
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001051 if 'description' in selEntries:
1052 if(args.json):
1053 return("{\n\t\"numAlerts\": 0\n}")
1054 else:
1055 return("No log entries found")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001056
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001057 else:
1058 if(len(policyTable)>0):
1059 events = parseAlerts(policyTable, selEntries, args)
1060 if(args.json):
1061 events["numAlerts"] = len(events)
1062 retValue = str(json.dumps(events, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False))
1063 return retValue
1064 elif(hasattr(args, 'fullSel')):
1065 return events
1066 else:
1067 #get log numbers to order event entries sequentially
1068 return selDisplay(events, args)
1069 else:
1070 if(args.json):
1071 return selEntries
1072 else:
1073 print("error: Policy Table not found.")
1074 return selEntries
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001075
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001076def selList(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001077 """
1078 prints out all all bmc alerts, or only prints out the specified alerts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001079
Justin Thalere412dc22018-01-12 16:28:24 -06001080 @param host: string, the hostname or IP address of the bmc
1081 @param args: contains additional arguments used by the fru sub command
1082 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001083 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1084 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001085 return(sel(host, args, session))
1086
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001087
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001088def selClear(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001089 """
1090 clears all alerts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001091
Justin Thalere412dc22018-01-12 16:28:24 -06001092 @param host: string, the hostname or IP address of the bmc
1093 @param args: contains additional arguments used by the fru sub command
1094 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001095 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1096 """
Matt Spinler47b13e92019-01-04 14:58:53 -06001097 url="https://"+host+"/xyz/openbmc_project/logging/action/DeleteAll"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001098 data = "{\"data\": [] }"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001099
Justin Thalere412dc22018-01-12 16:28:24 -06001100 try:
Justin Thaler27197622019-01-23 14:42:11 -06001101 res = session.post(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001102 except(requests.exceptions.Timeout):
1103 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001104 if res.status_code == 200:
1105 return "The Alert Log has been cleared. Please allow a few minutes for the action to complete."
1106 else:
1107 print("Unable to clear the logs, trying to clear 1 at a time")
1108 sels = json.loads(sel(host, args, session))['data']
1109 for key in sels:
1110 if 'callout' not in key:
1111 logNum = key.split('/')[-1]
1112 url = "https://"+ host+ "/xyz/openbmc_project/logging/entry/"+logNum+"/action/Delete"
1113 try:
Justin Thaler27197622019-01-23 14:42:11 -06001114 session.post(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001115 except(requests.exceptions.Timeout):
1116 return connectionErrHandler(args.json, "Timeout", None)
1117 sys.exit(1)
1118 except(requests.exceptions.ConnectionError) as err:
1119 return connectionErrHandler(args.json, "ConnectionError", err)
1120 sys.exit(1)
1121 return ('Sel clearing complete')
1122
1123def selSetResolved(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001124 """
1125 sets a sel entry to resolved
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001126
Justin Thalere412dc22018-01-12 16:28:24 -06001127 @param host: string, the hostname or IP address of the bmc
1128 @param args: contains additional arguments used by the fru sub command
1129 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001130 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1131 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001132 url="https://"+host+"/xyz/openbmc_project/logging/entry/" + str(args.selNum) + "/attr/Resolved"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001133 data = "{\"data\": 1 }"
Justin Thalere412dc22018-01-12 16:28:24 -06001134 try:
Justin Thaler27197622019-01-23 14:42:11 -06001135 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001136 except(requests.exceptions.Timeout):
1137 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001138 if res.status_code == 200:
1139 return "Sel entry "+ str(args.selNum) +" is now set to resolved"
1140 else:
1141 return "Unable to set the alert to resolved"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001142
Justin Thalere412dc22018-01-12 16:28:24 -06001143def selResolveAll(host, args, session):
1144 """
1145 sets a sel entry to resolved
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001146
Justin Thalere412dc22018-01-12 16:28:24 -06001147 @param host: string, the hostname or IP address of the bmc
1148 @param args: contains additional arguments used by the fru sub command
1149 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001150 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1151 """
Justin Thalere412dc22018-01-12 16:28:24 -06001152 rawselEntries = sel(host, args, session)
1153 loadFailed = False
1154 try:
1155 selEntries = json.loads(rawselEntries)
1156 except ValueError:
1157 loadFailed = True
1158 if loadFailed:
1159 cleanSels = json.dumps(rawselEntries).replace('\\n', '')
1160 #need to load json twice as original content was string escaped a second time
1161 selEntries = json.loads(json.loads(cleanSels))
1162 selEntries = selEntries['data']
1163
1164 if 'description' in selEntries:
1165 if(args.json):
1166 return("{\n\t\"selsResolved\": 0\n}")
1167 else:
1168 return("No log entries found")
1169 else:
1170 d = vars(args)
1171 successlist = []
1172 failedlist = []
1173 for key in selEntries:
1174 if 'callout' not in key:
1175 d['selNum'] = key.split('/')[-1]
1176 resolved = selSetResolved(host,args,session)
1177 if 'Sel entry' in resolved:
1178 successlist.append(d['selNum'])
1179 else:
1180 failedlist.append(d['selNum'])
1181 output = ""
1182 successlist.sort()
1183 failedlist.sort()
1184 if len(successlist)>0:
1185 output = "Successfully resolved: " +', '.join(successlist) +"\n"
1186 if len(failedlist)>0:
1187 output += "Failed to resolve: " + ', '.join(failedlist) + "\n"
1188 return output
1189
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001190def chassisPower(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001191 """
1192 called by the chassis function. Controls the power state of the chassis, or gets the status
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001193
Justin Thalere412dc22018-01-12 16:28:24 -06001194 @param host: string, the hostname or IP address of the bmc
1195 @param args: contains additional arguments used by the fru sub command
1196 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001197 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1198 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001199 if(args.powcmd == 'on'):
Justin Thaler22b1bb52018-03-15 13:31:32 -05001200 if checkFWactivation(host, args, session):
1201 return ("Chassis Power control disabled during firmware activation")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001202 print("Attempting to Power on...:")
1203 url="https://"+host+"/xyz/openbmc_project/state/host0/attr/RequestedHostTransition"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001204 data = '{"data":"xyz.openbmc_project.State.Host.Transition.On"}'
Justin Thalere412dc22018-01-12 16:28:24 -06001205 try:
Justin Thaler27197622019-01-23 14:42:11 -06001206 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001207 except(requests.exceptions.Timeout):
1208 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001209 return res.text
Justin Thalere412dc22018-01-12 16:28:24 -06001210 elif(args.powcmd == 'softoff'):
Justin Thaler22b1bb52018-03-15 13:31:32 -05001211 if checkFWactivation(host, args, session):
1212 return ("Chassis Power control disabled during firmware activation")
Justin Thalere412dc22018-01-12 16:28:24 -06001213 print("Attempting to Power off gracefully...:")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001214 url="https://"+host+"/xyz/openbmc_project/state/host0/attr/RequestedHostTransition"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001215 data = '{"data":"xyz.openbmc_project.State.Host.Transition.Off"}'
Justin Thalere412dc22018-01-12 16:28:24 -06001216 try:
Justin Thaler27197622019-01-23 14:42:11 -06001217 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001218 except(requests.exceptions.Timeout):
1219 return(connectionErrHandler(args.json, "Timeout", None))
1220 return res.text
1221 elif(args.powcmd == 'hardoff'):
Justin Thaler22b1bb52018-03-15 13:31:32 -05001222 if checkFWactivation(host, args, session):
1223 return ("Chassis Power control disabled during firmware activation")
Justin Thalere412dc22018-01-12 16:28:24 -06001224 print("Attempting to Power off immediately...:")
1225 url="https://"+host+"/xyz/openbmc_project/state/chassis0/attr/RequestedPowerTransition"
Justin Thalere412dc22018-01-12 16:28:24 -06001226 data = '{"data":"xyz.openbmc_project.State.Chassis.Transition.Off"}'
1227 try:
Justin Thaler27197622019-01-23 14:42:11 -06001228 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001229 except(requests.exceptions.Timeout):
1230 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001231 return res.text
1232 elif(args.powcmd == 'status'):
1233 url="https://"+host+"/xyz/openbmc_project/state/chassis0/attr/CurrentPowerState"
Justin Thalere412dc22018-01-12 16:28:24 -06001234 try:
Justin Thaler27197622019-01-23 14:42:11 -06001235 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001236 except(requests.exceptions.Timeout):
1237 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001238 chassisState = json.loads(res.text)['data'].split('.')[-1]
1239 url="https://"+host+"/xyz/openbmc_project/state/host0/attr/CurrentHostState"
Justin Thalere412dc22018-01-12 16:28:24 -06001240 try:
Justin Thaler27197622019-01-23 14:42:11 -06001241 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001242 except(requests.exceptions.Timeout):
1243 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001244 hostState = json.loads(res.text)['data'].split('.')[-1]
1245 url="https://"+host+"/xyz/openbmc_project/state/bmc0/attr/CurrentBMCState"
Justin Thalere412dc22018-01-12 16:28:24 -06001246 try:
Justin Thaler27197622019-01-23 14:42:11 -06001247 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001248 except(requests.exceptions.Timeout):
1249 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001250 bmcState = json.loads(res.text)['data'].split('.')[-1]
1251 if(args.json):
1252 outDict = {"Chassis Power State" : chassisState, "Host Power State" : hostState, "BMC Power State":bmcState}
1253 return json.dumps(outDict, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False)
1254 else:
1255 return "Chassis Power State: " +chassisState + "\nHost Power State: " + hostState + "\nBMC Power State: " + bmcState
1256 else:
1257 return "Invalid chassis power command"
1258
Justin Thalere412dc22018-01-12 16:28:24 -06001259
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001260def chassisIdent(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001261 """
1262 called by the chassis function. Controls the identify led of the chassis. Sets or gets the state
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001263
Justin Thalere412dc22018-01-12 16:28:24 -06001264 @param host: string, the hostname or IP address of the bmc
1265 @param args: contains additional arguments used by the fru sub command
1266 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001267 @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 -06001268 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001269 if(args.identcmd == 'on'):
1270 print("Attempting to turn identify light on...:")
1271 url="https://"+host+"/xyz/openbmc_project/led/groups/enclosure_identify/attr/Asserted"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001272 data = '{"data":true}'
Justin Thalere412dc22018-01-12 16:28:24 -06001273 try:
Justin Thaler27197622019-01-23 14:42:11 -06001274 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001275 except(requests.exceptions.Timeout):
1276 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001277 return res.text
1278 elif(args.identcmd == 'off'):
1279 print("Attempting to turn identify light off...:")
1280 url="https://"+host+"/xyz/openbmc_project/led/groups/enclosure_identify/attr/Asserted"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001281 data = '{"data":false}'
Justin Thalere412dc22018-01-12 16:28:24 -06001282 try:
Justin Thaler27197622019-01-23 14:42:11 -06001283 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001284 except(requests.exceptions.Timeout):
1285 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001286 return res.text
1287 elif(args.identcmd == 'status'):
1288 url="https://"+host+"/xyz/openbmc_project/led/groups/enclosure_identify"
Justin Thalere412dc22018-01-12 16:28:24 -06001289 try:
Justin Thaler27197622019-01-23 14:42:11 -06001290 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001291 except(requests.exceptions.Timeout):
1292 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001293 status = json.loads(res.text)['data']
1294 if(args.json):
1295 return status
1296 else:
1297 if status['Asserted'] == 0:
1298 return "Identify light is off"
1299 else:
1300 return "Identify light is blinking"
1301 else:
1302 return "Invalid chassis identify command"
1303
Justin Thalere412dc22018-01-12 16:28:24 -06001304
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001305def chassis(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001306 """
1307 controls the different chassis commands
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001308
Justin Thalere412dc22018-01-12 16:28:24 -06001309 @param host: string, the hostname or IP address of the bmc
1310 @param args: contains additional arguments used by the fru sub command
1311 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001312 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1313 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001314 if(hasattr(args, 'powcmd')):
1315 result = chassisPower(host,args,session)
1316 elif(hasattr(args, 'identcmd')):
1317 result = chassisIdent(host, args, session)
1318 else:
Justin Thaler22b1bb52018-03-15 13:31:32 -05001319 return "This feature is not yet implemented"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001320 return result
Justin Thalere412dc22018-01-12 16:28:24 -06001321
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001322def bmcDumpRetrieve(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001323 """
1324 Downloads a dump file from the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001325
Justin Thalere412dc22018-01-12 16:28:24 -06001326 @param host: string, the hostname or IP address of the bmc
1327 @param args: contains additional arguments used by the collectServiceData sub command
1328 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001329 @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 -06001330 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001331 dumpNum = args.dumpNum
1332 if (args.dumpSaveLoc is not None):
1333 saveLoc = args.dumpSaveLoc
1334 else:
Justin Thalercf1deae2018-05-25 19:35:21 -05001335 saveLoc = tempfile.gettempdir()
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001336 url ='https://'+host+'/download/dump/' + str(dumpNum)
1337 try:
Justin Thaler27197622019-01-23 14:42:11 -06001338 r = session.get(url, headers=jsonHeader, stream=True, verify=False, timeout=baseTimeout)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001339 if (args.dumpSaveLoc is not None):
1340 if os.path.exists(saveLoc):
1341 if saveLoc[-1] != os.path.sep:
1342 saveLoc = saveLoc + os.path.sep
1343 filename = saveLoc + host+'-dump' + str(dumpNum) + '.tar.xz'
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001344
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001345 else:
1346 return 'Invalid save location specified'
1347 else:
Justin Thalercf1deae2018-05-25 19:35:21 -05001348 filename = tempfile.gettempdir()+os.sep + host+'-dump' + str(dumpNum) + '.tar.xz'
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001349
1350 with open(filename, 'wb') as f:
1351 for chunk in r.iter_content(chunk_size =1024):
1352 if chunk:
1353 f.write(chunk)
1354 return 'Saved as ' + filename
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001355
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001356 except(requests.exceptions.Timeout):
1357 return connectionErrHandler(args.json, "Timeout", None)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001358
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001359 except(requests.exceptions.ConnectionError) as err:
1360 return connectionErrHandler(args.json, "ConnectionError", err)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001361
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001362def bmcDumpList(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001363 """
1364 Lists the number of dump files on the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001365
Justin Thalere412dc22018-01-12 16:28:24 -06001366 @param host: string, the hostname or IP address of the bmc
1367 @param args: contains additional arguments used by the collectServiceData sub command
1368 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001369 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1370 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001371 url ='https://'+host+'/xyz/openbmc_project/dump/list'
1372 try:
Justin Thaler27197622019-01-23 14:42:11 -06001373 r = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thaler3a5771b2019-01-23 14:31:52 -06001374 dumpList = r.json()
1375 return dumpList
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001376 except(requests.exceptions.Timeout):
1377 return connectionErrHandler(args.json, "Timeout", None)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001378
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001379 except(requests.exceptions.ConnectionError) as err:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001380 return connectionErrHandler(args.json, "ConnectionError", err)
1381
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001382def bmcDumpDelete(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001383 """
1384 Deletes BMC dump files from the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001385
Justin Thalere412dc22018-01-12 16:28:24 -06001386 @param host: string, the hostname or IP address of the bmc
1387 @param args: contains additional arguments used by the collectServiceData sub command
1388 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001389 @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 -06001390 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001391 dumpList = []
1392 successList = []
1393 failedList = []
1394 if args.dumpNum is not None:
1395 if isinstance(args.dumpNum, list):
1396 dumpList = args.dumpNum
1397 else:
1398 dumpList.append(args.dumpNum)
1399 for dumpNum in dumpList:
1400 url ='https://'+host+'/xyz/openbmc_project/dump/entry/'+str(dumpNum)+'/action/Delete'
1401 try:
Justin Thaler27197622019-01-23 14:42:11 -06001402 r = session.post(url, headers=jsonHeader, json = {"data": []}, verify=False, timeout=baseTimeout)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001403 if r.status_code == 200:
1404 successList.append(str(dumpNum))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001405 else:
1406 failedList.append(str(dumpNum))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001407 except(requests.exceptions.Timeout):
1408 return connectionErrHandler(args.json, "Timeout", None)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001409 except(requests.exceptions.ConnectionError) as err:
1410 return connectionErrHandler(args.json, "ConnectionError", err)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001411 output = "Successfully deleted dumps: " + ', '.join(successList)
1412 if(len(failedList)>0):
1413 output+= '\nFailed to delete dumps: ' + ', '.join(failedList)
1414 return output
1415 else:
1416 return 'You must specify an entry number to delete'
1417
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001418def bmcDumpDeleteAll(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001419 """
1420 Deletes All BMC dump files from the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001421
Justin Thalere412dc22018-01-12 16:28:24 -06001422 @param host: string, the hostname or IP address of the bmc
1423 @param args: contains additional arguments used by the collectServiceData sub command
1424 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001425 @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 -06001426 """
1427 dumpResp = bmcDumpList(host, args, session)
1428 if 'FQPSPIN0000M' in dumpResp or 'FQPSPIN0001M'in dumpResp:
1429 return dumpResp
Justin Thaler3a5771b2019-01-23 14:31:52 -06001430 dumpList = dumpResp['data']
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001431 d = vars(args)
1432 dumpNums = []
1433 for dump in dumpList:
Alvin Wang28bd09d2019-10-28 13:23:58 +08001434 dumpNum = dump.strip().split('/')[-1]
1435 if dumpNum.isdigit():
1436 dumpNums.append(int(dumpNum))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001437 d['dumpNum'] = dumpNums
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001438
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001439 return bmcDumpDelete(host, args, session)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001440
Justin Thalere412dc22018-01-12 16:28:24 -06001441
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001442def bmcDumpCreate(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001443 """
1444 Creates a bmc dump file
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001445
Justin Thalere412dc22018-01-12 16:28:24 -06001446 @param host: string, the hostname or IP address of the bmc
1447 @param args: contains additional arguments used by the collectServiceData sub command
1448 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001449 @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 -06001450 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001451 url = 'https://'+host+'/xyz/openbmc_project/dump/action/CreateDump'
1452 try:
Justin Thaler27197622019-01-23 14:42:11 -06001453 r = session.post(url, headers=jsonHeader, json = {"data": []}, verify=False, timeout=baseTimeout)
Matt Spinlereae05b02019-01-24 12:59:34 -06001454 if(r.status_code == 200 and not args.json):
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001455 return ('Dump successfully created')
Justin Thaler3a5771b2019-01-23 14:31:52 -06001456 elif(args.json):
1457 return r.json()
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001458 else:
1459 return ('Failed to create dump')
1460 except(requests.exceptions.Timeout):
1461 return connectionErrHandler(args.json, "Timeout", None)
1462 except(requests.exceptions.ConnectionError) as err:
1463 return connectionErrHandler(args.json, "ConnectionError", err)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001464
1465
Justin Thaler666cf342019-01-23 14:44:27 -06001466def csdDumpInitiate(host, args, session):
1467 """
1468 Starts the process of getting the current list of dumps then initiates the creation of one.
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001469
Justin Thaler666cf342019-01-23 14:44:27 -06001470 @param host: string, the hostname or IP address of the bmc
1471 @param args: contains additional arguments used by the collectServiceData sub command
1472 @param session: the active session to use
1473 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1474 """
1475 errorInfo = ""
1476 dumpcount = 0
1477 try:
1478 d = vars(args)
1479 d['json'] = True
1480 except Exception as e:
1481 errorInfo += "Failed to set the json flag to True \n Exception: {eInfo}\n".format(eInfo=e)
1482
1483 try:
1484 for i in range(3):
1485 dumpInfo = bmcDumpList(host, args, session)
1486 if 'data' in dumpInfo:
1487 dumpcount = len(dumpInfo['data'])
1488 break
1489 else:
1490 errorInfo+= "Dump List Message returned: " + json.dumps(dumpInfo,indent=0, separators=(',', ':')).replace('\n','') +"\n"
1491 except Exception as e:
1492 errorInfo+= "Failed to collect the list of dumps.\nException: {eInfo}\n".format(eInfo=e)
1493
1494 #Create a user initiated dump
1495 try:
1496 for i in range(3):
1497 dumpcreated = bmcDumpCreate(host, args, session)
1498 if 'message' in dumpcreated:
1499 if 'ok' in dumpcreated['message'].lower():
1500 break
1501 else:
1502 errorInfo+= "Dump create message returned: " + json.dumps(dumpInfo,indent=0, separators=(',', ':')).replace('\n','') +"\n"
1503 else:
1504 errorInfo+= "Dump create message returned: " + json.dumps(dumpInfo,indent=0, separators=(',', ':')).replace('\n','') +"\n"
1505 except Exception as e:
1506 errorInfo+= "Dump create exception encountered: {eInfo}\n".format(eInfo=e)
1507
1508 output = {}
1509 output['errors'] = errorInfo
1510 output['dumpcount'] = dumpcount
1511 return output
1512
1513def csdInventory(host, args,session, fileDir):
1514 """
1515 Collects the BMC inventory, retrying if necessary
1516
1517 @param host: string, the hostname or IP address of the bmc
1518 @param args: contains additional arguments used by the collectServiceData sub command
1519 @param session: the active session to use
1520 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1521 @param fileDir: string representation of the path to use for putting files created
1522 """
1523 errorInfo = "===========Inventory =============\n"
1524 output={}
1525 inventoryCollected = False
1526 try:
1527 for i in range(3):
1528 frulist = fruPrint(host, args, session)
1529 if 'Hardware' in frulist:
1530 inventoryCollected = True
1531 break
1532 else:
1533 errorInfo += json.dumps(frulist, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n'
1534 except Exception as e:
1535 errorInfo += "Inventory collection exception: {eInfo}\n".format(eInfo=e)
1536 if inventoryCollected:
1537 try:
1538 with open(fileDir +os.sep+'inventory.txt', 'w') as f:
1539 f.write(json.dumps(frulist, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n')
1540 print("Inventory collected and stored in " + fileDir + os.sep + "inventory.txt")
1541 output['fileLoc'] = fileDir+os.sep+'inventory.txt'
1542 except Exception as e:
1543 print("Failed to write inventory to file.")
1544 errorInfo += "Error writing inventory to the file. Exception: {eInfo}\n".format(eInfo=e)
1545
1546 output['errors'] = errorInfo
1547
1548 return output
1549
1550def csdSensors(host, args,session, fileDir):
1551 """
1552 Collects the BMC sensor readings, retrying if necessary
1553
1554 @param host: string, the hostname or IP address of the bmc
1555 @param args: contains additional arguments used by the collectServiceData sub command
1556 @param session: the active session to use
1557 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1558 @param fileDir: string representation of the path to use for putting files created
1559 """
1560 errorInfo = "===========Sensors =============\n"
1561 sensorsCollected = False
1562 output={}
1563 try:
1564 d = vars(args)
1565 d['json'] = False
1566 except Exception as e:
1567 errorInfo += "Failed to set the json flag to False \n Exception: {eInfo}\n".format(eInfo=e)
1568
1569 try:
1570 for i in range(3):
1571 sensorReadings = sensor(host, args, session)
1572 if 'OCC0' in sensorReadings:
1573 sensorsCollected = True
1574 break
1575 else:
1576 errorInfo += sensorReadings
1577 except Exception as e:
1578 errorInfo += "Sensor reading collection exception: {eInfo}\n".format(eInfo=e)
1579 if sensorsCollected:
1580 try:
1581 with open(fileDir +os.sep+'sensorReadings.txt', 'w') as f:
1582 f.write(sensorReadings)
1583 print("Sensor readings collected and stored in " + fileDir + os.sep+ "sensorReadings.txt")
1584 output['fileLoc'] = fileDir+os.sep+'sensorReadings.txt'
1585 except Exception as e:
1586 print("Failed to write sensor readings to file system.")
1587 errorInfo += "Error writing sensor readings to the file. Exception: {eInfo}\n".format(eInfo=e)
1588
1589 output['errors'] = errorInfo
1590 return output
1591
1592def csdLEDs(host,args, session, fileDir):
1593 """
1594 Collects the BMC LED status, retrying if necessary
1595
1596 @param host: string, the hostname or IP address of the bmc
1597 @param args: contains additional arguments used by the collectServiceData sub command
1598 @param session: the active session to use
1599 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1600 @param fileDir: string representation of the path to use for putting files created
1601 """
1602 errorInfo = "===========LEDs =============\n"
1603 ledsCollected = False
1604 output={}
1605 try:
1606 d = vars(args)
1607 d['json'] = True
1608 except Exception as e:
1609 errorInfo += "Failed to set the json flag to False \n Exception: {eInfo}\n".format(eInfo=e)
1610 try:
1611 url="https://"+host+"/xyz/openbmc_project/led/enumerate"
1612 httpHeader = {'Content-Type':'application/json'}
1613 for i in range(3):
1614 try:
1615 ledRes = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
1616 if ledRes.status_code == 200:
1617 ledsCollected = True
1618 leds = ledRes.json()['data']
1619 break
1620 else:
1621 errorInfo += ledRes.text
1622 except(requests.exceptions.Timeout):
1623 errorInfo+=json.dumps( connectionErrHandler(args.json, "Timeout", None), sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n'
1624 except(requests.exceptions.ConnectionError) as err:
1625 errorInfo += json.dumps(connectionErrHandler(args.json, "ConnectionError", err), sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n'
1626 except Exception as e:
1627 errorInfo += "LED status collection exception: {eInfo}\n".format(eInfo=e)
1628
1629 if ledsCollected:
1630 try:
1631 with open(fileDir +os.sep+'ledStatus.txt', 'w') as f:
1632 f.write(json.dumps(leds, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n')
1633 print("LED status collected and stored in " + fileDir + os.sep+ "ledStatus.txt")
1634 output['fileLoc'] = fileDir+os.sep+'ledStatus.txt'
1635 except Exception as e:
1636 print("Failed to write LED status to file system.")
1637 errorInfo += "Error writing LED status to the file. Exception: {eInfo}\n".format(eInfo=e)
1638
1639 output['errors'] = errorInfo
1640 return output
1641
1642def csdSelShortList(host, args, session, fileDir):
1643 """
1644 Collects the BMC log entries, retrying if necessary
1645
1646 @param host: string, the hostname or IP address of the bmc
1647 @param args: contains additional arguments used by the collectServiceData sub command
1648 @param session: the active session to use
1649 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1650 @param fileDir: string representation of the path to use for putting files created
1651 """
1652 errorInfo = "===========SEL Short List =============\n"
1653 selsCollected = False
1654 output={}
1655 try:
1656 d = vars(args)
1657 d['json'] = False
1658 except Exception as e:
1659 errorInfo += "Failed to set the json flag to False \n Exception: {eInfo}\n".format(eInfo=e)
1660
1661 try:
1662 for i in range(3):
1663 sels = selPrint(host,args,session)
1664 if '----Active Alerts----' in sels or 'No log entries found' in sels or '----Historical Alerts----' in sels:
1665 selsCollected = True
1666 break
1667 else:
1668 errorInfo += sels + '\n'
1669 except Exception as e:
1670 errorInfo += "SEL short list collection exception: {eInfo}\n".format(eInfo=e)
1671
1672 if selsCollected:
1673 try:
1674 with open(fileDir +os.sep+'SELshortlist.txt', 'w') as f:
1675 f.write(sels)
1676 print("SEL short list collected and stored in " + fileDir + os.sep+ "SELshortlist.txt")
1677 output['fileLoc'] = fileDir+os.sep+'SELshortlist.txt'
1678 except Exception as e:
1679 print("Failed to write SEL short list to file system.")
1680 errorInfo += "Error writing SEL short list to the file. Exception: {eInfo}\n".format(eInfo=e)
1681
1682 output['errors'] = errorInfo
1683 return output
1684
1685def csdParsedSels(host, args, session, fileDir):
1686 """
1687 Collects the BMC log entries, retrying if necessary
1688
1689 @param host: string, the hostname or IP address of the bmc
1690 @param args: contains additional arguments used by the collectServiceData sub command
1691 @param session: the active session to use
1692 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1693 @param fileDir: string representation of the path to use for putting files created
1694 """
1695 errorInfo = "===========SEL Parsed List =============\n"
1696 selsCollected = False
1697 output={}
1698 try:
1699 d = vars(args)
1700 d['json'] = True
1701 d['fullEsel'] = True
1702 except Exception as e:
1703 errorInfo += "Failed to set the json flag to True \n Exception: {eInfo}\n".format(eInfo=e)
1704
1705 try:
1706 for i in range(3):
1707 parsedfullsels = json.loads(selPrint(host,args,session))
1708 if 'numAlerts' in parsedfullsels:
1709 selsCollected = True
1710 break
1711 else:
1712 errorInfo += parsedfullsels + '\n'
1713 except Exception as e:
1714 errorInfo += "Parsed full SELs collection exception: {eInfo}\n".format(eInfo=e)
1715
1716 if selsCollected:
1717 try:
1718 sortedSELs = sortSELs(parsedfullsels)
1719 with open(fileDir +os.sep+'parsedSELs.txt', 'w') as f:
1720 for log in sortedSELs[0]:
1721 esel = ""
1722 parsedfullsels[sortedSELs[1][str(log)]]['timestamp'] = datetime.datetime.fromtimestamp(int(parsedfullsels[sortedSELs[1][str(log)]]['timestamp']/1000)).strftime("%Y-%m-%d %H:%M:%S")
1723 if ('raweSEL' in parsedfullsels[sortedSELs[1][str(log)]] and args.devdebug):
1724 esel = parsedfullsels[sortedSELs[1][str(log)]]['raweSEL']
1725 del parsedfullsels[sortedSELs[1][str(log)]]['raweSEL']
1726 f.write(json.dumps(parsedfullsels[sortedSELs[1][str(log)]],sort_keys=True, indent=4, separators=(',', ': ')))
1727 if(args.devdebug and esel != ""):
1728 f.write(parseESEL(args, esel))
1729 print("Parsed SELs collected and stored in " + fileDir + os.sep+ "parsedSELs.txt")
1730 output['fileLoc'] = fileDir+os.sep+'parsedSELs.txt'
1731 except Exception as e:
1732 print("Failed to write fully parsed SELs to file system.")
1733 errorInfo += "Error writing fully parsed SELs to the file. Exception: {eInfo}\n".format(eInfo=e)
1734
1735 output['errors'] = errorInfo
1736 return output
1737
1738def csdFullEnumeration(host, args, session, fileDir):
1739 """
1740 Collects a full enumeration of /xyz/openbmc_project/, retrying if necessary
1741
1742 @param host: string, the hostname or IP address of the bmc
1743 @param args: contains additional arguments used by the collectServiceData sub command
1744 @param session: the active session to use
1745 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1746 @param fileDir: string representation of the path to use for putting files created
1747 """
1748 errorInfo = "===========BMC Full Enumeration =============\n"
1749 bmcFullCollected = False
1750 output={}
1751 try:
1752 d = vars(args)
1753 d['json'] = True
1754 except Exception as e:
1755 errorInfo += "Failed to set the json flag to False \n Exception: {eInfo}\n".format(eInfo=e)
1756 try:
1757 print("Attempting to get a full BMC enumeration")
1758 url="https://"+host+"/xyz/openbmc_project/enumerate"
1759 httpHeader = {'Content-Type':'application/json'}
1760 for i in range(3):
1761 try:
1762 bmcRes = session.get(url, headers=jsonHeader, verify=False, timeout=180)
1763 if bmcRes.status_code == 200:
1764 bmcFullCollected = True
1765 fullEnumeration = bmcRes.json()
1766 break
1767 else:
1768 errorInfo += bmcRes.text
1769 except(requests.exceptions.Timeout):
1770 errorInfo+=json.dumps( connectionErrHandler(args.json, "Timeout", None), sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n'
1771 except(requests.exceptions.ConnectionError) as err:
1772 errorInfo += json.dumps(connectionErrHandler(args.json, "ConnectionError", err), sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n'
1773 except Exception as e:
1774 errorInfo += "RAW BMC data collection exception: {eInfo}\n".format(eInfo=e)
1775
1776 if bmcFullCollected:
1777 try:
1778 with open(fileDir +os.sep+'bmcFullRaw.txt', 'w') as f:
1779 f.write(json.dumps(fullEnumeration, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n')
1780 print("RAW BMC data collected and saved into " + fileDir + os.sep+ "bmcFullRaw.txt")
1781 output['fileLoc'] = fileDir+os.sep+'bmcFullRaw.txt'
1782 except Exception as e:
1783 print("Failed to write RAW BMC data to file system.")
1784 errorInfo += "Error writing RAW BMC data collection to the file. Exception: {eInfo}\n".format(eInfo=e)
1785
1786 output['errors'] = errorInfo
1787 return output
1788
1789def csdCollectAllDumps(host, args, session, fileDir):
1790 """
1791 Collects all of the bmc dump files and stores them in fileDir
1792
1793 @param host: string, the hostname or IP address of the bmc
1794 @param args: contains additional arguments used by the collectServiceData sub command
1795 @param session: the active session to use
1796 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1797 @param fileDir: string representation of the path to use for putting files created
1798 """
1799
1800 errorInfo = "===========BMC Dump Collection =============\n"
1801 dumpListCollected = False
1802 output={}
1803 dumpList = {}
1804 try:
1805 d = vars(args)
1806 d['json'] = True
1807 d['dumpSaveLoc'] = fileDir
1808 except Exception as e:
1809 errorInfo += "Failed to set the json flag to True, or failed to set the dumpSave Location \n Exception: {eInfo}\n".format(eInfo=e)
1810
1811 print('Collecting bmc dump files')
1812
1813 try:
1814 for i in range(3):
1815 dumpResp = bmcDumpList(host, args, session)
1816 if 'message' in dumpResp:
1817 if 'ok' in dumpResp['message'].lower():
1818 dumpList = dumpResp['data']
1819 dumpListCollected = True
1820 break
1821 else:
1822 errorInfo += "Status was not OK when retrieving the list of dumps available. \n Response: \n{resp}\n".format(resp=dumpResp)
1823 else:
1824 errorInfo += "Invalid response received from the BMC while retrieving the list of dumps available.\n {resp}\n".format(resp=dumpResp)
1825 except Exception as e:
1826 errorInfo += "BMC dump list exception: {eInfo}\n".format(eInfo=e)
1827
1828 if dumpListCollected:
1829 output['fileList'] = []
1830 for dump in dumpList:
1831 try:
1832 if '/xyz/openbmc_project/dump/internal/manager' not in dump:
1833 d['dumpNum'] = int(dump.strip().split('/')[-1])
1834 print('retrieving dump file ' + str(d['dumpNum']))
1835 filename = bmcDumpRetrieve(host, args, session).split('Saved as ')[-1]
1836 output['fileList'].append(filename)
1837 except Exception as e:
1838 print("Unable to collect dump: {dumpInfo}".format(dumpInfo=dump))
1839 errorInfo += "Exception collecting a bmc dump {dumpInfo}\n {eInfo}\n".format(dumpInfo=dump, eInfo=e)
1840 output['errors'] = errorInfo
1841 return output
Justin Thalere412dc22018-01-12 16:28:24 -06001842
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001843def collectServiceData(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001844 """
1845 Collects all data needed for service from the BMC
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001846
Justin Thalere412dc22018-01-12 16:28:24 -06001847 @param host: string, the hostname or IP address of the bmc
1848 @param args: contains additional arguments used by the collectServiceData sub command
1849 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001850 @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 -06001851 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001852
Justin Thaler22b1bb52018-03-15 13:31:32 -05001853 global toolVersion
Justin Thaler666cf342019-01-23 14:44:27 -06001854 filelist = []
1855 errorInfo = ""
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001856
Justin Thaler666cf342019-01-23 14:44:27 -06001857 #get current number of bmc dumps and create a new bmc dump
1858 dumpInitdata = csdDumpInitiate(host, args, session)
1859 dumpcount = dumpInitdata['dumpcount']
1860 errorInfo += dumpInitdata['errors']
1861 #create the directory to put files
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001862 try:
1863 args.silent = True
Justin Thalercf1deae2018-05-25 19:35:21 -05001864 myDir = tempfile.gettempdir()+os.sep + host + "--" + datetime.datetime.now().strftime("%Y-%m-%d_%H.%M.%S")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001865 os.makedirs(myDir)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001866
Justin Thaler666cf342019-01-23 14:44:27 -06001867 except Exception as e:
1868 print('Unable to create the temporary directory for data collection. Ensure sufficient privileges to create temporary directory. Aborting.')
1869 return("Python exception: {eInfo}".format(eInfo = e))
1870
1871 #Collect Inventory
1872 inventoryData = csdInventory(host, args, session, myDir)
1873 if 'fileLoc' in inventoryData:
1874 filelist.append(inventoryData['fileLoc'])
1875 errorInfo += inventoryData['errors']
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001876 #Read all the sensor and OCC status
Justin Thaler666cf342019-01-23 14:44:27 -06001877 sensorData = csdSensors(host,args,session,myDir)
1878 if 'fileLoc' in sensorData:
1879 filelist.append(sensorData['fileLoc'])
1880 errorInfo += sensorData['errors']
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001881 #Collect all of the LEDs status
Justin Thaler666cf342019-01-23 14:44:27 -06001882 ledStatus = csdLEDs(host, args, session, myDir)
1883 if 'fileLoc' in ledStatus:
1884 filelist.append(ledStatus['fileLoc'])
1885 errorInfo += ledStatus['errors']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001886
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001887 #Collect the bmc logs
Justin Thaler666cf342019-01-23 14:44:27 -06001888 selShort = csdSelShortList(host, args, session, myDir)
1889 if 'fileLoc' in selShort:
1890 filelist.append(selShort['fileLoc'])
1891 errorInfo += selShort['errors']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001892
Justin Thaler666cf342019-01-23 14:44:27 -06001893 parsedSELs = csdParsedSels(host, args, session, myDir)
1894 if 'fileLoc' in parsedSELs:
1895 filelist.append(parsedSELs['fileLoc'])
1896 errorInfo += parsedSELs['errors']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001897
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001898 #collect RAW bmc enumeration
Justin Thaler666cf342019-01-23 14:44:27 -06001899 bmcRaw = csdFullEnumeration(host, args, session, myDir)
1900 if 'fileLoc' in bmcRaw:
1901 filelist.append(bmcRaw['fileLoc'])
1902 errorInfo += bmcRaw['errors']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001903
Justin Thaler666cf342019-01-23 14:44:27 -06001904 #wait for new dump to finish being created
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001905 waitingForNewDump = True
1906 count = 0;
Justin Thaler666cf342019-01-23 14:44:27 -06001907 print("Waiting for new BMC dump to finish being created.")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001908 while(waitingForNewDump):
Justin Thaler666cf342019-01-23 14:44:27 -06001909 dumpList = bmcDumpList(host, args, session)['data']
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001910 if len(dumpList) > dumpcount:
1911 waitingForNewDump = False
1912 break;
1913 elif(count>30):
1914 print("Timed out waiting for bmc to make a new dump file. Dump space may be full.")
1915 break;
1916 else:
1917 time.sleep(2)
1918 count += 1
Justin Thaler666cf342019-01-23 14:44:27 -06001919
1920 #collect all of the dump files
1921 getBMCDumps = csdCollectAllDumps(host, args, session, myDir)
1922 if 'fileList' in getBMCDumps:
1923 filelist+= getBMCDumps['fileList']
1924 errorInfo += getBMCDumps['errors']
1925
1926 #write the runtime errors to a file
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001927 try:
Justin Thaler666cf342019-01-23 14:44:27 -06001928 with open(myDir +os.sep+'openbmctoolRuntimeErrors.txt', 'w') as f:
1929 f.write(errorInfo)
1930 print("OpenBMC tool runtime errors collected and stored in " + myDir + os.sep+ "openbmctoolRuntimeErrors.txt")
1931 filelist.append(myDir+os.sep+'openbmctoolRuntimeErrors.txt')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001932 except Exception as e:
Justin Thaler666cf342019-01-23 14:44:27 -06001933 print("Failed to write OpenBMC tool runtime errors to file system.")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001934
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001935 #create the zip file
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001936 try:
Justin Thalercf1deae2018-05-25 19:35:21 -05001937 filename = myDir.split(tempfile.gettempdir()+os.sep)[-1] + "_" + toolVersion + '_openbmc.zip'
Justin Thaler666cf342019-01-23 14:44:27 -06001938 zf = zipfile.ZipFile(myDir+os.sep + filename, 'w')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001939 for myfile in filelist:
1940 zf.write(myfile, os.path.basename(myfile))
1941 zf.close()
Justin Thaler666cf342019-01-23 14:44:27 -06001942 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 -06001943 except Exception as e:
1944 print("Failed to create zip file with collected information")
Justin Thaler666cf342019-01-23 14:44:27 -06001945 return "data collection finished"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001946
Justin Thalere412dc22018-01-12 16:28:24 -06001947
1948def healthCheck(host, args, session):
1949 """
1950 runs a health check on the platform
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001951
Justin Thalere412dc22018-01-12 16:28:24 -06001952 @param host: string, the hostname or IP address of the bmc
1953 @param args: contains additional arguments used by the bmc sub command
1954 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001955 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1956 """
Justin Thalere412dc22018-01-12 16:28:24 -06001957 #check fru status and get as json to easily work through
1958 d = vars(args)
1959 useJson = d['json']
1960 d['json'] = True
1961 d['verbose']= False
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001962
Justin Thalere412dc22018-01-12 16:28:24 -06001963 frus = json.loads(fruStatus(host, args, session))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001964
Justin Thalere412dc22018-01-12 16:28:24 -06001965 hwStatus= "OK"
1966 performanceStatus = "OK"
1967 for key in frus:
1968 if frus[key]["Functional"] == "No" and frus[key]["Present"] == "Yes":
1969 hwStatus= "Degraded"
Justin Thalerfb9c81c2018-07-16 11:14:37 -05001970 if("power_supply" in key or "powersupply" in key):
1971 gpuCount =0
1972 for comp in frus:
Justin Thalere412dc22018-01-12 16:28:24 -06001973 if "gv100card" in comp:
1974 gpuCount +=1
1975 if gpuCount > 4:
1976 hwStatus = "Critical"
1977 performanceStatus="Degraded"
1978 break;
1979 elif("fan" in key):
1980 hwStatus = "Degraded"
1981 else:
1982 performanceStatus = "Degraded"
1983 if useJson:
1984 output = {"Hardware Status": hwStatus, "Performance": performanceStatus}
1985 output = json.dumps(output, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False)
1986 else:
1987 output = ("Hardware Status: " + hwStatus +
1988 "\nPerformance: " +performanceStatus )
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001989
1990
Justin Thalere412dc22018-01-12 16:28:24 -06001991 #SW407886: Clear the duplicate entries
1992 #collect the dups
1993 d['devdebug'] = False
1994 sels = json.loads(selPrint(host, args, session))
1995 logNums2Clr = []
1996 oldestLogNum={"logNum": "bogus" ,"key" : ""}
1997 count = 0
1998 if sels['numAlerts'] > 0:
1999 for key in sels:
2000 if "numAlerts" in key:
2001 continue
2002 try:
2003 if "slave@00:00/00:00:00:06/sbefifo1-dev0/occ1-dev0" in sels[key]['Message']:
2004 count += 1
2005 if count > 1:
2006 #preserve first occurrence
2007 if sels[key]['timestamp'] < sels[oldestLogNum['key']]['timestamp']:
2008 oldestLogNum['key']=key
2009 oldestLogNum['logNum'] = sels[key]['logNum']
2010 else:
2011 oldestLogNum['key']=key
2012 oldestLogNum['logNum'] = sels[key]['logNum']
2013 logNums2Clr.append(sels[key]['logNum'])
2014 except KeyError:
2015 continue
2016 if(count >0):
2017 logNums2Clr.remove(oldestLogNum['logNum'])
2018 #delete the dups
2019 if count >1:
Justin Thalere412dc22018-01-12 16:28:24 -06002020 data = "{\"data\": [] }"
2021 for logNum in logNums2Clr:
2022 url = "https://"+ host+ "/xyz/openbmc_project/logging/entry/"+logNum+"/action/Delete"
2023 try:
Justin Thaler27197622019-01-23 14:42:11 -06002024 session.post(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002025 except(requests.exceptions.Timeout):
2026 deleteFailed = True
2027 except(requests.exceptions.ConnectionError) as err:
2028 deleteFailed = True
2029 #End of defect resolve code
2030 d['json'] = useJson
2031 return output
2032
2033
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002034
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002035def bmc(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06002036 """
2037 handles various bmc level commands, currently bmc rebooting
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002038
Justin Thalere412dc22018-01-12 16:28:24 -06002039 @param host: string, the hostname or IP address of the bmc
2040 @param args: contains additional arguments used by the bmc sub command
2041 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002042 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
2043 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002044 if(args.type is not None):
2045 return bmcReset(host, args, session)
Justin Thalere412dc22018-01-12 16:28:24 -06002046 if(args.info):
2047 return "Not implemented at this time"
2048
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002049
Justin Thalere412dc22018-01-12 16:28:24 -06002050
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002051def bmcReset(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06002052 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002053 controls resetting the bmc. warm reset reboots the bmc, cold reset removes the configuration and reboots.
2054
Justin Thalere412dc22018-01-12 16:28:24 -06002055 @param host: string, the hostname or IP address of the bmc
2056 @param args: contains additional arguments used by the bmcReset sub command
2057 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002058 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
2059 """
Justin Thaler22b1bb52018-03-15 13:31:32 -05002060 if checkFWactivation(host, args, session):
2061 return ("BMC reset control disabled during firmware activation")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002062 if(args.type == "warm"):
2063 print("\nAttempting to reboot the BMC...:")
2064 url="https://"+host+"/xyz/openbmc_project/state/bmc0/attr/RequestedBMCTransition"
Justin Thalere412dc22018-01-12 16:28:24 -06002065 data = '{"data":"xyz.openbmc_project.State.BMC.Transition.Reboot"}'
Justin Thaler27197622019-01-23 14:42:11 -06002066 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002067 return res.text
2068 elif(args.type =="cold"):
Justin Thalere412dc22018-01-12 16:28:24 -06002069 print("\nAttempting to reboot the BMC...:")
2070 url="https://"+host+"/xyz/openbmc_project/state/bmc0/attr/RequestedBMCTransition"
Justin Thalere412dc22018-01-12 16:28:24 -06002071 data = '{"data":"xyz.openbmc_project.State.BMC.Transition.Reboot"}'
Justin Thaler27197622019-01-23 14:42:11 -06002072 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002073 return res.text
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002074 else:
2075 return "invalid command"
Justin Thalere412dc22018-01-12 16:28:24 -06002076
2077def gardClear(host, args, session):
2078 """
2079 clears the gard records from the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002080
Justin Thalere412dc22018-01-12 16:28:24 -06002081 @param host: string, the hostname or IP address of the bmc
2082 @param args: contains additional arguments used by the gardClear sub command
2083 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002084 """
Justin Thalere412dc22018-01-12 16:28:24 -06002085 url="https://"+host+"/org/open_power/control/gard/action/Reset"
Justin Thalere412dc22018-01-12 16:28:24 -06002086 data = '{"data":[]}'
2087 try:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002088
Justin Thaler27197622019-01-23 14:42:11 -06002089 res = session.post(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002090 if res.status_code == 404:
2091 return "Command not supported by this firmware version"
2092 else:
2093 return res.text
2094 except(requests.exceptions.Timeout):
2095 return connectionErrHandler(args.json, "Timeout", None)
2096 except(requests.exceptions.ConnectionError) as err:
2097 return connectionErrHandler(args.json, "ConnectionError", err)
2098
2099def activateFWImage(host, args, session):
2100 """
2101 activates a firmware image on the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002102
Justin Thalere412dc22018-01-12 16:28:24 -06002103 @param host: string, the hostname or IP address of the bmc
2104 @param args: contains additional arguments used by the fwflash sub command
2105 @param session: the active session to use
2106 @param fwID: the unique ID of the fw image to activate
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002107 """
Justin Thalere412dc22018-01-12 16:28:24 -06002108 fwID = args.imageID
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002109
Justin Thalere412dc22018-01-12 16:28:24 -06002110 #determine the existing versions
Justin Thalere412dc22018-01-12 16:28:24 -06002111 url="https://"+host+"/xyz/openbmc_project/software/enumerate"
2112 try:
Justin Thaler27197622019-01-23 14:42:11 -06002113 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002114 except(requests.exceptions.Timeout):
2115 return connectionErrHandler(args.json, "Timeout", None)
2116 except(requests.exceptions.ConnectionError) as err:
2117 return connectionErrHandler(args.json, "ConnectionError", err)
2118 existingSoftware = json.loads(resp.text)['data']
2119 altVersionID = ''
2120 versionType = ''
2121 imageKey = '/xyz/openbmc_project/software/'+fwID
2122 if imageKey in existingSoftware:
2123 versionType = existingSoftware[imageKey]['Purpose']
2124 for key in existingSoftware:
2125 if imageKey == key:
2126 continue
2127 if 'Purpose' in existingSoftware[key]:
2128 if versionType == existingSoftware[key]['Purpose']:
2129 altVersionID = key.split('/')[-1]
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002130
2131
2132
2133
Justin Thalere412dc22018-01-12 16:28:24 -06002134 url="https://"+host+"/xyz/openbmc_project/software/"+ fwID + "/attr/Priority"
2135 url1="https://"+host+"/xyz/openbmc_project/software/"+ altVersionID + "/attr/Priority"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002136 data = "{\"data\": 0}"
Justin Thalere412dc22018-01-12 16:28:24 -06002137 data1 = "{\"data\": 1 }"
2138 try:
Justin Thaler27197622019-01-23 14:42:11 -06002139 resp = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
2140 resp1 = session.put(url1, headers=jsonHeader, data=data1, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002141 except(requests.exceptions.Timeout):
2142 return connectionErrHandler(args.json, "Timeout", None)
2143 except(requests.exceptions.ConnectionError) as err:
2144 return connectionErrHandler(args.json, "ConnectionError", err)
2145 if(not args.json):
2146 if resp.status_code == 200 and resp1.status_code == 200:
Justin Thaler22b1bb52018-03-15 13:31:32 -05002147 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 -06002148 else:
2149 return "Firmware activation failed."
2150 else:
2151 return resp.text + resp1.text
Justin Thaler22b1bb52018-03-15 13:31:32 -05002152
2153def activateStatus(host, args, session):
2154 if checkFWactivation(host, args, session):
2155 return("Firmware is currently being activated. Do not reboot the BMC or start the Host OS")
2156 else:
2157 return("No firmware activations are pending")
2158
2159def extractFWimage(path, imageType):
2160 """
2161 extracts the bmc image and returns information about the package
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002162
Justin Thaler22b1bb52018-03-15 13:31:32 -05002163 @param path: the path and file name of the firmware image
2164 @param imageType: The type of image the user is trying to flash. Host or BMC
2165 @return: the image id associated with the package. returns an empty string on error.
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002166 """
Justin Thaler22b1bb52018-03-15 13:31:32 -05002167 f = tempfile.TemporaryFile()
2168 tmpDir = tempfile.gettempdir()
2169 newImageID = ""
2170 if os.path.exists(path):
2171 try:
2172 imageFile = tarfile.open(path,'r')
2173 contents = imageFile.getmembers()
2174 for tf in contents:
2175 if 'MANIFEST' in tf.name:
2176 imageFile.extract(tf.name, path=tmpDir)
2177 with open(tempfile.gettempdir() +os.sep+ tf.name, 'r') as imageInfo:
2178 for line in imageInfo:
2179 if 'purpose' in line:
2180 purpose = line.split('=')[1]
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002181 if imageType not in purpose.split('.')[-1]:
Justin Thaler22b1bb52018-03-15 13:31:32 -05002182 print('The specified image is not for ' + imageType)
2183 print('Please try again with the image for ' + imageType)
2184 return ""
2185 if 'version' == line.split('=')[0]:
2186 version = line.split('=')[1].strip().encode('utf-8')
2187 m = hashlib.sha512()
2188 m.update(version)
2189 newImageID = m.hexdigest()[:8]
2190 break
2191 try:
2192 os.remove(tempfile.gettempdir() +os.sep+ tf.name)
2193 except OSError:
2194 pass
2195 return newImageID
2196 except tarfile.ExtractError as e:
2197 print('Unable to extract information from the firmware file.')
2198 print('Ensure you have write access to the directory: ' + tmpDir)
2199 return newImageID
2200 except tarfile.TarError as e:
2201 print('This is not a valid firmware file.')
2202 return newImageID
2203 print("This is not a valid firmware file.")
2204 return newImageID
2205 else:
2206 print('The filename and path provided are not valid.')
2207 return newImageID
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002208
Justin Thaler22b1bb52018-03-15 13:31:32 -05002209def getAllFWImageIDs(fwInvDict):
2210 """
2211 gets a list of all the firmware image IDs
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002212
Justin Thaler22b1bb52018-03-15 13:31:32 -05002213 @param fwInvDict: the dictionary to search for FW image IDs
2214 @return: list containing string representation of the found image ids
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002215 """
Justin Thaler22b1bb52018-03-15 13:31:32 -05002216 idList = []
2217 for key in fwInvDict:
2218 if 'Version' in fwInvDict[key]:
2219 idList.append(key.split('/')[-1])
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002220 return idList
2221
Justin Thalere412dc22018-01-12 16:28:24 -06002222def fwFlash(host, args, session):
2223 """
2224 updates the bmc firmware and pnor firmware
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002225
Justin Thalere412dc22018-01-12 16:28:24 -06002226 @param host: string, the hostname or IP address of the bmc
2227 @param args: contains additional arguments used by the fwflash sub command
2228 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002229 """
Justin Thaler22b1bb52018-03-15 13:31:32 -05002230 d = vars(args)
Justin Thalere412dc22018-01-12 16:28:24 -06002231 if(args.type == 'bmc'):
2232 purp = 'BMC'
2233 else:
2234 purp = 'Host'
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002235
2236 #check power state of the machine. No concurrent FW updates allowed
Justin Thaler22b1bb52018-03-15 13:31:32 -05002237 d['powcmd'] = 'status'
2238 powerstate = chassisPower(host, args, session)
2239 if 'Chassis Power State: On' in powerstate:
2240 return("Aborting firmware update. Host is powered on. Please turn off the host and try again.")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002241
Justin Thaler22b1bb52018-03-15 13:31:32 -05002242 #determine the existing images on the bmc
Justin Thalere412dc22018-01-12 16:28:24 -06002243 url="https://"+host+"/xyz/openbmc_project/software/enumerate"
2244 try:
Justin Thaler27197622019-01-23 14:42:11 -06002245 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002246 except(requests.exceptions.Timeout):
2247 return connectionErrHandler(args.json, "Timeout", None)
2248 except(requests.exceptions.ConnectionError) as err:
2249 return connectionErrHandler(args.json, "ConnectionError", err)
2250 oldsoftware = json.loads(resp.text)['data']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002251
Justin Thaler22b1bb52018-03-15 13:31:32 -05002252 #Extract the tar and get information from the manifest file
2253 newversionID = extractFWimage(args.fileloc, purp)
2254 if newversionID == "":
2255 return "Unable to verify FW image."
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002256
2257
Justin Thaler22b1bb52018-03-15 13:31:32 -05002258 #check if the new image is already on the bmc
2259 if newversionID not in getAllFWImageIDs(oldsoftware):
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002260
Justin Thaler22b1bb52018-03-15 13:31:32 -05002261 #upload the file
2262 httpHeader = {'Content-Type':'application/octet-stream'}
Matt Spinler220c3c42019-01-04 15:09:29 -06002263 httpHeader.update(xAuthHeader)
Justin Thaler22b1bb52018-03-15 13:31:32 -05002264 url="https://"+host+"/upload/image"
2265 data=open(args.fileloc,'rb').read()
2266 print("Uploading file to BMC")
Justin Thalere412dc22018-01-12 16:28:24 -06002267 try:
Justin Thaler22b1bb52018-03-15 13:31:32 -05002268 resp = session.post(url, headers=httpHeader, data=data, verify=False)
Justin Thalere412dc22018-01-12 16:28:24 -06002269 except(requests.exceptions.Timeout):
2270 return connectionErrHandler(args.json, "Timeout", None)
2271 except(requests.exceptions.ConnectionError) as err:
2272 return connectionErrHandler(args.json, "ConnectionError", err)
Justin Thaler22b1bb52018-03-15 13:31:32 -05002273 if resp.status_code != 200:
2274 return "Failed to upload the file to the bmc"
Justin Thalere412dc22018-01-12 16:28:24 -06002275 else:
Justin Thaler22b1bb52018-03-15 13:31:32 -05002276 print("Upload complete.")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002277
Justin Thaler22b1bb52018-03-15 13:31:32 -05002278 #verify bmc processed the image
2279 software ={}
2280 for i in range(0, 5):
Justin Thaler22b1bb52018-03-15 13:31:32 -05002281 url="https://"+host+"/xyz/openbmc_project/software/enumerate"
2282 try:
Justin Thaler27197622019-01-23 14:42:11 -06002283 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thaler22b1bb52018-03-15 13:31:32 -05002284 except(requests.exceptions.Timeout):
2285 return connectionErrHandler(args.json, "Timeout", None)
2286 except(requests.exceptions.ConnectionError) as err:
2287 return connectionErrHandler(args.json, "ConnectionError", err)
2288 software = json.loads(resp.text)['data']
2289 #check if bmc is done processing the new image
2290 if (newversionID in getAllFWImageIDs(software)):
Justin Thalere412dc22018-01-12 16:28:24 -06002291 break
Justin Thaler22b1bb52018-03-15 13:31:32 -05002292 else:
2293 time.sleep(15)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002294
Justin Thaler22b1bb52018-03-15 13:31:32 -05002295 #activate the new image
2296 print("Activating new image: "+newversionID)
2297 url="https://"+host+"/xyz/openbmc_project/software/"+ newversionID + "/attr/RequestedActivation"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002298 data = '{"data":"xyz.openbmc_project.Software.Activation.RequestedActivations.Active"}'
Justin Thaler22b1bb52018-03-15 13:31:32 -05002299 try:
Justin Thaler27197622019-01-23 14:42:11 -06002300 resp = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thaler22b1bb52018-03-15 13:31:32 -05002301 except(requests.exceptions.Timeout):
2302 return connectionErrHandler(args.json, "Timeout", None)
2303 except(requests.exceptions.ConnectionError) as err:
2304 return connectionErrHandler(args.json, "ConnectionError", err)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002305
Justin Thaler22b1bb52018-03-15 13:31:32 -05002306 #wait for the activation to complete, timeout after ~1 hour
2307 i=0
2308 while i < 360:
2309 url="https://"+host+"/xyz/openbmc_project/software/"+ newversionID
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002310 data = '{"data":"xyz.openbmc_project.Software.Activation.RequestedActivations.Active"}'
Justin Thaler22b1bb52018-03-15 13:31:32 -05002311 try:
Justin Thaler27197622019-01-23 14:42:11 -06002312 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thaler22b1bb52018-03-15 13:31:32 -05002313 except(requests.exceptions.Timeout):
2314 return connectionErrHandler(args.json, "Timeout", None)
2315 except(requests.exceptions.ConnectionError) as err:
2316 return connectionErrHandler(args.json, "ConnectionError", err)
2317 fwInfo = json.loads(resp.text)['data']
2318 if 'Activating' not in fwInfo['Activation'] and 'Activating' not in fwInfo['RequestedActivation']:
2319 print('')
2320 break
2321 else:
2322 sys.stdout.write('.')
2323 sys.stdout.flush()
2324 time.sleep(10) #check every 10 seconds
2325 return "Firmware flash and activation completed. Please reboot the bmc and then boot the host OS for the changes to take effect. "
2326 else:
2327 print("This image has been found on the bmc. Activating image: " + newversionID)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002328
Justin Thaler22b1bb52018-03-15 13:31:32 -05002329 d['imageID'] = newversionID
2330 return activateFWImage(host, args, session)
Justin Thalere412dc22018-01-12 16:28:24 -06002331
Justin Thaler3d71d402018-07-24 14:35:39 -05002332def getFWInventoryAttributes(rawFWInvItem, ID):
2333 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002334 gets and lists all of the firmware in the system.
2335
Justin Thaler3d71d402018-07-24 14:35:39 -05002336 @return: returns a dictionary containing the image attributes
2337 """
2338 reqActivation = rawFWInvItem["RequestedActivation"].split('.')[-1]
2339 pendingActivation = ""
2340 if reqActivation == "None":
2341 pendingActivation = "No"
2342 else:
2343 pendingActivation = "Yes"
2344 firmwareAttr = {ID: {
2345 "Purpose": rawFWInvItem["Purpose"].split('.')[-1],
2346 "Version": rawFWInvItem["Version"],
2347 "RequestedActivation": pendingActivation,
2348 "ID": ID}}
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002349
Justin Thaler3d71d402018-07-24 14:35:39 -05002350 if "ExtendedVersion" in rawFWInvItem:
2351 firmwareAttr[ID]['ExtendedVersion'] = rawFWInvItem['ExtendedVersion'].split(',')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002352 else:
Justin Thaler3d71d402018-07-24 14:35:39 -05002353 firmwareAttr[ID]['ExtendedVersion'] = ""
2354 return firmwareAttr
2355
2356def parseFWdata(firmwareDict):
2357 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002358 creates a dictionary with parsed firmware data
2359
Justin Thaler3d71d402018-07-24 14:35:39 -05002360 @return: returns a dictionary containing the image attributes
2361 """
2362 firmwareInfoDict = {"Functional": {}, "Activated":{}, "NeedsActivated":{}}
2363 for key in firmwareDict['data']:
2364 #check for valid endpoint
2365 if "Purpose" in firmwareDict['data'][key]:
2366 id = key.split('/')[-1]
2367 if firmwareDict['data'][key]['Activation'].split('.')[-1] == "Active":
2368 fwActivated = True
2369 else:
2370 fwActivated = False
Justin Thalercb68e062019-03-26 19:04:52 -05002371 if 'Priority' in firmwareDict['data'][key]:
2372 if firmwareDict['data'][key]['Priority'] == 0:
2373 firmwareInfoDict['Functional'].update(getFWInventoryAttributes(firmwareDict['data'][key], id))
2374 elif firmwareDict['data'][key]['Priority'] >= 0 and fwActivated:
2375 firmwareInfoDict['Activated'].update(getFWInventoryAttributes(firmwareDict['data'][key], id))
2376 else:
2377 firmwareInfoDict['NeedsActivated'].update(getFWInventoryAttributes(firmwareDict['data'][key], id))
Justin Thaler3d71d402018-07-24 14:35:39 -05002378 else:
Justin Thalercb68e062019-03-26 19:04:52 -05002379 firmwareInfoDict['NeedsActivated'].update(getFWInventoryAttributes(firmwareDict['data'][key], id))
Justin Thaler3d71d402018-07-24 14:35:39 -05002380 emptySections = []
2381 for key in firmwareInfoDict:
2382 if len(firmwareInfoDict[key])<=0:
2383 emptySections.append(key)
2384 for key in emptySections:
2385 del firmwareInfoDict[key]
2386 return firmwareInfoDict
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002387
Justin Thaler3d71d402018-07-24 14:35:39 -05002388def displayFWInvenory(firmwareInfoDict, args):
2389 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002390 gets and lists all of the firmware in the system.
2391
Justin Thaler3d71d402018-07-24 14:35:39 -05002392 @return: returns a string containing all of the firmware information
2393 """
2394 output = ""
2395 if not args.json:
2396 for key in firmwareInfoDict:
2397 for subkey in firmwareInfoDict[key]:
2398 firmwareInfoDict[key][subkey]['ExtendedVersion'] = str(firmwareInfoDict[key][subkey]['ExtendedVersion'])
2399 if not args.verbose:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002400 output = "---Running Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002401 colNames = ["Purpose", "Version", "ID"]
2402 keylist = ["Purpose", "Version", "ID"]
2403 output += tableDisplay(keylist, colNames, firmwareInfoDict["Functional"])
2404 if "Activated" in firmwareInfoDict:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002405 output += "\n---Available Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002406 output += tableDisplay(keylist, colNames, firmwareInfoDict["Activated"])
2407 if "NeedsActivated" in firmwareInfoDict:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002408 output += "\n---Needs Activated Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002409 output += tableDisplay(keylist, colNames, firmwareInfoDict["NeedsActivated"])
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002410
Justin Thaler3d71d402018-07-24 14:35:39 -05002411 else:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002412 output = "---Running Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002413 colNames = ["Purpose", "Version", "ID", "Pending Activation", "Extended Version"]
2414 keylist = ["Purpose", "Version", "ID", "RequestedActivation", "ExtendedVersion"]
2415 output += tableDisplay(keylist, colNames, firmwareInfoDict["Functional"])
2416 if "Activated" in firmwareInfoDict:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002417 output += "\n---Available Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002418 output += tableDisplay(keylist, colNames, firmwareInfoDict["Activated"])
2419 if "NeedsActivated" in firmwareInfoDict:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002420 output += "\n---Needs Activated Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002421 output += tableDisplay(keylist, colNames, firmwareInfoDict["NeedsActivated"])
2422 return output
2423 else:
2424 return str(json.dumps(firmwareInfoDict, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False))
2425
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002426def firmwareList(host, args, session):
Justin Thaler3d71d402018-07-24 14:35:39 -05002427 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002428 gets and lists all of the firmware in the system.
2429
Justin Thaler3d71d402018-07-24 14:35:39 -05002430 @return: returns a string containing all of the firmware information
2431 """
Justin Thaler3d71d402018-07-24 14:35:39 -05002432 url="https://{hostname}/xyz/openbmc_project/software/enumerate".format(hostname=host)
2433 try:
Justin Thaler27197622019-01-23 14:42:11 -06002434 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thaler3d71d402018-07-24 14:35:39 -05002435 except(requests.exceptions.Timeout):
2436 return(connectionErrHandler(args.json, "Timeout", None))
2437 firmwareDict = json.loads(res.text)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002438
Justin Thaler3d71d402018-07-24 14:35:39 -05002439 #sort the received information
2440 firmwareInfoDict = parseFWdata(firmwareDict)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002441
Justin Thaler3d71d402018-07-24 14:35:39 -05002442 #display the information
2443 return displayFWInvenory(firmwareInfoDict, args)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002444
2445
Adriana Kobylak5af2fad2018-11-08 12:33:43 -06002446def deleteFWVersion(host, args, session):
2447 """
2448 deletes a firmware version on the BMC
2449
2450 @param host: string, the hostname or IP address of the BMC
2451 @param args: contains additional arguments used by the fwflash sub command
2452 @param session: the active session to use
2453 @param fwID: the unique ID of the fw version to delete
2454 """
2455 fwID = args.versionID
2456
2457 print("Deleting version: "+fwID)
2458 url="https://"+host+"/xyz/openbmc_project/software/"+ fwID + "/action/Delete"
Adriana Kobylak5af2fad2018-11-08 12:33:43 -06002459 data = "{\"data\": [] }"
2460
2461 try:
Justin Thaler27197622019-01-23 14:42:11 -06002462 res = session.post(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Adriana Kobylak5af2fad2018-11-08 12:33:43 -06002463 except(requests.exceptions.Timeout):
2464 return(connectionErrHandler(args.json, "Timeout", None))
2465 if res.status_code == 200:
2466 return ('The firmware version has been deleted')
2467 else:
2468 return ('Unable to delete the specified firmware version')
2469
2470
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05002471def restLogging(host, args, session):
2472 """
2473 Called by the logging function. Turns REST API logging on/off.
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002474
Deepak Kodihalli22d4df02018-09-18 06:52:43 -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 Kodihalli22d4df02018-09-18 06:52:43 -05002479 """
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05002480 url="https://"+host+"/xyz/openbmc_project/logging/rest_api_logs/attr/Enabled"
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05002481
2482 if(args.rest_logging == 'on'):
2483 data = '{"data": 1}'
2484 elif(args.rest_logging == 'off'):
2485 data = '{"data": 0}'
2486 else:
2487 return "Invalid logging rest_api command"
2488
2489 try:
Justin Thaler27197622019-01-23 14:42:11 -06002490 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05002491 except(requests.exceptions.Timeout):
2492 return(connectionErrHandler(args.json, "Timeout", None))
2493 return res.text
2494
2495
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002496def remoteLogging(host, args, session):
2497 """
2498 Called by the logging function. View config information for/disable 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:
2509 if(args.remote_logging == 'view'):
Justin Thaler27197622019-01-23 14:42:11 -06002510 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002511 elif(args.remote_logging == 'disable'):
Justin Thaler27197622019-01-23 14:42:11 -06002512 res = session.put(url + '/attr/Port', headers=jsonHeader, json = {"data": 0}, verify=False, timeout=baseTimeout)
2513 res = session.put(url + '/attr/Address', headers=jsonHeader, json = {"data": ""}, verify=False, timeout=baseTimeout)
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002514 else:
2515 return "Invalid logging remote_logging command"
2516 except(requests.exceptions.Timeout):
2517 return(connectionErrHandler(args.json, "Timeout", None))
2518 return res.text
2519
2520
2521def remoteLoggingConfig(host, args, session):
2522 """
2523 Called by the logging function. Configures remote logging (rsyslog).
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002524
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002525 @param host: string, the hostname or IP address of the bmc
2526 @param args: contains additional arguments used by the logging sub command
2527 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002528 @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 -05002529 """
2530
2531 url="https://"+host+"/xyz/openbmc_project/logging/config/remote"
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002532
2533 try:
Justin Thaler27197622019-01-23 14:42:11 -06002534 res = session.put(url + '/attr/Port', headers=jsonHeader, json = {"data": args.port}, verify=False, timeout=baseTimeout)
2535 res = session.put(url + '/attr/Address', headers=jsonHeader, json = {"data": args.address}, verify=False, timeout=baseTimeout)
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002536 except(requests.exceptions.Timeout):
2537 return(connectionErrHandler(args.json, "Timeout", None))
2538 return res.text
2539
Marri Devender Rao82590dc2019-06-06 04:54:22 -05002540def redfishSupportPresent(host, session):
2541 url = "https://" + host + "/redfish/v1"
2542 try:
2543 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
2544 except(requests.exceptions.Timeout):
2545 return False
2546 except(requests.exceptions.ConnectionError) as err:
2547 return False
2548 if resp.status_code != 200:
2549 return False
2550 else:
2551 return True
Ratan Gupta9166cd22018-10-01 18:09:40 +05302552
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002553def certificateUpdate(host, args, session):
2554 """
2555 Called by certificate management function. update server/client/authority certificates
2556 Example:
2557 certificate update server https -f cert.pem
2558 certificate update authority ldap -f Root-CA.pem
2559 certificate update client ldap -f cert.pem
2560 @param host: string, the hostname or IP address of the bmc
2561 @param args: contains additional arguments used by the certificate update sub command
2562 @param session: the active session to use
2563 """
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002564 httpHeader = {'Content-Type': 'application/octet-stream'}
Matt Spinler220c3c42019-01-04 15:09:29 -06002565 httpHeader.update(xAuthHeader)
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002566 data = open(args.fileloc, 'rb').read()
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002567 try:
Marri Devender Rao82590dc2019-06-06 04:54:22 -05002568 if redfishSupportPresent(host, session):
Marri Devender Rao62db08a2019-08-22 03:16:02 -05002569 if(args.type.lower() == 'server' and args.service.lower() != "https"):
2570 return "Invalid service type"
2571 if(args.type.lower() == 'client' and args.service.lower() != "ldap"):
2572 return "Invalid service type"
2573 if(args.type.lower() == 'authority' and args.service.lower() != "ldap"):
2574 return "Invalid service type"
Marri Devender Rao82590dc2019-06-06 04:54:22 -05002575 url = "";
2576 if(args.type.lower() == 'server'):
2577 url = "https://" + host + \
2578 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"
2579 elif(args.type.lower() == 'client'):
2580 url = "https://" + host + \
2581 "/redfish/v1/AccountService/LDAP/Certificates"
2582 elif(args.type.lower() == 'authority'):
2583 url = "https://" + host + \
2584 "/redfish/v1/Managers/bmc/Truststore/Certificates"
2585 else:
2586 return "Unsupported certificate type"
2587 resp = session.post(url, headers=httpHeader, data=data,
2588 verify=False)
2589 else:
2590 url = "https://" + host + "/xyz/openbmc_project/certs/" + \
2591 args.type.lower() + "/" + args.service.lower()
2592 resp = session.put(url, headers=httpHeader, data=data, verify=False)
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002593 except(requests.exceptions.Timeout):
2594 return(connectionErrHandler(args.json, "Timeout", None))
2595 except(requests.exceptions.ConnectionError) as err:
2596 return connectionErrHandler(args.json, "ConnectionError", err)
2597 if resp.status_code != 200:
2598 print(resp.text)
2599 return "Failed to update the certificate"
2600 else:
Marri Devender Rao82590dc2019-06-06 04:54:22 -05002601 print("Update complete.")
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002602
2603def certificateDelete(host, args, session):
2604 """
2605 Called by certificate management function to delete certificate
2606 Example:
2607 certificate delete server https
2608 certificate delete authority ldap
2609 certificate delete client ldap
2610 @param host: string, the hostname or IP address of the bmc
2611 @param args: contains additional arguments used by the certificate delete sub command
2612 @param session: the active session to use
2613 """
Marri Devender Rao77e78682019-07-17 03:18:35 -05002614 if redfishSupportPresent(host, session):
2615 return "Not supported, please use certificate replace instead";
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002616 httpHeader = {'Content-Type': 'multipart/form-data'}
Matt Spinler220c3c42019-01-04 15:09:29 -06002617 httpHeader.update(xAuthHeader)
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002618 url = "https://" + host + "/xyz/openbmc_project/certs/" + args.type.lower() + "/" + args.service.lower()
2619 print("Deleting certificate url=" + url)
2620 try:
2621 resp = session.delete(url, headers=httpHeader)
2622 except(requests.exceptions.Timeout):
2623 return(connectionErrHandler(args.json, "Timeout", None))
2624 except(requests.exceptions.ConnectionError) as err:
2625 return connectionErrHandler(args.json, "ConnectionError", err)
2626 if resp.status_code != 200:
2627 print(resp.text)
2628 return "Failed to delete the certificate"
2629 else:
Marri Devender Rao77e78682019-07-17 03:18:35 -05002630 print("Delete complete.")
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002631
Marri Devender Raodfe81ad2019-07-01 05:38:09 -05002632def certificateReplace(host, args, session):
2633 """
2634 Called by certificate management function. replace server/client/
2635 authority certificates
2636 Example:
2637 certificate replace server https -f cert.pem
2638 certificate replace authority ldap -f Root-CA.pem
2639 certificate replace client ldap -f cert.pem
2640 @param host: string, the hostname or IP address of the bmc
2641 @param args: contains additional arguments used by the certificate
2642 replace sub command
2643 @param session: the active session to use
2644 """
2645 cert = open(args.fileloc, 'rb').read()
2646 try:
2647 if redfishSupportPresent(host, session):
2648 httpHeader = {'Content-Type': 'application/json'}
2649 httpHeader.update(xAuthHeader)
2650 url = "";
Marri Devender Rao62db08a2019-08-22 03:16:02 -05002651 if(args.type.lower() == 'server' and args.service.lower() != "https"):
2652 return "Invalid service type"
2653 if(args.type.lower() == 'client' and args.service.lower() != "ldap"):
2654 return "Invalid service type"
2655 if(args.type.lower() == 'authority' and args.service.lower() != "ldap"):
2656 return "Invalid service type"
Marri Devender Raodfe81ad2019-07-01 05:38:09 -05002657 if(args.type.lower() == 'server'):
2658 url = "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/1"
2659 elif(args.type.lower() == 'client'):
2660 url = "/redfish/v1/AccountService/LDAP/Certificates/1"
2661 elif(args.type.lower() == 'authority'):
2662 url = "/redfish/v1/Managers/bmc/Truststore/Certificates/1"
2663 replaceUrl = "https://" + host + \
2664 "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate"
2665 data ={"CertificateUri":{"@odata.id":url}, "CertificateType":"PEM",
2666 "CertificateString":cert}
2667 resp = session.post(replaceUrl, headers=httpHeader, json=data, verify=False)
2668 else:
2669 httpHeader = {'Content-Type': 'application/octet-stream'}
2670 httpHeader.update(xAuthHeader)
2671 url = "https://" + host + "/xyz/openbmc_project/certs/" + \
2672 args.type.lower() + "/" + args.service.lower()
2673 resp = session.delete(url, headers=httpHeader)
2674 resp = session.put(url, headers=httpHeader, data=cert, verify=False)
2675 except(requests.exceptions.Timeout):
2676 return(connectionErrHandler(args.json, "Timeout", None))
2677 except(requests.exceptions.ConnectionError) as err:
2678 return connectionErrHandler(args.json, "ConnectionError", err)
2679 if resp.status_code != 200:
2680 print(resp.text)
2681 return "Failed to replace the certificate"
2682 else:
2683 print("Replace complete.")
2684 return resp.text
2685
Marri Devender Rao34646402019-07-01 05:46:03 -05002686def certificateDisplay(host, args, session):
2687 """
2688 Called by certificate management function. display server/client/
2689 authority certificates
2690 Example:
2691 certificate display server
2692 certificate display authority
2693 certificate display client
2694 @param host: string, the hostname or IP address of the bmc
2695 @param args: contains additional arguments used by the certificate
2696 display 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 if(args.type.lower() == 'server'):
2705 url = "https://" + host + \
2706 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/1"
2707 elif(args.type.lower() == 'client'):
2708 url = "https://" + host + \
2709 "/redfish/v1/AccountService/LDAP/Certificates/1"
2710 elif(args.type.lower() == 'authority'):
2711 url = "https://" + host + \
2712 "/redfish/v1/Managers/bmc/Truststore/Certificates/1"
2713 try:
2714 resp = session.get(url, headers=httpHeader, verify=False)
2715 except(requests.exceptions.Timeout):
2716 return(connectionErrHandler(args.json, "Timeout", None))
2717 except(requests.exceptions.ConnectionError) as err:
2718 return connectionErrHandler(args.json, "ConnectionError", err)
2719 if resp.status_code != 200:
2720 print(resp.text)
2721 return "Failed to display the certificate"
2722 else:
2723 print("Display complete.")
2724 return resp.text
2725
Marri Devender Raoa208ff82019-07-01 05:51:27 -05002726def certificateList(host, args, session):
2727 """
2728 Called by certificate management function.
2729 Example:
2730 certificate list
2731 @param host: string, the hostname or IP address of the bmc
2732 @param args: contains additional arguments used by the certificate
2733 list sub command
2734 @param session: the active session to use
2735 """
2736 if not redfishSupportPresent(host, session):
2737 return "Not supported";
2738
2739 httpHeader = {'Content-Type': 'application/octet-stream'}
2740 httpHeader.update(xAuthHeader)
2741 url = "https://" + host + \
2742 "/redfish/v1/CertificateService/CertificateLocations/"
2743 try:
2744 resp = session.get(url, headers=httpHeader, verify=False)
2745 except(requests.exceptions.Timeout):
2746 return(connectionErrHandler(args.json, "Timeout", None))
2747 except(requests.exceptions.ConnectionError) as err:
2748 return connectionErrHandler(args.json, "ConnectionError", err)
2749 if resp.status_code != 200:
2750 print(resp.text)
2751 return "Failed to list certificates"
2752 else:
2753 print("List certificates complete.")
2754 return resp.text
2755
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05002756def certificateGenerateCSR(host, args, session):
2757 """
2758 Called by certificate management function. Generate CSR for server/
2759 client certificates
2760 Example:
Marri Devender Raodf0e1a42019-09-09 08:18:27 -05002761 certificate generatecsr server NJ w3.ibm.com US IBM IBM-UNIT NY EC prime256v1 cp abc.com an.com,bm.com gn sn un in
2762 certificate generatecsr client NJ w3.ibm.com US IBM IBM-UNIT NY EC prime256v1 cp abc.com an.com,bm.com gn sn un in
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05002763 @param host: string, the hostname or IP address of the bmc
2764 @param args: contains additional arguments used by the certificate replace sub command
2765 @param session: the active session to use
2766 """
2767 if not redfishSupportPresent(host, session):
2768 return "Not supported";
2769
2770 httpHeader = {'Content-Type': 'application/octet-stream'}
2771 httpHeader.update(xAuthHeader)
2772 url = "";
2773 if(args.type.lower() == 'server'):
2774 url = "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/"
Marri Devender Rao88064f02019-08-19 09:00:30 -05002775 usage_list = ["ServerAuthentication"]
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05002776 elif(args.type.lower() == 'client'):
2777 url = "/redfish/v1/AccountService/LDAP/Certificates/"
Marri Devender Rao88064f02019-08-19 09:00:30 -05002778 usage_list = ["ClientAuthentication"]
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05002779 elif(args.type.lower() == 'authority'):
2780 url = "/redfish/v1/Managers/bmc/Truststore/Certificates/"
2781 print("Generating CSR url=" + url)
2782 generateCSRUrl = "https://" + host + \
2783 "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR"
2784 try:
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05002785 alt_name_list = args.alternativeNames.split(",")
2786 data ={"CertificateCollection":{"@odata.id":url},
2787 "CommonName":args.commonName, "City":args.city,
2788 "Country":args.country, "Organization":args.organization,
2789 "OrganizationalUnit":args.organizationUnit, "State":args.state,
Marri Devender Raodf0e1a42019-09-09 08:18:27 -05002790 "KeyPairAlgorithm":args.keyPairAlgorithm, "KeyCurveId":args.keyCurveId,
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05002791 "AlternativeNames":alt_name_list, "ContactPerson":args.contactPerson,
2792 "Email":args.email, "GivenName":args.givenname, "Initials":args.initials,
2793 "KeyUsage":usage_list, "Surname":args.surname,
2794 "UnstructuredName":args.unstructuredname}
2795 resp = session.post(generateCSRUrl, headers=httpHeader,
2796 json=data, verify=False)
2797 except(requests.exceptions.Timeout):
2798 return(connectionErrHandler(args.json, "Timeout", None))
2799 except(requests.exceptions.ConnectionError) as err:
2800 return connectionErrHandler(args.json, "ConnectionError", err)
2801 if resp.status_code != 200:
2802 print(resp.text)
2803 return "Failed to generate CSR"
2804 else:
2805 print("GenerateCSR complete.")
2806 return resp.text
2807
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05002808def enableLDAPConfig(host, args, session):
Ratan Gupta9166cd22018-10-01 18:09:40 +05302809 """
2810 Called by the ldap function. Configures LDAP.
2811
2812 @param host: string, the hostname or IP address of the bmc
2813 @param args: contains additional arguments used by the ldap subcommand
2814 @param session: the active session to use
2815 @param args.json: boolean, if this flag is set to true, the output will
2816 be provided in json format for programmatic consumption
2817 """
2818
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05002819 if(isRedfishSupport):
2820 return enableLDAP(host, args, session)
2821 else:
2822 return enableLegacyLDAP(host, args, session)
2823
2824def enableLegacyLDAP(host, args, session):
2825 """
2826 Called by the ldap function. Configures LDAP on Lagecy systems.
2827
2828 @param host: string, the hostname or IP address of the bmc
2829 @param args: contains additional arguments used by the ldap subcommand
2830 @param session: the active session to use
2831 @param args.json: boolean, if this flag is set to true, the output will
2832 be provided in json format for programmatic consumption
2833 """
2834
Ratan Gupta9166cd22018-10-01 18:09:40 +05302835 url='https://'+host+'/xyz/openbmc_project/user/ldap/action/CreateConfig'
Ratan Gupta9166cd22018-10-01 18:09:40 +05302836 scope = {
2837 'sub' : 'xyz.openbmc_project.User.Ldap.Create.SearchScope.sub',
2838 'one' : 'xyz.openbmc_project.User.Ldap.Create.SearchScope.one',
2839 'base': 'xyz.openbmc_project.User.Ldap.Create.SearchScope.base'
2840 }
2841
2842 serverType = {
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05002843 'ActiveDirectory' : 'xyz.openbmc_project.User.Ldap.Create.Type.ActiveDirectory',
2844 'OpenLDAP' : 'xyz.openbmc_project.User.Ldap.Create.Type.OpenLdap'
Ratan Gupta9166cd22018-10-01 18:09:40 +05302845 }
2846
2847 data = {"data": [args.uri, args.bindDN, args.baseDN, args.bindPassword, scope[args.scope], serverType[args.serverType]]}
2848
2849 try:
Justin Thaler27197622019-01-23 14:42:11 -06002850 res = session.post(url, headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
Ratan Gupta9166cd22018-10-01 18:09:40 +05302851 except(requests.exceptions.Timeout):
2852 return(connectionErrHandler(args.json, "Timeout", None))
2853 except(requests.exceptions.ConnectionError) as err:
2854 return connectionErrHandler(args.json, "ConnectionError", err)
2855
2856 return res.text
2857
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05002858def enableLDAP(host, args, session):
2859 """
2860 Called by the ldap function. Configures LDAP for systems with latest user-manager design changes
2861
2862 @param host: string, the hostname or IP address of the bmc
2863 @param args: contains additional arguments used by the ldap subcommand
2864 @param session: the active session to use
2865 @param args.json: boolean, if this flag is set to true, the output will
2866 be provided in json format for programmatic consumption
2867 """
2868
2869 scope = {
2870 'sub' : 'xyz.openbmc_project.User.Ldap.Config.SearchScope.sub',
2871 'one' : 'xyz.openbmc_project.User.Ldap.Config.SearchScope.one',
2872 'base': 'xyz.openbmc_project.User.Ldap.Config.SearchScope.base'
2873 }
2874
2875 serverType = {
2876 'ActiveDirectory' : 'xyz.openbmc_project.User.Ldap.Config.Type.ActiveDirectory',
2877 'OpenLDAP' : 'xyz.openbmc_project.User.Ldap.Config.Type.OpenLdap'
2878 }
2879
2880 url = "https://"+host+"/xyz/openbmc_project/user/ldap/"
2881
2882 serverTypeEnabled = getLDAPTypeEnabled(host,session)
2883 serverTypeToBeEnabled = args.serverType
2884
2885 #If the given LDAP type is already enabled, then return
2886 if (serverTypeToBeEnabled == serverTypeEnabled):
2887 return("Server type " + serverTypeToBeEnabled + " is already enabled...")
2888
2889 try:
2890
2891 # Copy the role map from the currently enabled LDAP server type
2892 # to the newly enabled server type
2893 # Disable the currently enabled LDAP server type. Unless
2894 # it is disabled, we cannot enable a new LDAP server type
2895 if (serverTypeEnabled is not None):
2896
2897 if (serverTypeToBeEnabled != serverTypeEnabled):
2898 res = syncRoleMap(host,args,session,serverTypeEnabled,serverTypeToBeEnabled)
2899
2900 data = "{\"data\": 0 }"
2901 res = session.put(url + serverTypeMap[serverTypeEnabled] + '/attr/Enabled', headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
2902
2903 data = {"data": args.baseDN}
2904 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/LDAPBaseDN', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
2905 if (res.status_code != requests.codes.ok):
2906 print("Updates to the property LDAPBaseDN failed...")
2907 return(res.text)
2908
2909 data = {"data": args.bindDN}
2910 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/LDAPBindDN', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
2911 if (res.status_code != requests.codes.ok):
2912 print("Updates to the property LDAPBindDN failed...")
2913 return(res.text)
2914
2915 data = {"data": args.bindPassword}
2916 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/LDAPBindDNPassword', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
2917 if (res.status_code != requests.codes.ok):
2918 print("Updates to the property LDAPBindDNPassword failed...")
2919 return(res.text)
2920
2921 data = {"data": scope[args.scope]}
2922 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/LDAPSearchScope', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
2923 if (res.status_code != requests.codes.ok):
2924 print("Updates to the property LDAPSearchScope failed...")
2925 return(res.text)
2926
2927 data = {"data": args.uri}
2928 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/LDAPServerURI', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
2929 if (res.status_code != requests.codes.ok):
2930 print("Updates to the property LDAPServerURI failed...")
2931 return(res.text)
2932
2933 data = {"data": args.groupAttrName}
2934 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/GroupNameAttribute', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
2935 if (res.status_code != requests.codes.ok):
2936 print("Updates to the property GroupNameAttribute failed...")
2937 return(res.text)
2938
2939 data = {"data": args.userAttrName}
2940 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/UserNameAttribute', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
2941 if (res.status_code != requests.codes.ok):
2942 print("Updates to the property UserNameAttribute failed...")
2943 return(res.text)
2944
2945 #After updating the properties, enable the new server type
2946 data = "{\"data\": 1 }"
2947 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/Enabled', headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
2948
2949 except(requests.exceptions.Timeout):
2950 return(connectionErrHandler(args.json, "Timeout", None))
2951 except(requests.exceptions.ConnectionError) as err:
2952 return connectionErrHandler(args.json, "ConnectionError", err)
2953 return res.text
Ratan Gupta9166cd22018-10-01 18:09:40 +05302954
2955def disableLDAP(host, args, session):
2956 """
2957 Called by the ldap function. Deletes the LDAP Configuration.
2958
2959 @param host: string, the hostname or IP address of the bmc
2960 @param args: contains additional arguments used by the ldap subcommand
2961 @param session: the active session to use
2962 @param args.json: boolean, if this flag is set to true, the output
2963 will be provided in json format for programmatic consumption
2964 """
2965
Ratan Gupta9166cd22018-10-01 18:09:40 +05302966 try:
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05002967 if (isRedfishSupport) :
2968
2969 url = "https://"+host+"/xyz/openbmc_project/user/ldap/"
2970
2971 serverTypeEnabled = getLDAPTypeEnabled(host,session)
2972
2973 if (serverTypeEnabled is not None):
2974 #To keep the role map in sync,
2975 #If the server type being disabled has role map, then
2976 # - copy the role map to the other server type(s)
2977 for serverType in serverTypeMap.keys():
2978 if (serverType != serverTypeEnabled):
2979 res = syncRoleMap(host,args,session,serverTypeEnabled,serverType)
2980
2981 #Disable the currently enabled LDAP server type
2982 data = "{\"data\": 0 }"
2983 res = session.put(url + serverTypeMap[serverTypeEnabled] + '/attr/Enabled', headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
2984
2985 else:
2986 return("LDAP server has not been enabled...")
2987
2988 else :
2989 url='https://'+host+'/xyz/openbmc_project/user/ldap/config/action/delete'
2990 data = {"data": []}
2991 res = session.post(url, headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
2992
Ratan Gupta9166cd22018-10-01 18:09:40 +05302993 except(requests.exceptions.Timeout):
2994 return(connectionErrHandler(args.json, "Timeout", None))
2995 except(requests.exceptions.ConnectionError) as err:
2996 return connectionErrHandler(args.json, "ConnectionError", err)
2997
2998 return res.text
2999
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003000def enableDHCP(host, args, session):
3001
3002 """
3003 Called by the network function. Enables DHCP.
3004
3005 @param host: string, the hostname or IP address of the bmc
3006 @param args: contains additional arguments used by the ldap subcommand
3007 args.json: boolean, if this flag is set to true, the output
3008 will be provided in json format for programmatic consumption
3009 @param session: the active session to use
3010 """
3011
3012 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3013 "/attr/DHCPEnabled"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003014 data = "{\"data\": 1 }"
3015 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003016 res = session.put(url, headers=jsonHeader, data=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003017 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003018
3019 except(requests.exceptions.Timeout):
3020 return(connectionErrHandler(args.json, "Timeout", None))
3021 except(requests.exceptions.ConnectionError) as err:
3022 return connectionErrHandler(args.json, "ConnectionError", err)
3023 if res.status_code == 403:
3024 return "The specified Interface"+"("+args.Interface+")"+\
3025 " doesn't exist"
3026
3027 return res.text
3028
3029
3030def disableDHCP(host, args, session):
3031 """
3032 Called by the network function. Disables DHCP.
3033
3034 @param host: string, the hostname or IP address of the bmc
3035 @param args: contains additional arguments used by the ldap subcommand
3036 args.json: boolean, if this flag is set to true, the output
3037 will be provided in json format for programmatic consumption
3038 @param session: the active session to use
3039 """
3040
3041 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3042 "/attr/DHCPEnabled"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003043 data = "{\"data\": 0 }"
3044 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003045 res = session.put(url, headers=jsonHeader, data=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003046 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003047 except(requests.exceptions.Timeout):
3048 return(connectionErrHandler(args.json, "Timeout", None))
3049 except(requests.exceptions.ConnectionError) as err:
3050 return connectionErrHandler(args.json, "ConnectionError", err)
3051 if res.status_code == 403:
3052 return "The specified Interface"+"("+args.Interface+")"+\
3053 " doesn't exist"
3054 return res.text
3055
3056
3057def getHostname(host, args, session):
3058
3059 """
3060 Called by the network function. Prints out the Hostname.
3061
3062 @param host: string, the hostname or IP address of the bmc
3063 @param args: contains additional arguments used by the ldap subcommand
3064 args.json: boolean, if this flag is set to true, the output
3065 will be provided in json format for programmatic consumption
3066 @param session: the active session to use
3067 """
3068
3069 url = "https://"+host+"/xyz/openbmc_project/network/config/attr/HostName"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003070
3071 try:
Justin Thaler27197622019-01-23 14:42:11 -06003072 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003073 except(requests.exceptions.Timeout):
3074 return(connectionErrHandler(args.json, "Timeout", None))
3075 except(requests.exceptions.ConnectionError) as err:
3076 return connectionErrHandler(args.json, "ConnectionError", err)
3077
3078 return res.text
3079
3080
3081def setHostname(host, args, session):
3082 """
3083 Called by the network function. Sets the Hostname.
3084
3085 @param host: string, the hostname or IP address of the bmc
3086 @param args: contains additional arguments used by the ldap subcommand
3087 args.json: boolean, if this flag is set to true, the output
3088 will be provided in json format for programmatic consumption
3089 @param session: the active session to use
3090 """
3091
3092 url = "https://"+host+"/xyz/openbmc_project/network/config/attr/HostName"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003093
3094 data = {"data": args.HostName}
3095
3096 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003097 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003098 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003099 except(requests.exceptions.Timeout):
3100 return(connectionErrHandler(args.json, "Timeout", None))
3101 except(requests.exceptions.ConnectionError) as err:
3102 return connectionErrHandler(args.json, "ConnectionError", err)
3103
3104 return res.text
3105
3106
3107def getDomainName(host, args, session):
3108
3109 """
3110 Called by the network function. Prints out the DomainName.
3111
3112 @param host: string, the hostname or IP address of the bmc
3113 @param args: contains additional arguments used by the ldap subcommand
3114 args.json: boolean, if this flag is set to true, the output
3115 will be provided in json format for programmatic consumption
3116 @param session: the active session to use
3117 """
3118
3119 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3120 "/attr/DomainName"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003121
3122 try:
Justin Thaler27197622019-01-23 14:42:11 -06003123 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003124 except(requests.exceptions.Timeout):
3125 return(connectionErrHandler(args.json, "Timeout", None))
3126 except(requests.exceptions.ConnectionError) as err:
3127 return connectionErrHandler(args.json, "ConnectionError", err)
3128 if res.status_code == 404:
Sunitha Harishf9bb2fa2019-09-19 01:48:00 -05003129 return "The DomainName is not configured on Interface"+"("+args.Interface+")"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003130
3131 return res.text
3132
3133
3134def setDomainName(host, args, session):
3135 """
3136 Called by the network function. Sets the DomainName.
3137
3138 @param host: string, the hostname or IP address of the bmc
3139 @param args: contains additional arguments used by the ldap subcommand
3140 args.json: boolean, if this flag is set to true, the output
3141 will be provided in json format for programmatic consumption
3142 @param session: the active session to use
3143 """
3144
3145 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3146 "/attr/DomainName"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003147
3148 data = {"data": args.DomainName.split(",")}
3149
3150 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003151 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003152 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003153 except(requests.exceptions.Timeout):
3154 return(connectionErrHandler(args.json, "Timeout", None))
3155 except(requests.exceptions.ConnectionError) as err:
3156 return connectionErrHandler(args.json, "ConnectionError", err)
3157 if res.status_code == 403:
3158 return "The specified Interface"+"("+args.Interface+")"+\
3159 " doesn't exist"
3160
3161 return res.text
3162
3163
3164def getMACAddress(host, args, session):
3165
3166 """
3167 Called by the network function. Prints out the MACAddress.
3168
3169 @param host: string, the hostname or IP address of the bmc
3170 @param args: contains additional arguments used by the ldap subcommand
3171 args.json: boolean, if this flag is set to true, the output
3172 will be provided in json format for programmatic consumption
3173 @param session: the active session to use
3174 """
3175
3176 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3177 "/attr/MACAddress"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003178
3179 try:
Justin Thaler27197622019-01-23 14:42:11 -06003180 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003181 except(requests.exceptions.Timeout):
3182 return(connectionErrHandler(args.json, "Timeout", None))
3183 except(requests.exceptions.ConnectionError) as err:
3184 return connectionErrHandler(args.json, "ConnectionError", err)
3185 if res.status_code == 404:
3186 return "The specified Interface"+"("+args.Interface+")"+\
3187 " doesn't exist"
3188
3189 return res.text
3190
3191
3192def setMACAddress(host, args, session):
3193 """
3194 Called by the network function. Sets the MACAddress.
3195
3196 @param host: string, the hostname or IP address of the bmc
3197 @param args: contains additional arguments used by the ldap subcommand
3198 args.json: boolean, if this flag is set to true, the output
3199 will be provided in json format for programmatic consumption
3200 @param session: the active session to use
3201 """
3202
3203 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3204 "/attr/MACAddress"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003205
3206 data = {"data": args.MACAddress}
3207
3208 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003209 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003210 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003211 except(requests.exceptions.Timeout):
3212 return(connectionErrHandler(args.json, "Timeout", None))
3213 except(requests.exceptions.ConnectionError) as err:
3214 return connectionErrHandler(args.json, "ConnectionError", err)
3215 if res.status_code == 403:
3216 return "The specified Interface"+"("+args.Interface+")"+\
3217 " doesn't exist"
3218
3219 return res.text
3220
3221
3222def getDefaultGateway(host, args, session):
3223
3224 """
3225 Called by the network function. Prints out the DefaultGateway.
3226
3227 @param host: string, the hostname or IP address of the bmc
3228 @param args: contains additional arguments used by the ldap subcommand
3229 args.json: boolean, if this flag is set to true, the output
3230 will be provided in json format for programmatic consumption
3231 @param session: the active session to use
3232 """
3233
3234 url = "https://"+host+"/xyz/openbmc_project/network/config/attr/DefaultGateway"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003235
3236 try:
Justin Thaler27197622019-01-23 14:42:11 -06003237 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003238 except(requests.exceptions.Timeout):
3239 return(connectionErrHandler(args.json, "Timeout", None))
3240 except(requests.exceptions.ConnectionError) as err:
3241 return connectionErrHandler(args.json, "ConnectionError", err)
3242 if res.status_code == 404:
3243 return "Failed to get Default Gateway info!!"
3244
3245 return res.text
3246
3247
3248def setDefaultGateway(host, args, session):
3249 """
3250 Called by the network function. Sets the DefaultGateway.
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/config/attr/DefaultGateway"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003260
3261 data = {"data": args.DefaultGW}
3262
3263 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003264 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003265 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003266 except(requests.exceptions.Timeout):
3267 return(connectionErrHandler(args.json, "Timeout", None))
3268 except(requests.exceptions.ConnectionError) as err:
3269 return connectionErrHandler(args.json, "ConnectionError", err)
3270 if res.status_code == 403:
3271 return "Failed to set Default Gateway!!"
3272
3273 return res.text
3274
3275
3276def viewNWConfig(host, args, session):
3277 """
3278 Called by the ldap function. Prints out network configured properties
3279
3280 @param host: string, the hostname or IP address of the bmc
3281 @param args: contains additional arguments used by the ldap subcommand
3282 args.json: boolean, if this flag is set to true, the output
3283 will be provided in json format for programmatic consumption
3284 @param session: the active session to use
3285 @return returns LDAP's configured properties.
3286 """
3287 url = "https://"+host+"/xyz/openbmc_project/network/enumerate"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003288 try:
Justin Thaler27197622019-01-23 14:42:11 -06003289 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003290 except(requests.exceptions.Timeout):
3291 return(connectionErrHandler(args.json, "Timeout", None))
3292 except(requests.exceptions.ConnectionError) as err:
3293 return connectionErrHandler(args.json, "ConnectionError", err)
3294 except(requests.exceptions.RequestException) as err:
3295 return connectionErrHandler(args.json, "RequestException", err)
3296 if res.status_code == 404:
3297 return "LDAP server config has not been created"
3298 return res.text
3299
3300
3301def getDNS(host, args, session):
3302
3303 """
3304 Called by the network function. Prints out DNS servers on the interface
3305
3306 @param host: string, the hostname or IP address of the bmc
3307 @param args: contains additional arguments used by the ldap subcommand
3308 args.json: boolean, if this flag is set to true, the output
3309 will be provided in json format for programmatic consumption
3310 @param session: the active session to use
3311 """
3312
3313 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
3314 + "/attr/Nameservers"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003315
3316 try:
Justin Thaler27197622019-01-23 14:42:11 -06003317 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003318 except(requests.exceptions.Timeout):
3319 return(connectionErrHandler(args.json, "Timeout", None))
3320 except(requests.exceptions.ConnectionError) as err:
3321 return connectionErrHandler(args.json, "ConnectionError", err)
3322 if res.status_code == 404:
Sunitha Harishf9bb2fa2019-09-19 01:48:00 -05003323 return "The NameServer is not configured on Interface"+"("+args.Interface+")"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003324
3325 return res.text
3326
3327
3328def setDNS(host, args, session):
3329 """
3330 Called by the network function. Sets DNS servers on the interface.
3331
3332 @param host: string, the hostname or IP address of the bmc
3333 @param args: contains additional arguments used by the ldap subcommand
3334 args.json: boolean, if this flag is set to true, the output
3335 will be provided in json format for programmatic consumption
3336 @param session: the active session to use
3337 """
3338
3339 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
3340 + "/attr/Nameservers"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003341
3342 data = {"data": args.DNSServers.split(",")}
3343
3344 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003345 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003346 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003347 except(requests.exceptions.Timeout):
3348 return(connectionErrHandler(args.json, "Timeout", None))
3349 except(requests.exceptions.ConnectionError) as err:
3350 return connectionErrHandler(args.json, "ConnectionError", err)
3351 if res.status_code == 403:
3352 return "The specified Interface"+"("+args.Interface+")" +\
3353 " doesn't exist"
3354
3355 return res.text
3356
3357
3358def getNTP(host, args, session):
3359
3360 """
3361 Called by the network function. Prints out NTP servers on the interface
3362
3363 @param host: string, the hostname or IP address of the bmc
3364 @param args: contains additional arguments used by the ldap subcommand
3365 args.json: boolean, if this flag is set to true, the output
3366 will be provided in json format for programmatic consumption
3367 @param session: the active session to use
3368 """
3369
3370 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
3371 + "/attr/NTPServers"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003372 try:
Justin Thaler27197622019-01-23 14:42:11 -06003373 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003374 except(requests.exceptions.Timeout):
3375 return(connectionErrHandler(args.json, "Timeout", None))
3376 except(requests.exceptions.ConnectionError) as err:
3377 return connectionErrHandler(args.json, "ConnectionError", err)
3378 if res.status_code == 404:
Sunitha Harishf9bb2fa2019-09-19 01:48:00 -05003379 return "The NTPServer is not configured on Interface"+"("+args.Interface+")"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003380
3381 return res.text
3382
3383
3384def setNTP(host, args, session):
3385 """
3386 Called by the network function. Sets NTP servers on the interface.
3387
3388 @param host: string, the hostname or IP address of the bmc
3389 @param args: contains additional arguments used by the ldap subcommand
3390 args.json: boolean, if this flag is set to true, the output
3391 will be provided in json format for programmatic consumption
3392 @param session: the active session to use
3393 """
3394
3395 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
3396 + "/attr/NTPServers"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003397
3398 data = {"data": args.NTPServers.split(",")}
3399
3400 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003401 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003402 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003403 except(requests.exceptions.Timeout):
3404 return(connectionErrHandler(args.json, "Timeout", None))
3405 except(requests.exceptions.ConnectionError) as err:
3406 return connectionErrHandler(args.json, "ConnectionError", err)
3407 if res.status_code == 403:
3408 return "The specified Interface"+"("+args.Interface+")" +\
3409 " doesn't exist"
3410
3411 return res.text
3412
3413
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003414def addIP(host, args, session):
3415 """
3416 Called by the network function. Configures IP address on given interface
3417
3418 @param host: string, the hostname or IP address of the bmc
3419 @param args: contains additional arguments used by the ldap subcommand
3420 args.json: boolean, if this flag is set to true, the output
3421 will be provided in json format for programmatic consumption
3422 @param session: the active session to use
3423 """
3424
3425 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
3426 + "/action/IP"
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003427 protocol = {
3428 'ipv4': 'xyz.openbmc_project.Network.IP.Protocol.IPv4',
3429 'ipv6': 'xyz.openbmc_project.Network.IP.Protocol.IPv6'
3430 }
3431
3432 data = {"data": [protocol[args.type], args.address, int(args.prefixLength),
3433 args.gateway]}
3434
3435 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003436 res = session.post(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003437 timeout=baseTimeout)
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003438 except(requests.exceptions.Timeout):
3439 return(connectionErrHandler(args.json, "Timeout", None))
3440 except(requests.exceptions.ConnectionError) as err:
3441 return connectionErrHandler(args.json, "ConnectionError", err)
3442 if res.status_code == 404:
3443 return "The specified Interface" + "(" + args.Interface + ")" +\
3444 " doesn't exist"
3445
3446 return res.text
3447
3448
3449def getIP(host, args, session):
3450 """
3451 Called by the network function. Prints out IP address of given interface
3452
3453 @param host: string, the hostname or IP address of the bmc
3454 @param args: contains additional arguments used by the ldap subcommand
3455 args.json: boolean, if this flag is set to true, the output
3456 will be provided in json format for programmatic consumption
3457 @param session: the active session to use
3458 """
3459
3460 url = "https://" + host+"/xyz/openbmc_project/network/" + args.Interface +\
3461 "/enumerate"
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003462 try:
Justin Thaler27197622019-01-23 14:42:11 -06003463 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003464 except(requests.exceptions.Timeout):
3465 return(connectionErrHandler(args.json, "Timeout", None))
3466 except(requests.exceptions.ConnectionError) as err:
3467 return connectionErrHandler(args.json, "ConnectionError", err)
3468 if res.status_code == 404:
3469 return "The specified Interface" + "(" + args.Interface + ")" +\
3470 " doesn't exist"
3471
3472 return res.text
3473
3474
3475def deleteIP(host, args, session):
3476 """
3477 Called by the network function. Deletes the IP address from given Interface
3478
3479 @param host: string, the hostname or IP address of the bmc
3480 @param args: contains additional arguments used by the ldap subcommand
3481 @param session: the active session to use
3482 @param args.json: boolean, if this flag is set to true, the output
3483 will be provided in json format for programmatic consumption
3484 """
3485
3486 url = "https://"+host+"/xyz/openbmc_project/network/" + args.Interface+\
3487 "/enumerate"
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003488 data = {"data": []}
3489 try:
Justin Thaler27197622019-01-23 14:42:11 -06003490 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003491 except(requests.exceptions.Timeout):
3492 return(connectionErrHandler(args.json, "Timeout", None))
3493 except(requests.exceptions.ConnectionError) as err:
3494 return connectionErrHandler(args.json, "ConnectionError", err)
3495 if res.status_code == 404:
3496 return "The specified Interface" + "(" + args.Interface + ")" +\
3497 " doesn't exist"
3498 objDict = json.loads(res.text)
3499 if not objDict['data']:
3500 return "No object found for given address on given Interface"
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003501 for obj in objDict['data']:
Sunitha Harish0baf6372019-07-31 03:59:03 -05003502 try:
3503 if args.address in objDict['data'][obj]['Address']:
3504 url = "https://"+host+obj+"/action/Delete"
3505 try:
3506 res = session.post(url, headers=jsonHeader, json=data,
3507 verify=False, timeout=baseTimeout)
3508 except(requests.exceptions.Timeout):
3509 return(connectionErrHandler(args.json, "Timeout", None))
3510 except(requests.exceptions.ConnectionError) as err:
3511 return connectionErrHandler(args.json, "ConnectionError", err)
3512 return res.text
3513 else:
3514 continue
3515 except KeyError:
Sunitha Harishf9bb2fa2019-09-19 01:48:00 -05003516 continue
3517 return "No object found for address " + args.address + \
3518 " on Interface(" + args.Interface + ")"
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003519
3520
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003521def addVLAN(host, args, session):
3522 """
3523 Called by the network function. Creates VLAN on given interface.
3524
3525 @param host: string, the hostname or IP address of the bmc
3526 @param args: contains additional arguments used by the ldap subcommand
3527 args.json: boolean, if this flag is set to true, the output
3528 will be provided in json format for programmatic consumption
3529 @param session: the active session to use
3530 """
3531
3532 url = "https://" + host+"/xyz/openbmc_project/network/action/VLAN"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003533
Sunitha Harish0baf6372019-07-31 03:59:03 -05003534 data = {"data": [args.Interface,int(args.Identifier)]}
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003535 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003536 res = session.post(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003537 timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003538 except(requests.exceptions.Timeout):
3539 return(connectionErrHandler(args.json, "Timeout", None))
3540 except(requests.exceptions.ConnectionError) as err:
3541 return connectionErrHandler(args.json, "ConnectionError", err)
3542 if res.status_code == 400:
Sunitha Harish0baf6372019-07-31 03:59:03 -05003543 return "Adding VLAN to interface" + "(" + args.Interface + ")" +\
3544 " failed"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003545
3546 return res.text
3547
3548
3549def deleteVLAN(host, args, session):
3550 """
3551 Called by the network function. Creates VLAN on given interface.
3552
3553 @param host: string, the hostname or IP address of the bmc
3554 @param args: contains additional arguments used by the ldap subcommand
3555 args.json: boolean, if this flag is set to true, the output
3556 will be provided in json format for programmatic consumption
3557 @param session: the active session to use
3558 """
3559
Sunitha Harish577a5032019-08-08 06:27:40 -05003560 url = "https://" + host+"/xyz/openbmc_project/network/"+args.Interface+"/action/Delete"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003561 data = {"data": []}
3562
3563 try:
Justin Thaler27197622019-01-23 14:42:11 -06003564 res = session.post(url, headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003565 except(requests.exceptions.Timeout):
3566 return(connectionErrHandler(args.json, "Timeout", None))
3567 except(requests.exceptions.ConnectionError) as err:
3568 return connectionErrHandler(args.json, "ConnectionError", err)
3569 if res.status_code == 404:
Sunitha Harish577a5032019-08-08 06:27:40 -05003570 return "The specified VLAN"+"("+args.Interface+")" +" doesn't exist"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003571
3572 return res.text
3573
3574
3575def viewDHCPConfig(host, args, session):
3576 """
3577 Called by the network function. Shows DHCP configured Properties.
3578
3579 @param host: string, the hostname or IP address of the bmc
3580 @param args: contains additional arguments used by the ldap subcommand
3581 args.json: boolean, if this flag is set to true, the output
3582 will be provided in json format for programmatic consumption
3583 @param session: the active session to use
3584 """
3585
3586 url="https://"+host+"/xyz/openbmc_project/network/config/dhcp"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003587
3588 try:
Justin Thaler27197622019-01-23 14:42:11 -06003589 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003590 except(requests.exceptions.Timeout):
3591 return(connectionErrHandler(args.json, "Timeout", None))
3592 except(requests.exceptions.ConnectionError) as err:
3593 return connectionErrHandler(args.json, "ConnectionError", err)
3594
3595 return res.text
3596
3597
3598def configureDHCP(host, args, session):
3599 """
3600 Called by the network function. Configures/updates DHCP Properties.
3601
3602 @param host: string, the hostname or IP address of the bmc
3603 @param args: contains additional arguments used by the ldap subcommand
3604 args.json: boolean, if this flag is set to true, the output
3605 will be provided in json format for programmatic consumption
3606 @param session: the active session to use
3607 """
3608
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003609
3610 try:
3611 url="https://"+host+"/xyz/openbmc_project/network/config/dhcp"
3612 if(args.DNSEnabled == True):
3613 data = '{"data": 1}'
3614 else:
3615 data = '{"data": 0}'
Matt Spinler220c3c42019-01-04 15:09:29 -06003616 res = session.put(url + '/attr/DNSEnabled', headers=jsonHeader,
Justin Thaler27197622019-01-23 14:42:11 -06003617 data=data, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003618 if(args.HostNameEnabled == True):
3619 data = '{"data": 1}'
3620 else:
3621 data = '{"data": 0}'
Matt Spinler220c3c42019-01-04 15:09:29 -06003622 res = session.put(url + '/attr/HostNameEnabled', headers=jsonHeader,
Justin Thaler27197622019-01-23 14:42:11 -06003623 data=data, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003624 if(args.NTPEnabled == True):
3625 data = '{"data": 1}'
3626 else:
3627 data = '{"data": 0}'
Matt Spinler220c3c42019-01-04 15:09:29 -06003628 res = session.put(url + '/attr/NTPEnabled', headers=jsonHeader,
Justin Thaler27197622019-01-23 14:42:11 -06003629 data=data, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003630 if(args.SendHostNameEnabled == True):
3631 data = '{"data": 1}'
3632 else:
3633 data = '{"data": 0}'
Matt Spinler220c3c42019-01-04 15:09:29 -06003634 res = session.put(url + '/attr/SendHostNameEnabled', headers=jsonHeader,
Justin Thaler27197622019-01-23 14:42:11 -06003635 data=data, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003636 except(requests.exceptions.Timeout):
3637 return(connectionErrHandler(args.json, "Timeout", None))
3638 except(requests.exceptions.ConnectionError) as err:
3639 return connectionErrHandler(args.json, "ConnectionError", err)
3640
3641 return res.text
3642
3643
3644def nwReset(host, args, session):
3645
3646 """
3647 Called by the network function. Resets networks setting to factory defaults.
3648
3649 @param host: string, the hostname or IP address of the bmc
3650 @param args: contains additional arguments used by the ldap subcommand
3651 args.json: boolean, if this flag is set to true, the output
3652 will be provided in json format for programmatic consumption
3653 @param session: the active session to use
3654 """
3655
3656 url = "https://"+host+"/xyz/openbmc_project/network/action/Reset"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003657 data = '{"data":[] }'
3658 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003659 res = session.post(url, headers=jsonHeader, data=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003660 timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003661
3662 except(requests.exceptions.Timeout):
3663 return(connectionErrHandler(args.json, "Timeout", None))
3664 except(requests.exceptions.ConnectionError) as err:
3665 return connectionErrHandler(args.json, "ConnectionError", err)
3666
3667 return res.text
3668
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003669def getLDAPTypeEnabled(host,session):
3670
3671 """
3672 Called by LDAP related functions to find the LDAP server type that has been enabled.
3673 Returns None if LDAP has not been configured.
3674
3675 @param host: string, the hostname or IP address of the bmc
3676 @param session: the active session to use
3677 """
3678
3679 enabled = False
3680 url = 'https://'+host+'/xyz/openbmc_project/user/ldap/'
3681 for key,value in serverTypeMap.items():
3682 data = {"data": []}
3683 try:
3684 res = session.get(url + value + '/attr/Enabled', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
3685 except(requests.exceptions.Timeout):
3686 print(connectionErrHandler(args.json, "Timeout", None))
3687 return
3688 except(requests.exceptions.ConnectionError) as err:
3689 print(connectionErrHandler(args.json, "ConnectionError", err))
3690 return
3691
3692 enabled = res.json()['data']
3693 if (enabled):
3694 return key
3695
3696def syncRoleMap(host,args,session,fromServerType,toServerType):
3697
3698 """
3699 Called by LDAP related functions to sync the role maps
3700 Returns False if LDAP has not been configured.
3701
3702 @param host: string, the hostname or IP address of the bmc
3703 @param session: the active session to use
3704 @param fromServerType : Server type whose role map has to be copied
3705 @param toServerType : Server type to which role map has to be copied
3706 """
3707
3708 url = "https://"+host+"/xyz/openbmc_project/user/ldap/"
3709
3710 try:
3711 #Note: If the fromServerType has no role map, then
3712 #the toServerType will not have any role map.
3713
3714 #delete the privilege mapping from the toServerType and
3715 #then copy the privilege mapping from fromServerType to
3716 #toServerType.
3717 args.serverType = toServerType
3718 res = deleteAllPrivilegeMapping(host, args, session)
3719
3720 data = {"data": []}
3721 res = session.get(url + serverTypeMap[fromServerType] + '/role_map/enumerate', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
3722 #Previously enabled server type has no role map
3723 if (res.status_code != requests.codes.ok):
3724
3725 #fromServerType has no role map; So, no need to copy
3726 #role map to toServerType.
3727 return
3728
3729 objDict = json.loads(res.text)
3730 dataDict = objDict['data']
3731 for key,value in dataDict.items():
3732 data = {"data": [value["GroupName"], value["Privilege"]]}
3733 res = session.post(url + serverTypeMap[toServerType] + '/action/Create', headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
3734
3735 except(requests.exceptions.Timeout):
3736 return(connectionErrHandler(args.json, "Timeout", None))
3737 except(requests.exceptions.ConnectionError) as err:
3738 return connectionErrHandler(args.json, "ConnectionError", err)
3739 return res.text
3740
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003741
Ratan Guptafeee6372018-10-17 23:25:51 +05303742def createPrivilegeMapping(host, args, session):
3743 """
3744 Called by the ldap function. Creates the group and the privilege mapping.
3745
3746 @param host: string, the hostname or IP address of the bmc
3747 @param args: contains additional arguments used by the ldap subcommand
3748 @param session: the active session to use
3749 @param args.json: boolean, if this flag is set to true, the output
3750 will be provided in json format for programmatic consumption
3751 """
3752
Ratan Guptafeee6372018-10-17 23:25:51 +05303753 try:
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003754 if (isRedfishSupport):
3755 url = 'https://'+host+'/xyz/openbmc_project/user/ldap/'
3756
3757 #To maintain the interface compatibility between op930 and op940, the server type has been made
3758 #optional. If the server type is not specified, then create the role-mapper for the currently
3759 #enabled server type.
3760 serverType = args.serverType
3761 if (serverType is None):
3762 serverType = getLDAPTypeEnabled(host,session)
3763 if (serverType is None):
3764 return("LDAP server has not been enabled. Please specify LDAP serverType to proceed further...")
3765
3766 data = {"data": [args.groupName,args.privilege]}
3767 res = session.post(url + serverTypeMap[serverType] + '/action/Create', headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
3768
3769 else:
3770 url = 'https://'+host+'/xyz/openbmc_project/user/ldap/action/Create'
3771 data = {"data": [args.groupName,args.privilege]}
3772 res = session.post(url, headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
3773
Ratan Guptafeee6372018-10-17 23:25:51 +05303774 except(requests.exceptions.Timeout):
3775 return(connectionErrHandler(args.json, "Timeout", None))
3776 except(requests.exceptions.ConnectionError) as err:
3777 return connectionErrHandler(args.json, "ConnectionError", err)
3778 return res.text
3779
3780def listPrivilegeMapping(host, args, session):
3781 """
3782 Called by the ldap function. Lists the group and the privilege mapping.
3783
3784 @param host: string, the hostname or IP address of the bmc
3785 @param args: contains additional arguments used by the ldap subcommand
3786 @param session: the active session to use
3787 @param args.json: boolean, if this flag is set to true, the output
3788 will be provided in json format for programmatic consumption
3789 """
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003790
3791 if (isRedfishSupport):
3792 serverType = args.serverType
3793 if (serverType is None):
3794 serverType = getLDAPTypeEnabled(host,session)
3795 if (serverType is None):
3796 return("LDAP has not been enabled. Please specify LDAP serverType to proceed further...")
3797
3798 url = 'https://'+host+'/xyz/openbmc_project/user/ldap/'+serverTypeMap[serverType]+'/role_map/enumerate'
3799
3800 else:
3801 url = 'https://'+host+'/xyz/openbmc_project/user/ldap/enumerate'
3802
Ratan Guptafeee6372018-10-17 23:25:51 +05303803 data = {"data": []}
3804
3805 try:
Justin Thaler27197622019-01-23 14:42:11 -06003806 res = session.get(url, headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
Ratan Guptafeee6372018-10-17 23:25:51 +05303807 except(requests.exceptions.Timeout):
3808 return(connectionErrHandler(args.json, "Timeout", None))
3809 except(requests.exceptions.ConnectionError) as err:
3810 return connectionErrHandler(args.json, "ConnectionError", err)
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003811
Ratan Guptafeee6372018-10-17 23:25:51 +05303812 return res.text
3813
3814def deletePrivilegeMapping(host, args, session):
3815 """
3816 Called by the ldap function. Deletes the mapping associated with the group.
3817
3818 @param host: string, the hostname or IP address of the bmc
3819 @param args: contains additional arguments used by the ldap subcommand
3820 @param session: the active session to use
3821 @param args.json: boolean, if this flag is set to true, the output
3822 will be provided in json format for programmatic consumption
3823 """
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003824
3825 ldapNameSpaceObjects = listPrivilegeMapping(host, args, session)
Ratan Guptafeee6372018-10-17 23:25:51 +05303826 ldapNameSpaceObjects = json.loads(ldapNameSpaceObjects)["data"]
3827 path = ''
Ratan Guptafeee6372018-10-17 23:25:51 +05303828 data = {"data": []}
3829
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003830 if (isRedfishSupport):
3831 if (args.serverType is None):
3832 serverType = getLDAPTypeEnabled(host,session)
3833 if (serverType is None):
3834 return("LDAP has not been enabled. Please specify LDAP serverType to proceed further...")
3835 # search for the object having the mapping for the given group
3836 for key,value in ldapNameSpaceObjects.items():
3837 if value['GroupName'] == args.groupName:
3838 path = key
3839 break
3840
3841 if path == '':
3842 return "No privilege mapping found for this group."
3843
3844 # delete the object
3845 url = 'https://'+host+path+'/action/Delete'
3846
3847 else:
3848 # not interested in the config objet
3849 ldapNameSpaceObjects.pop('/xyz/openbmc_project/user/ldap/config', None)
3850
3851 # search for the object having the mapping for the given group
3852 for key,value in ldapNameSpaceObjects.items():
3853 if value['GroupName'] == args.groupName:
3854 path = key
3855 break
3856
3857 if path == '':
3858 return "No privilege mapping found for this group."
3859
3860 # delete the object
3861 url = 'https://'+host+path+'/action/delete'
3862
Ratan Guptafeee6372018-10-17 23:25:51 +05303863 try:
Justin Thaler27197622019-01-23 14:42:11 -06003864 res = session.post(url, headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
Ratan Guptafeee6372018-10-17 23:25:51 +05303865 except(requests.exceptions.Timeout):
3866 return(connectionErrHandler(args.json, "Timeout", None))
3867 except(requests.exceptions.ConnectionError) as err:
3868 return connectionErrHandler(args.json, "ConnectionError", err)
3869 return res.text
Ratan Gupta9166cd22018-10-01 18:09:40 +05303870
Sivas SRR78835272018-11-27 05:27:19 -06003871def deleteAllPrivilegeMapping(host, args, session):
3872 """
3873 Called by the ldap function. Deletes all the privilege mapping and group defined.
3874 @param host: string, the hostname or IP address of the bmc
3875 @param args: contains additional arguments used by the ldap subcommand
3876 @param session: the active session to use
3877 @param args.json: boolean, if this flag is set to true, the output
3878 will be provided in json format for programmatic consumption
3879 """
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003880
Sivas SRR78835272018-11-27 05:27:19 -06003881 ldapNameSpaceObjects = listPrivilegeMapping(host, args, session)
3882 ldapNameSpaceObjects = json.loads(ldapNameSpaceObjects)["data"]
3883 path = ''
Sivas SRR78835272018-11-27 05:27:19 -06003884 data = {"data": []}
3885
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003886 if (isRedfishSupport):
3887 if (args.serverType is None):
3888 serverType = getLDAPTypeEnabled(host,session)
3889 if (serverType is None):
3890 return("LDAP has not been enabled. Please specify LDAP serverType to proceed further...")
3891
3892 else:
3893 # Remove the config object.
3894 ldapNameSpaceObjects.pop('/xyz/openbmc_project/user/ldap/config', None)
3895
Sivas SRR78835272018-11-27 05:27:19 -06003896 try:
3897 # search for GroupName property and delete if it is available.
3898 for path in ldapNameSpaceObjects.keys():
3899 # delete the object
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003900 url = 'https://'+host+path+'/action/Delete'
Justin Thaler27197622019-01-23 14:42:11 -06003901 res = session.post(url, headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003902
Sivas SRR78835272018-11-27 05:27:19 -06003903 except(requests.exceptions.Timeout):
3904 return(connectionErrHandler(args.json, "Timeout", None))
3905 except(requests.exceptions.ConnectionError) as err:
3906 return connectionErrHandler(args.json, "ConnectionError", err)
3907 return res.text
3908
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06003909def viewLDAPConfig(host, args, session):
3910 """
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003911 Called by the ldap function. Prints out active LDAP configuration properties
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06003912
3913 @param host: string, the hostname or IP address of the bmc
3914 @param args: contains additional arguments used by the ldap subcommand
3915 args.json: boolean, if this flag is set to true, the output
3916 will be provided in json format for programmatic consumption
3917 @param session: the active session to use
3918 @return returns LDAP's configured properties.
3919 """
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003920
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06003921 try:
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003922 if (isRedfishSupport):
3923
3924 url = "https://"+host+"/xyz/openbmc_project/user/ldap/"
3925
3926 serverTypeEnabled = getLDAPTypeEnabled(host,session)
3927
3928 if (serverTypeEnabled is not None):
3929 data = {"data": []}
3930 res = session.get(url + serverTypeMap[serverTypeEnabled], headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
3931 else:
3932 return("LDAP server has not been enabled...")
3933
3934 else :
3935 url = "https://"+host+"/xyz/openbmc_project/user/ldap/config"
3936 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
3937
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06003938 except(requests.exceptions.Timeout):
3939 return(connectionErrHandler(args.json, "Timeout", None))
3940 except(requests.exceptions.ConnectionError) as err:
3941 return connectionErrHandler(args.json, "ConnectionError", err)
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06003942 if res.status_code == 404:
3943 return "LDAP server config has not been created"
3944 return res.text
3945
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003946def str2bool(v):
3947 if v.lower() in ('yes', 'true', 't', 'y', '1'):
3948 return True
3949 elif v.lower() in ('no', 'false', 'f', 'n', '0'):
3950 return False
3951 else:
3952 raise argparse.ArgumentTypeError('Boolean value expected.')
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06003953
Matt Spinler7d426c22018-09-24 14:42:07 -05003954def localUsers(host, args, session):
3955 """
3956 Enables and disables local BMC users.
3957
3958 @param host: string, the hostname or IP address of the bmc
3959 @param args: contains additional arguments used by the logging sub command
3960 @param session: the active session to use
3961 """
3962
Matt Spinler7d426c22018-09-24 14:42:07 -05003963 url="https://{hostname}/xyz/openbmc_project/user/enumerate".format(hostname=host)
3964 try:
Justin Thaler27197622019-01-23 14:42:11 -06003965 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Matt Spinler7d426c22018-09-24 14:42:07 -05003966 except(requests.exceptions.Timeout):
3967 return(connectionErrHandler(args.json, "Timeout", None))
3968 usersDict = json.loads(res.text)
3969
3970 if not usersDict['data']:
3971 return "No users found"
3972
3973 output = ""
3974 for user in usersDict['data']:
Matt Spinler015adc22018-10-23 14:30:19 -05003975
3976 # Skip LDAP and another non-local users
3977 if 'UserEnabled' not in usersDict['data'][user]:
3978 continue
3979
Matt Spinler7d426c22018-09-24 14:42:07 -05003980 name = user.split('/')[-1]
3981 url = "https://{hostname}{user}/attr/UserEnabled".format(hostname=host, user=user)
3982
3983 if args.local_users == "queryenabled":
3984 try:
Justin Thaler27197622019-01-23 14:42:11 -06003985 res = session.get(url, headers=jsonHeader,verify=False, timeout=baseTimeout)
Matt Spinler7d426c22018-09-24 14:42:07 -05003986 except(requests.exceptions.Timeout):
3987 return(connectionErrHandler(args.json, "Timeout", None))
3988
3989 result = json.loads(res.text)
3990 output += ("User: {name} Enabled: {result}\n").format(name=name, result=result['data'])
3991
3992 elif args.local_users in ["enableall", "disableall"]:
3993 action = ""
3994 if args.local_users == "enableall":
3995 data = '{"data": true}'
3996 action = "Enabling"
3997 else:
3998 data = '{"data": false}'
3999 action = "Disabling"
4000
4001 output += "{action} {name}\n".format(action=action, name=name)
4002
4003 try:
Justin Thaler27197622019-01-23 14:42:11 -06004004 resp = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Matt Spinler7d426c22018-09-24 14:42:07 -05004005 except(requests.exceptions.Timeout):
4006 return connectionErrHandler(args.json, "Timeout", None)
4007 except(requests.exceptions.ConnectionError) as err:
4008 return connectionErrHandler(args.json, "ConnectionError", err)
4009 else:
4010 return "Invalid local users argument"
4011
4012 return output
4013
Marri Devender Rao2c2a5162018-11-05 08:57:11 -06004014def setPassword(host, args, session):
4015 """
4016 Set local user password
4017 @param host: string, the hostname or IP address of the bmc
4018 @param args: contains additional arguments used by the logging sub
4019 command
4020 @param session: the active session to use
4021 @param args.json: boolean, if this flag is set to true, the output
4022 will be provided in json format for programmatic consumption
4023 @return: Session object
4024 """
Marri Devender Rao2c2a5162018-11-05 08:57:11 -06004025 try:
Sunitha Harishc99faba2019-07-19 06:55:22 -05004026 if(isRedfishSupport):
4027 url = "https://" + host + "/redfish/v1/AccountService/Accounts/"+ \
4028 args.user
4029 data = {"Password":args.password}
4030 res = session.patch(url, headers=jsonHeader, json=data,
4031 verify=False, timeout=baseTimeout)
4032 else:
4033 url = "https://" + host + "/xyz/openbmc_project/user/" + args.user + \
4034 "/action/SetPassword"
4035 res = session.post(url, headers=jsonHeader,
Marri Devender Rao2c2a5162018-11-05 08:57:11 -06004036 json={"data": [args.password]}, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06004037 timeout=baseTimeout)
Marri Devender Rao2c2a5162018-11-05 08:57:11 -06004038 except(requests.exceptions.Timeout):
4039 return(connectionErrHandler(args.json, "Timeout", None))
4040 except(requests.exceptions.ConnectionError) as err:
4041 return connectionErrHandler(args.json, "ConnectionError", err)
4042 except(requests.exceptions.RequestException) as err:
4043 return connectionErrHandler(args.json, "RequestException", err)
Sunitha Harishc99faba2019-07-19 06:55:22 -05004044 return res.status_code
Matthew Barth368e83c2019-02-01 13:48:25 -06004045
4046def getThermalZones(host, args, session):
4047 """
4048 Get the available thermal control zones
4049 @param host: string, the hostname or IP address of the bmc
4050 @param args: contains additional arguments used to get the thermal
4051 control zones
4052 @param session: the active session to use
4053 @return: Session object
4054 """
4055 url = "https://" + host + "/xyz/openbmc_project/control/thermal/enumerate"
4056
4057 try:
4058 res = session.get(url, headers=jsonHeader, verify=False, timeout=30)
4059 except(requests.exceptions.Timeout):
4060 return(connectionErrHandler(args.json, "Timeout", None))
4061 except(requests.exceptions.ConnectionError) as err:
4062 return connectionErrHandler(args.json, "ConnectionError", err)
4063 except(requests.exceptions.RequestException) as err:
4064 return connectionErrHandler(args.json, "RequestException", err)
4065
4066 if (res.status_code == 404):
Matthew Barth0939e822019-09-27 15:47:50 -05004067 return "No thermal control zones found"
Matthew Barth368e83c2019-02-01 13:48:25 -06004068
4069 zonesDict = json.loads(res.text)
4070 if not zonesDict['data']:
4071 return "No thermal control zones found"
4072 for zone in zonesDict['data']:
4073 z = ",".join(str(zone.split('/')[-1]) for zone in zonesDict['data'])
4074
4075 return "Zones: [ " + z + " ]"
4076
4077
4078def getThermalMode(host, args, session):
4079 """
4080 Get thermal control mode
4081 @param host: string, the hostname or IP address of the bmc
4082 @param args: contains additional arguments used to get the thermal
4083 control mode
4084 @param session: the active session to use
4085 @param args.zone: the zone to get the mode on
4086 @return: Session object
4087 """
4088 url = "https://" + host + "/xyz/openbmc_project/control/thermal/" + \
4089 args.zone
4090
4091 try:
4092 res = session.get(url, headers=jsonHeader, verify=False, timeout=30)
4093 except(requests.exceptions.Timeout):
4094 return(connectionErrHandler(args.json, "Timeout", None))
4095 except(requests.exceptions.ConnectionError) as err:
4096 return connectionErrHandler(args.json, "ConnectionError", err)
4097 except(requests.exceptions.RequestException) as err:
4098 return connectionErrHandler(args.json, "RequestException", err)
4099
4100 if (res.status_code == 404):
Matthew Barth0939e822019-09-27 15:47:50 -05004101 return "Thermal control zone(" + args.zone + ") not found"
Matthew Barth368e83c2019-02-01 13:48:25 -06004102
4103 propsDict = json.loads(res.text)
4104 if not propsDict['data']:
4105 return "No thermal control properties found on zone(" + args.zone + ")"
4106 curMode = "Current"
4107 supModes = "Supported"
4108 result = "\n"
4109 for prop in propsDict['data']:
4110 if (prop.casefold() == curMode.casefold()):
4111 result += curMode + " Mode: " + propsDict['data'][curMode] + "\n"
4112 if (prop.casefold() == supModes.casefold()):
4113 s = ", ".join(str(sup) for sup in propsDict['data'][supModes])
4114 result += supModes + " Modes: [ " + s + " ]\n"
4115
4116 return result
4117
4118def setThermalMode(host, args, session):
4119 """
4120 Set thermal control mode
4121 @param host: string, the hostname or IP address of the bmc
4122 @param args: contains additional arguments used for setting the thermal
4123 control mode
4124 @param session: the active session to use
4125 @param args.zone: the zone to set the mode on
4126 @param args.mode: the mode to enable
4127 @return: Session object
4128 """
4129 url = "https://" + host + "/xyz/openbmc_project/control/thermal/" + \
4130 args.zone + "/attr/Current"
4131
4132 # Check args.mode against supported modes using `getThermalMode` output
4133 modes = getThermalMode(host, args, session)
4134 modes = os.linesep.join([m for m in modes.splitlines() if m])
4135 modes = modes.replace("\n", ";").strip()
4136 modesDict = dict(m.split(': ') for m in modes.split(';'))
4137 sModes = ''.join(s for s in modesDict['Supported Modes'] if s not in '[ ]')
4138 if args.mode.casefold() not in \
4139 (m.casefold() for m in sModes.split(',')) or not args.mode:
4140 result = ("Unsupported mode('" + args.mode + "') given, " +
4141 "select a supported mode: \n" +
4142 getThermalMode(host, args, session))
4143 return result
4144
4145 data = '{"data":"' + args.mode + '"}'
4146 try:
4147 res = session.get(url, headers=jsonHeader, verify=False, timeout=30)
4148 except(requests.exceptions.Timeout):
4149 return(connectionErrHandler(args.json, "Timeout", None))
4150 except(requests.exceptions.ConnectionError) as err:
4151 return connectionErrHandler(args.json, "ConnectionError", err)
4152 except(requests.exceptions.RequestException) as err:
4153 return connectionErrHandler(args.json, "RequestException", err)
4154
4155 if (data and res.status_code != 404):
4156 try:
4157 res = session.put(url, headers=jsonHeader,
4158 data=data, verify=False,
4159 timeout=30)
4160 except(requests.exceptions.Timeout):
4161 return(connectionErrHandler(args.json, "Timeout", None))
4162 except(requests.exceptions.ConnectionError) as err:
4163 return connectionErrHandler(args.json, "ConnectionError", err)
4164 except(requests.exceptions.RequestException) as err:
4165 return connectionErrHandler(args.json, "RequestException", err)
4166
4167 if res.status_code == 403:
4168 return "The specified thermal control zone(" + args.zone + ")" + \
4169 " does not exist"
4170
4171 return res.text
4172 else:
4173 return "Setting thermal control mode(" + args.mode + ")" + \
Matthew Barth0939e822019-09-27 15:47:50 -05004174 " not supported or operation not available"
Matthew Barth368e83c2019-02-01 13:48:25 -06004175
4176
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004177def createCommandParser():
Justin Thalere412dc22018-01-12 16:28:24 -06004178 """
4179 creates the parser for the command line along with help for each command and subcommand
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004180
Justin Thalere412dc22018-01-12 16:28:24 -06004181 @return: returns the parser for the command line
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004182 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004183 parser = argparse.ArgumentParser(description='Process arguments')
Justin Thalere412dc22018-01-12 16:28:24 -06004184 parser.add_argument("-H", "--host", help='A hostname or IP for the BMC')
4185 parser.add_argument("-U", "--user", help='The username to login with')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004186 group = parser.add_mutually_exclusive_group()
4187 group.add_argument("-A", "--askpw", action='store_true', help='prompt for password')
4188 group.add_argument("-P", "--PW", help='Provide the password in-line')
Joseph Reynoldsa2d54c52019-06-11 22:02:57 -05004189 group.add_argument("-E", "--PWenvvar", action='store_true', help='Get password from envvar OPENBMCTOOL_PASSWORD')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004190 parser.add_argument('-j', '--json', action='store_true', help='output json data only')
4191 parser.add_argument('-t', '--policyTableLoc', help='The location of the policy table to parse alerts')
4192 parser.add_argument('-c', '--CerFormat', action='store_true', help=argparse.SUPPRESS)
4193 parser.add_argument('-T', '--procTime', action='store_true', help= argparse.SUPPRESS)
Justin Thalere412dc22018-01-12 16:28:24 -06004194 parser.add_argument('-V', '--version', action='store_true', help='Display the version number of the openbmctool')
4195 subparsers = parser.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004196
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004197 #fru command
4198 parser_inv = subparsers.add_parser("fru", help='Work with platform inventory')
Justin Thalere412dc22018-01-12 16:28:24 -06004199 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 -05004200 inv_subparser.required = True
4201 #fru print
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004202 inv_print = inv_subparser.add_parser("print", help="prints out a list of all FRUs")
4203 inv_print.set_defaults(func=fruPrint)
4204 #fru list [0....n]
4205 inv_list = inv_subparser.add_parser("list", help="print out details on selected FRUs. Specifying no items will list the entire inventory")
4206 inv_list.add_argument('items', nargs='?', help="print out details on selected FRUs. Specifying no items will list the entire inventory")
4207 inv_list.set_defaults(func=fruList)
4208 #fru status
4209 inv_status = inv_subparser.add_parser("status", help="prints out the status of all FRUs")
Justin Thalere412dc22018-01-12 16:28:24 -06004210 inv_status.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004211 inv_status.set_defaults(func=fruStatus)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004212
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004213 #sensors command
4214 parser_sens = subparsers.add_parser("sensors", help="Work with platform sensors")
Justin Thalere412dc22018-01-12 16:28:24 -06004215 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 -05004216 sens_subparser.required = True
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004217 #sensor print
4218 sens_print= sens_subparser.add_parser('print', help="prints out a list of all Sensors.")
4219 sens_print.set_defaults(func=sensor)
4220 #sensor list[0...n]
4221 sens_list=sens_subparser.add_parser("list", help="Lists all Sensors in the platform. Specify a sensor for full details. ")
4222 sens_list.add_argument("sensNum", nargs='?', help="The Sensor number to get full details on" )
4223 sens_list.set_defaults(func=sensor)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004224
Matthew Barth368e83c2019-02-01 13:48:25 -06004225 #thermal control commands
4226 parser_therm = subparsers.add_parser("thermal", help="Work with thermal control parameters")
4227 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')
4228 #thermal control zones
4229 parser_thermZones = therm_subparser.add_parser("zones", help="Get a list of available thermal control zones")
4230 parser_thermZones.set_defaults(func=getThermalZones)
4231 #thermal control modes
4232 parser_thermMode = therm_subparser.add_parser("modes", help="Work with thermal control modes")
4233 thermMode_sub = parser_thermMode.add_subparsers(title='subactions', description='Work with thermal control modes', help="Work with thermal control modes")
4234 #get thermal control mode
4235 parser_getThermMode = thermMode_sub.add_parser("get", help="Get current and supported thermal control modes")
4236 parser_getThermMode.add_argument('-z', '--zone', required=True, help='Thermal zone to work with')
4237 parser_getThermMode.set_defaults(func=getThermalMode)
4238 #set thermal control mode
4239 parser_setThermMode = thermMode_sub.add_parser("set", help="Set the thermal control mode")
4240 parser_setThermMode.add_argument('-z', '--zone', required=True, help='Thermal zone to work with')
4241 parser_setThermMode.add_argument('-m', '--mode', required=True, help='The supported thermal control mode')
4242 parser_setThermMode.set_defaults(func=setThermalMode)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004243
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004244 #sel command
4245 parser_sel = subparsers.add_parser("sel", help="Work with platform alerts")
Justin Thalere412dc22018-01-12 16:28:24 -06004246 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 -05004247 sel_subparser.required = True
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004248 #sel print
4249 sel_print = sel_subparser.add_parser("print", help="prints out a list of all sels in a condensed list")
4250 sel_print.add_argument('-d', '--devdebug', action='store_true', help=argparse.SUPPRESS)
4251 sel_print.add_argument('-v', '--verbose', action='store_true', help="Changes the output to being very verbose")
4252 sel_print.add_argument('-f', '--fileloc', help='Parse a file instead of the BMC output')
4253 sel_print.set_defaults(func=selPrint)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004254
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004255 #sel list
4256 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")
4257 sel_list.add_argument("selNum", nargs='?', type=int, help="The SEL entry to get details on")
4258 sel_list.set_defaults(func=selList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004259
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004260 sel_get = sel_subparser.add_parser("get", help="Gets the verbose details of a specified SEL entry")
4261 sel_get.add_argument('selNum', type=int, help="the number of the SEL entry to get")
4262 sel_get.set_defaults(func=selList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004263
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004264 sel_clear = sel_subparser.add_parser("clear", help="Clears all entries from the SEL")
4265 sel_clear.set_defaults(func=selClear)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004266
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004267 sel_setResolved = sel_subparser.add_parser("resolve", help="Sets the sel entry to resolved")
Justin Thalere412dc22018-01-12 16:28:24 -06004268 sel_setResolved.add_argument('-n', '--selNum', type=int, help="the number of the SEL entry to resolve")
4269 sel_ResolveAll_sub = sel_setResolved.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
4270 sel_ResolveAll = sel_ResolveAll_sub.add_parser('all', help='Resolve all SEL entries')
4271 sel_ResolveAll.set_defaults(func=selResolveAll)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004272 sel_setResolved.set_defaults(func=selSetResolved)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004273
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004274 parser_chassis = subparsers.add_parser("chassis", help="Work with chassis power and status")
Justin Thalere412dc22018-01-12 16:28:24 -06004275 chas_sub = parser_chassis.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004276
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004277 parser_chassis.add_argument('status', action='store_true', help='Returns the current status of the platform')
4278 parser_chassis.set_defaults(func=chassis)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004279
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004280 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 -06004281 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 -06004282 parser_chasPower.set_defaults(func=chassisPower)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004283
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004284 #control the chassis identify led
4285 parser_chasIdent = chas_sub.add_parser("identify", help="Control the chassis identify led")
4286 parser_chasIdent.add_argument('identcmd', choices=['on', 'off', 'status'], help='The control option for the led: on, off, blink, status')
4287 parser_chasIdent.set_defaults(func=chassisIdent)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004288
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004289 #collect service data
4290 parser_servData = subparsers.add_parser("collect_service_data", help="Collect all bmc data needed for service")
4291 parser_servData.add_argument('-d', '--devdebug', action='store_true', help=argparse.SUPPRESS)
4292 parser_servData.set_defaults(func=collectServiceData)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004293
Justin Thalere412dc22018-01-12 16:28:24 -06004294 #system quick health check
4295 parser_healthChk = subparsers.add_parser("health_check", help="Work with platform sensors")
4296 parser_healthChk.set_defaults(func=healthCheck)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004297
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004298 #work with bmc dumps
4299 parser_bmcdump = subparsers.add_parser("dump", help="Work with bmc dump files")
Justin Thalere412dc22018-01-12 16:28:24 -06004300 bmcDump_sub = parser_bmcdump.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Justin Thaler53bf2f12018-07-16 14:05:32 -05004301 bmcDump_sub.required = True
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004302 dump_Create = bmcDump_sub.add_parser('create', help="Create a bmc dump")
4303 dump_Create.set_defaults(func=bmcDumpCreate)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004304
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004305 dump_list = bmcDump_sub.add_parser('list', help="list all bmc dump files")
4306 dump_list.set_defaults(func=bmcDumpList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004307
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004308 parserdumpdelete = bmcDump_sub.add_parser('delete', help="Delete bmc dump files")
4309 parserdumpdelete.add_argument("-n", "--dumpNum", nargs='*', type=int, help="The Dump entry to delete")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004310 parserdumpdelete.set_defaults(func=bmcDumpDelete)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004311
Justin Thalere412dc22018-01-12 16:28:24 -06004312 bmcDumpDelsub = parserdumpdelete.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004313 deleteAllDumps = bmcDumpDelsub.add_parser('all', help='Delete all bmc dump files')
4314 deleteAllDumps.set_defaults(func=bmcDumpDeleteAll)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004315
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004316 parser_dumpretrieve = bmcDump_sub.add_parser('retrieve', help='Retrieve a dump file')
4317 parser_dumpretrieve.add_argument("dumpNum", type=int, help="The Dump entry to delete")
4318 parser_dumpretrieve.add_argument("-s", "--dumpSaveLoc", help="The location to save the bmc dump file")
4319 parser_dumpretrieve.set_defaults(func=bmcDumpRetrieve)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004320
Justin Thaler22b1bb52018-03-15 13:31:32 -05004321 #bmc command for reseting the bmc
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004322 parser_bmc = subparsers.add_parser('bmc', help="Work with the bmc")
Justin Thalere412dc22018-01-12 16:28:24 -06004323 bmc_sub = parser_bmc.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004324 parser_BMCReset = bmc_sub.add_parser('reset', help='Reset the bmc' )
4325 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 -06004326 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.")
4327 parser_bmc.set_defaults(func=bmc)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004328
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004329 #add alias to the bmc command
4330 parser_mc = subparsers.add_parser('mc', help="Work with the management controller")
Justin Thalere412dc22018-01-12 16:28:24 -06004331 mc_sub = parser_mc.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004332 parser_MCReset = mc_sub.add_parser('reset', help='Reset the bmc' )
4333 parser_MCReset.add_argument('type', choices=['warm','cold'], help="Reboot the BMC")
4334 #parser_MCReset.add_argument('cold', action='store_true', help="Reboot the BMC and CLEAR the configuration")
4335 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 -06004336 parser_MCReset.set_defaults(func=bmcReset)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004337 parser_mc.set_defaults(func=bmc)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004338
Justin Thalere412dc22018-01-12 16:28:24 -06004339 #gard clear
4340 parser_gc = subparsers.add_parser("gardclear", help="Used to clear gard records")
4341 parser_gc.set_defaults(func=gardClear)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004342
Justin Thalere412dc22018-01-12 16:28:24 -06004343 #firmware_flash
4344 parser_fw = subparsers.add_parser("firmware", help="Work with the system firmware")
4345 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 -05004346 fwflash_subproc.required = True
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004347
Justin Thalere412dc22018-01-12 16:28:24 -06004348 fwflash = fwflash_subproc.add_parser('flash', help="Flash the system firmware")
4349 fwflash.add_argument('type', choices=['bmc', 'pnor'], help="image type to flash")
4350 fwflash.add_argument('-f', '--fileloc', required=True, help="The absolute path to the firmware image")
4351 fwflash.set_defaults(func=fwFlash)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004352
Justin Thaler22b1bb52018-03-15 13:31:32 -05004353 fwActivate = fwflash_subproc.add_parser('activate', help="Activate existing image on the bmc")
Justin Thalere412dc22018-01-12 16:28:24 -06004354 fwActivate.add_argument('imageID', help="The image ID to activate from the firmware list. Ex: 63c95399")
4355 fwActivate.set_defaults(func=activateFWImage)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004356
Justin Thaler22b1bb52018-03-15 13:31:32 -05004357 fwActivateStatus = fwflash_subproc.add_parser('activation_status', help="Check Status of activations")
4358 fwActivateStatus.set_defaults(func=activateStatus)
4359
Justin Thaler3d71d402018-07-24 14:35:39 -05004360 fwList = fwflash_subproc.add_parser('list', help="List all of the installed firmware")
4361 fwList.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
4362 fwList.set_defaults(func=firmwareList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004363
Justin Thaler3d71d402018-07-24 14:35:39 -05004364 fwprint = fwflash_subproc.add_parser('print', help="List all of the installed firmware")
4365 fwprint.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
4366 fwprint.set_defaults(func=firmwareList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004367
Adriana Kobylak5af2fad2018-11-08 12:33:43 -06004368 fwDelete = fwflash_subproc.add_parser('delete', help="Delete an existing firmware version")
4369 fwDelete.add_argument('versionID', help="The version ID to delete from the firmware list. Ex: 63c95399")
4370 fwDelete.set_defaults(func=deleteFWVersion)
4371
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05004372 #logging
4373 parser_logging = subparsers.add_parser("logging", help="logging controls")
4374 logging_sub = parser_logging.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004375
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05004376 #turn rest api logging on/off
4377 parser_rest_logging = logging_sub.add_parser("rest_api", help="turn rest api logging on/off")
4378 parser_rest_logging.add_argument('rest_logging', choices=['on', 'off'], help='The control option for rest logging: on, off')
4379 parser_rest_logging.set_defaults(func=restLogging)
Deepak Kodihalli02d53282018-09-18 06:53:31 -05004380
4381 #remote logging
4382 parser_remote_logging = logging_sub.add_parser("remote_logging", help="Remote logging (rsyslog) commands")
4383 parser_remote_logging.add_argument('remote_logging', choices=['view', 'disable'], help='Remote logging (rsyslog) commands')
4384 parser_remote_logging.set_defaults(func=remoteLogging)
4385
4386 #configure remote logging
4387 parser_remote_logging_config = logging_sub.add_parser("remote_logging_config", help="Configure remote logging (rsyslog)")
4388 parser_remote_logging_config.add_argument("-a", "--address", required=True, help="Set IP address of rsyslog server")
4389 parser_remote_logging_config.add_argument("-p", "--port", required=True, type=int, help="Set Port of rsyslog server")
4390 parser_remote_logging_config.set_defaults(func=remoteLoggingConfig)
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05004391
4392 #certificate management
4393 parser_cert = subparsers.add_parser("certificate", help="Certificate management")
4394 certMgmt_subproc = parser_cert.add_subparsers(title='subcommands', description='valid certificate commands', help='sub-command help', dest='command')
4395
4396 certUpdate = certMgmt_subproc.add_parser('update', help="Update the certificate")
4397 certUpdate.add_argument('type', choices=['server', 'client', 'authority'], help="certificate type to update")
4398 certUpdate.add_argument('service', choices=['https', 'ldap'], help="Service to update")
4399 certUpdate.add_argument('-f', '--fileloc', required=True, help="The absolute path to the certificate file")
4400 certUpdate.set_defaults(func=certificateUpdate)
4401
4402 certDelete = certMgmt_subproc.add_parser('delete', help="Delete the certificate")
4403 certDelete.add_argument('type', choices=['server', 'client', 'authority'], help="certificate type to delete")
4404 certDelete.add_argument('service', choices=['https', 'ldap'], help="Service to delete the certificate")
4405 certDelete.set_defaults(func=certificateDelete)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004406
Marri Devender Raodfe81ad2019-07-01 05:38:09 -05004407 certReplace = certMgmt_subproc.add_parser('replace',
4408 help="Replace the certificate")
4409 certReplace.add_argument('type', choices=['server', 'client', 'authority'],
4410 help="certificate type to replace")
4411 certReplace.add_argument('service', choices=['https', 'ldap'],
4412 help="Service to replace the certificate")
4413 certReplace.add_argument('-f', '--fileloc', required=True,
4414 help="The absolute path to the certificate file")
4415 certReplace.set_defaults(func=certificateReplace)
4416
Marri Devender Rao34646402019-07-01 05:46:03 -05004417 certDisplay = certMgmt_subproc.add_parser('display',
4418 help="Print the certificate")
4419 certDisplay.add_argument('type', choices=['server', 'client', 'authority'],
4420 help="certificate type to display")
4421 certDisplay.set_defaults(func=certificateDisplay)
4422
Marri Devender Raoa208ff82019-07-01 05:51:27 -05004423 certList = certMgmt_subproc.add_parser('list',
4424 help="Certificate list")
4425 certList.set_defaults(func=certificateList)
4426
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05004427 certGenerateCSR = certMgmt_subproc.add_parser('generatecsr', help="Generate CSR")
4428 certGenerateCSR.add_argument('type', choices=['server', 'client', 'authority'],
4429 help="Generate CSR")
4430 certGenerateCSR.add_argument('city',
4431 help="The city or locality of the organization making the request")
4432 certGenerateCSR.add_argument('commonName',
4433 help="The fully qualified domain name of the component that is being secured.")
4434 certGenerateCSR.add_argument('country',
4435 help="The country of the organization making the request")
4436 certGenerateCSR.add_argument('organization',
4437 help="The name of the organization making the request.")
4438 certGenerateCSR.add_argument('organizationUnit',
4439 help="The name of the unit or division of the organization making the request.")
4440 certGenerateCSR.add_argument('state',
4441 help="The state, province, or region of the organization making the request.")
4442 certGenerateCSR.add_argument('keyPairAlgorithm', choices=['RSA', 'EC'],
4443 help="The type of key pair for use with signing algorithms.")
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05004444 certGenerateCSR.add_argument('keyCurveId',
4445 help="The curve ID to be used with the key, if needed based on the value of the 'KeyPairAlgorithm' parameter.")
4446 certGenerateCSR.add_argument('contactPerson',
4447 help="The name of the user making the request")
4448 certGenerateCSR.add_argument('email',
4449 help="The email address of the contact within the organization")
4450 certGenerateCSR.add_argument('alternativeNames',
4451 help="Additional hostnames of the component that is being secured")
4452 certGenerateCSR.add_argument('givenname',
4453 help="The given name of the user making the request")
4454 certGenerateCSR.add_argument('surname',
4455 help="The surname of the user making the request")
4456 certGenerateCSR.add_argument('unstructuredname',
4457 help="he unstructured name of the subject")
4458 certGenerateCSR.add_argument('initials',
4459 help="The initials of the user making the request")
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05004460 certGenerateCSR.set_defaults(func=certificateGenerateCSR)
4461
Matt Spinler7d426c22018-09-24 14:42:07 -05004462 # local users
4463 parser_users = subparsers.add_parser("local_users", help="Work with local users")
4464 parser_users.add_argument('local_users', choices=['disableall','enableall', 'queryenabled'], help="Disable, enable or query local user accounts")
4465 parser_users.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
4466 parser_users.set_defaults(func=localUsers)
4467
Ratan Gupta9166cd22018-10-01 18:09:40 +05304468 #LDAP
4469 parser_ldap = subparsers.add_parser("ldap", help="LDAP controls")
4470 ldap_sub = parser_ldap.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
4471
4472 #configure and enable LDAP
4473 parser_ldap_config = ldap_sub.add_parser("enable", help="Configure and enables the LDAP")
4474 parser_ldap_config.add_argument("-a", "--uri", required=True, help="Set LDAP server URI")
4475 parser_ldap_config.add_argument("-B", "--bindDN", required=True, help="Set the bind DN of the LDAP server")
4476 parser_ldap_config.add_argument("-b", "--baseDN", required=True, help="Set the base DN of the LDAP server")
4477 parser_ldap_config.add_argument("-p", "--bindPassword", required=True, help="Set the bind password of the LDAP server")
4478 parser_ldap_config.add_argument("-S", "--scope", choices=['sub','one', 'base'],
4479 help='Specifies the search scope:subtree, one level or base object.')
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004480 parser_ldap_config.add_argument("-t", "--serverType", required=True, choices=['ActiveDirectory','OpenLDAP'],
Ratan Gupta9166cd22018-10-01 18:09:40 +05304481 help='Specifies the configured server is ActiveDirectory(AD) or OpenLdap')
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004482 parser_ldap_config.add_argument("-g","--groupAttrName", required=False, default='', help="Group Attribute Name")
4483 parser_ldap_config.add_argument("-u","--userAttrName", required=False, default='', help="User Attribute Name")
4484 parser_ldap_config.set_defaults(func=enableLDAPConfig)
Ratan Gupta9166cd22018-10-01 18:09:40 +05304485
4486 # disable LDAP
4487 parser_disable_ldap = ldap_sub.add_parser("disable", help="disables the LDAP")
4488 parser_disable_ldap.set_defaults(func=disableLDAP)
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06004489 # view-config
4490 parser_ldap_config = \
4491 ldap_sub.add_parser("view-config", help="prints out a list of all \
4492 LDAPS's configured properties")
4493 parser_ldap_config.set_defaults(func=viewLDAPConfig)
Ratan Gupta9166cd22018-10-01 18:09:40 +05304494
Ratan Guptafeee6372018-10-17 23:25:51 +05304495 #create group privilege mapping
4496 parser_ldap_mapper = ldap_sub.add_parser("privilege-mapper", help="LDAP group privilege controls")
4497 parser_ldap_mapper_sub = parser_ldap_mapper.add_subparsers(title='subcommands', description='valid subcommands',
4498 help="sub-command help", dest='command')
4499
4500 parser_ldap_mapper_create = parser_ldap_mapper_sub.add_parser("create", help="Create mapping of ldap group and privilege")
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004501 parser_ldap_mapper_create.add_argument("-t", "--serverType", choices=['ActiveDirectory','OpenLDAP'],
4502 help='Specifies the configured server is ActiveDirectory(AD) or OpenLdap')
Ratan Guptafeee6372018-10-17 23:25:51 +05304503 parser_ldap_mapper_create.add_argument("-g","--groupName",required=True,help="Group Name")
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004504 parser_ldap_mapper_create.add_argument("-p","--privilege",choices=['priv-admin','priv-operator','priv-user','priv-callback'],required=True,help="Privilege")
Ratan Guptafeee6372018-10-17 23:25:51 +05304505 parser_ldap_mapper_create.set_defaults(func=createPrivilegeMapping)
4506
4507 #list group privilege mapping
4508 parser_ldap_mapper_list = parser_ldap_mapper_sub.add_parser("list",help="List privilege mapping")
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004509 parser_ldap_mapper_list.add_argument("-t", "--serverType", choices=['ActiveDirectory','OpenLDAP'],
4510 help='Specifies the configured server is ActiveDirectory(AD) or OpenLdap')
Ratan Guptafeee6372018-10-17 23:25:51 +05304511 parser_ldap_mapper_list.set_defaults(func=listPrivilegeMapping)
4512
4513 #delete group privilege mapping
4514 parser_ldap_mapper_delete = parser_ldap_mapper_sub.add_parser("delete",help="Delete privilege mapping")
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004515 parser_ldap_mapper_delete.add_argument("-t", "--serverType", choices=['ActiveDirectory','OpenLDAP'],
4516 help='Specifies the configured server is ActiveDirectory(AD) or OpenLdap')
Ratan Guptafeee6372018-10-17 23:25:51 +05304517 parser_ldap_mapper_delete.add_argument("-g","--groupName",required=True,help="Group Name")
4518 parser_ldap_mapper_delete.set_defaults(func=deletePrivilegeMapping)
4519
Sivas SRR78835272018-11-27 05:27:19 -06004520 #deleteAll group privilege mapping
4521 parser_ldap_mapper_delete = parser_ldap_mapper_sub.add_parser("purge",help="Delete All privilege mapping")
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004522 parser_ldap_mapper_delete.add_argument("-t", "--serverType", choices=['ActiveDirectory','OpenLDAP'],
4523 help='Specifies the configured server is ActiveDirectory(AD) or OpenLdap')
Sivas SRR78835272018-11-27 05:27:19 -06004524 parser_ldap_mapper_delete.set_defaults(func=deleteAllPrivilegeMapping)
4525
Marri Devender Rao2c2a5162018-11-05 08:57:11 -06004526 # set local user password
4527 parser_set_password = subparsers.add_parser("set_password",
4528 help="Set password of local user")
4529 parser_set_password.add_argument( "-p", "--password", required=True,
4530 help="Password of local user")
4531 parser_set_password.set_defaults(func=setPassword)
4532
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004533 # network
4534 parser_nw = subparsers.add_parser("network", help="network controls")
4535 nw_sub = parser_nw.add_subparsers(title='subcommands',
4536 description='valid subcommands',
4537 help="sub-command help",
4538 dest='command')
4539
4540 # enable DHCP
4541 parser_enable_dhcp = nw_sub.add_parser("enableDHCP",
4542 help="enables the DHCP on given "
4543 "Interface")
4544 parser_enable_dhcp.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004545 help="Name of the ethernet interface(it can"
4546 "be obtained by the "
4547 "command:network view-config)"
4548 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004549 parser_enable_dhcp.set_defaults(func=enableDHCP)
4550
4551 # disable DHCP
4552 parser_disable_dhcp = nw_sub.add_parser("disableDHCP",
4553 help="disables the DHCP on given "
4554 "Interface")
4555 parser_disable_dhcp.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004556 help="Name of the ethernet interface(it can"
4557 "be obtained by the "
4558 "command:network view-config)"
4559 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004560 parser_disable_dhcp.set_defaults(func=disableDHCP)
4561
4562 # get HostName
4563 parser_gethostname = nw_sub.add_parser("getHostName",
4564 help="prints out HostName")
4565 parser_gethostname.set_defaults(func=getHostname)
4566
4567 # set HostName
4568 parser_sethostname = nw_sub.add_parser("setHostName", help="sets HostName")
4569 parser_sethostname.add_argument("-H", "--HostName", required=True,
4570 help="A HostName for the BMC")
4571 parser_sethostname.set_defaults(func=setHostname)
4572
4573 # get domainname
4574 parser_getdomainname = nw_sub.add_parser("getDomainName",
4575 help="prints out DomainName of "
4576 "given Interface")
4577 parser_getdomainname.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004578 help="Name of the ethernet interface(it "
4579 "can be obtained by the "
4580 "command:network view-config)"
4581 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004582 parser_getdomainname.set_defaults(func=getDomainName)
4583
4584 # set domainname
4585 parser_setdomainname = nw_sub.add_parser("setDomainName",
4586 help="sets DomainName of given "
4587 "Interface")
4588 parser_setdomainname.add_argument("-D", "--DomainName", required=True,
4589 help="Ex: DomainName=Domain1,Domain2,...")
4590 parser_setdomainname.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004591 help="Name of the ethernet interface(it "
4592 "can be obtained by the "
4593 "command:network view-config)"
4594 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004595 parser_setdomainname.set_defaults(func=setDomainName)
4596
4597 # get MACAddress
4598 parser_getmacaddress = nw_sub.add_parser("getMACAddress",
4599 help="prints out MACAddress the "
4600 "given Interface")
4601 parser_getmacaddress.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004602 help="Name of the ethernet interface(it "
4603 "can be obtained by the "
4604 "command:network view-config)"
4605 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004606 parser_getmacaddress.set_defaults(func=getMACAddress)
4607
4608 # set MACAddress
4609 parser_setmacaddress = nw_sub.add_parser("setMACAddress",
4610 help="sets MACAddress")
4611 parser_setmacaddress.add_argument("-MA", "--MACAddress", required=True,
4612 help="A MACAddress for the given "
4613 "Interface")
4614 parser_setmacaddress.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004615 help="Name of the ethernet interface(it can"
4616 "be obtained by the "
4617 "command:network view-config)"
4618 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004619 parser_setmacaddress.set_defaults(func=setMACAddress)
4620
4621 # get DefaultGW
4622 parser_getdefaultgw = nw_sub.add_parser("getDefaultGW",
4623 help="prints out DefaultGateway "
4624 "the BMC")
4625 parser_getdefaultgw.set_defaults(func=getDefaultGateway)
4626
4627 # set DefaultGW
4628 parser_setdefaultgw = nw_sub.add_parser("setDefaultGW",
4629 help="sets DefaultGW")
4630 parser_setdefaultgw.add_argument("-GW", "--DefaultGW", required=True,
4631 help="A DefaultGateway for the BMC")
4632 parser_setdefaultgw.set_defaults(func=setDefaultGateway)
4633
4634 # view network Config
4635 parser_ldap_config = nw_sub.add_parser("view-config", help="prints out a "
4636 "list of all network's configured "
4637 "properties")
4638 parser_ldap_config.set_defaults(func=viewNWConfig)
4639
4640 # get DNS
4641 parser_getDNS = nw_sub.add_parser("getDNS",
4642 help="prints out DNS servers on the "
4643 "given interface")
4644 parser_getDNS.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004645 help="Name of the ethernet interface(it can"
4646 "be obtained by the "
4647 "command:network view-config)"
4648 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004649 parser_getDNS.set_defaults(func=getDNS)
4650
4651 # set DNS
4652 parser_setDNS = nw_sub.add_parser("setDNS",
4653 help="sets DNS servers on the given "
4654 "interface")
4655 parser_setDNS.add_argument("-d", "--DNSServers", required=True,
4656 help="Ex: DNSSERVERS=DNS1,DNS2,...")
4657 parser_setDNS.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004658 help="Name of the ethernet interface(it can"
4659 "be obtained by the "
4660 "command:network view-config)"
4661 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004662 parser_setDNS.set_defaults(func=setDNS)
4663
4664 # get NTP
4665 parser_getNTP = nw_sub.add_parser("getNTP",
4666 help="prints out NTP servers on the "
4667 "given interface")
4668 parser_getNTP.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004669 help="Name of the ethernet interface(it can"
4670 "be obtained by the "
4671 "command:network view-config)"
4672 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004673 parser_getNTP.set_defaults(func=getNTP)
4674
4675 # set NTP
4676 parser_setNTP = nw_sub.add_parser("setNTP",
4677 help="sets NTP servers on the given "
4678 "interface")
4679 parser_setNTP.add_argument("-N", "--NTPServers", required=True,
4680 help="Ex: NTPSERVERS=NTP1,NTP2,...")
4681 parser_setNTP.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004682 help="Name of the ethernet interface(it can"
4683 "be obtained by the "
4684 "command:network view-config)"
4685 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004686 parser_setNTP.set_defaults(func=setNTP)
4687
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004688 # configure IP
4689 parser_ip_config = nw_sub.add_parser("addIP", help="Sets IP address to"
4690 "given interface")
4691 parser_ip_config.add_argument("-a", "--address", required=True,
4692 help="IP address of given interface")
4693 parser_ip_config.add_argument("-gw", "--gateway", required=False, default='',
4694 help="The gateway for given interface")
4695 parser_ip_config.add_argument("-l", "--prefixLength", required=True,
4696 help="The prefixLength of IP address")
Sunitha Harish0baf6372019-07-31 03:59:03 -05004697 parser_ip_config.add_argument("-p", "--type", required=True,
4698 choices=['ipv4', 'ipv6'],
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004699 help="The protocol type of the given"
4700 "IP address")
4701 parser_ip_config.add_argument("-I", "--Interface", required=True,
4702 help="Name of the ethernet interface(it can"
4703 "be obtained by the "
4704 "command:network view-config)"
4705 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
4706 parser_ip_config.set_defaults(func=addIP)
4707
4708 # getIP
4709 parser_getIP = nw_sub.add_parser("getIP", help="prints out IP address"
4710 "of given interface")
4711 parser_getIP.add_argument("-I", "--Interface", required=True,
4712 help="Name of the ethernet interface(it can"
4713 "be obtained by the command:network view-config)"
4714 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
4715 parser_getIP.set_defaults(func=getIP)
4716
4717 # rmIP
4718 parser_rmIP = nw_sub.add_parser("rmIP", help="deletes IP address"
4719 "of given interface")
4720 parser_rmIP.add_argument("-a", "--address", required=True,
4721 help="IP address to remove form given Interface")
4722 parser_rmIP.add_argument("-I", "--Interface", required=True,
4723 help="Name of the ethernet interface(it can"
4724 "be obtained by the command:network view-config)"
4725 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
4726 parser_rmIP.set_defaults(func=deleteIP)
4727
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004728 # add VLAN
4729 parser_create_vlan = nw_sub.add_parser("addVLAN", help="enables VLAN "
4730 "on given interface with given "
4731 "VLAN Identifier")
4732 parser_create_vlan.add_argument("-I", "--Interface", required=True,
4733 choices=['eth0', 'eth1'],
4734 help="Name of the ethernet interface")
4735 parser_create_vlan.add_argument("-n", "--Identifier", required=True,
4736 help="VLAN Identifier")
4737 parser_create_vlan.set_defaults(func=addVLAN)
4738
4739 # delete VLAN
4740 parser_delete_vlan = nw_sub.add_parser("deleteVLAN", help="disables VLAN "
4741 "on given interface with given "
4742 "VLAN Identifier")
4743 parser_delete_vlan.add_argument("-I", "--Interface", required=True,
4744 help="Name of the ethernet interface(it can"
4745 "be obtained by the "
4746 "command:network view-config)"
4747 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
4748 parser_delete_vlan.set_defaults(func=deleteVLAN)
4749
4750 # viewDHCPConfig
4751 parser_viewDHCPConfig = nw_sub.add_parser("viewDHCPConfig",
4752 help="Shows DHCP configured "
4753 "Properties")
4754 parser_viewDHCPConfig.set_defaults(func=viewDHCPConfig)
4755
4756 # configureDHCP
4757 parser_configDHCP = nw_sub.add_parser("configureDHCP",
4758 help="Configures/updates DHCP "
4759 "Properties")
4760 parser_configDHCP.add_argument("-d", "--DNSEnabled", type=str2bool,
4761 required=True, help="Sets DNSEnabled property")
4762 parser_configDHCP.add_argument("-n", "--HostNameEnabled", type=str2bool,
4763 required=True,
4764 help="Sets HostNameEnabled property")
4765 parser_configDHCP.add_argument("-t", "--NTPEnabled", type=str2bool,
4766 required=True,
4767 help="Sets NTPEnabled property")
4768 parser_configDHCP.add_argument("-s", "--SendHostNameEnabled", type=str2bool,
4769 required=True,
4770 help="Sets SendHostNameEnabled property")
4771 parser_configDHCP.set_defaults(func=configureDHCP)
4772
4773 # network factory reset
4774 parser_nw_reset = nw_sub.add_parser("nwReset",
4775 help="Resets networks setting to "
4776 "factory defaults. "
4777 "note:Reset settings will be applied "
4778 "after BMC reboot")
4779 parser_nw_reset.set_defaults(func=nwReset)
4780
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004781 return parser
4782
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004783def main(argv=None):
Justin Thalere412dc22018-01-12 16:28:24 -06004784 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004785 main function for running the command line utility as a sub application
4786 """
4787 global toolVersion
Joy Onyerikwu182c3a32019-10-15 08:33:59 -05004788 toolVersion = "1.18"
Sunitha Harishc99faba2019-07-19 06:55:22 -05004789 global isRedfishSupport
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004790
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004791 parser = createCommandParser()
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004792 args = parser.parse_args(argv)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004793
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004794 totTimeStart = int(round(time.time()*1000))
4795
4796 if(sys.version_info < (3,0)):
4797 urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
4798 if sys.version_info >= (3,0):
4799 requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)
Justin Thalere412dc22018-01-12 16:28:24 -06004800 if (args.version):
Justin Thaler22b1bb52018-03-15 13:31:32 -05004801 print("Version: "+ toolVersion)
Justin Thalere412dc22018-01-12 16:28:24 -06004802 sys.exit(0)
4803 if (hasattr(args, 'fileloc') and args.fileloc is not None and 'print' in args.command):
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004804 mysess = None
Justin Thalere412dc22018-01-12 16:28:24 -06004805 print(selPrint('N/A', args, mysess))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004806 else:
Justin Thalere412dc22018-01-12 16:28:24 -06004807 if(hasattr(args, 'host') and hasattr(args,'user')):
4808 if (args.askpw):
4809 pw = getpass.getpass()
4810 elif(args.PW is not None):
4811 pw = args.PW
Joseph Reynoldsa2d54c52019-06-11 22:02:57 -05004812 elif(args.PWenvvar):
4813 pw = os.environ['OPENBMCTOOL_PASSWORD']
Justin Thalere412dc22018-01-12 16:28:24 -06004814 else:
4815 print("You must specify a password")
4816 sys.exit()
4817 logintimeStart = int(round(time.time()*1000))
Joy Onyerikwu182c3a32019-10-15 08:33:59 -05004818 mysess = login(args.host, args.user, pw, args.json,
4819 args.command == 'set_password')
Sunitha Harish336cda22019-07-23 02:02:52 -05004820 if(mysess == None):
4821 print("Login Failed!")
4822 sys.exit()
Justin Thalera9415b42018-05-25 19:40:13 -05004823 if(sys.version_info < (3,0)):
4824 if isinstance(mysess, basestring):
4825 print(mysess)
4826 sys.exit(1)
4827 elif sys.version_info >= (3,0):
4828 if isinstance(mysess, str):
4829 print(mysess)
4830 sys.exit(1)
Justin Thalere412dc22018-01-12 16:28:24 -06004831 logintimeStop = int(round(time.time()*1000))
Sunitha Harishc99faba2019-07-19 06:55:22 -05004832 isRedfishSupport = redfishSupportPresent(args.host,mysess)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004833 commandTimeStart = int(round(time.time()*1000))
Justin Thalere412dc22018-01-12 16:28:24 -06004834 output = args.func(args.host, args, mysess)
4835 commandTimeStop = int(round(time.time()*1000))
Justin Thaler761484a2019-03-26 19:20:23 -05004836 if isinstance(output, dict):
4837 print(json.dumps(output, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False))
4838 else:
4839 print(output)
Justin Thalere412dc22018-01-12 16:28:24 -06004840 if (mysess is not None):
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004841 logout(args.host, args.user, pw, mysess, args.json)
4842 if(args.procTime):
Justin Thalere412dc22018-01-12 16:28:24 -06004843 print("Total time: " + str(int(round(time.time()*1000))- totTimeStart))
4844 print("loginTime: " + str(logintimeStop - logintimeStart))
4845 print("command Time: " + str(commandTimeStop - commandTimeStart))
4846 else:
Joseph Reynoldsa2d54c52019-06-11 22:02:57 -05004847 print("usage:\n"
4848 " OPENBMCTOOL_PASSWORD=secret # if using -E\n"
4849 " openbmctool.py [-h] -H HOST -U USER {-A | -P PW | -E} [-j]\n" +
Justin Thalere412dc22018-01-12 16:28:24 -06004850 "\t[-t POLICYTABLELOC] [-V]\n" +
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05004851 "\t{fru,sensors,sel,chassis,collect_service_data, \
4852 health_check,dump,bmc,mc,gardclear,firmware,logging}\n" +
Justin Thalere412dc22018-01-12 16:28:24 -06004853 "\t...\n" +
4854 "openbmctool.py: error: the following arguments are required: -H/--host, -U/--user")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004855 sys.exit()
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004856
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004857if __name__ == '__main__':
Justin Thalere412dc22018-01-12 16:28:24 -06004858 """
4859 main function when called from the command line
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004860
4861 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004862 import sys
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004863
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004864 isTTY = sys.stdout.isatty()
4865 assert sys.version_info >= (2,7)
4866 main()