blob: f93c7c241874f48e6072d55c63d3b67a02353bac [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
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600260def login(host, username, pw,jsonFormat):
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.
Justin Thalere412dc22018-01-12 16:28:24 -0600268 @return: Session object
269 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600270 if(jsonFormat==False):
271 print("Attempting login...")
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600272 mysess = requests.session()
273 try:
Justin Thaler27197622019-01-23 14:42:11 -0600274 r = mysess.post('https://'+host+'/login', headers=jsonHeader, json = {"data": [username, pw]}, verify=False, timeout=baseTimeout)
Sunitha Harish336cda22019-07-23 02:02:52 -0500275 if r.status_code == 200:
276 cookie = r.headers['Set-Cookie']
277 match = re.search('SESSION=(\w+);', cookie)
278 if match:
279 xAuthHeader['X-Auth-Token'] = match.group(1)
280 jsonHeader.update(xAuthHeader)
281 loginMessage = json.loads(r.text)
282 if (loginMessage['status'] != "ok"):
283 print(loginMessage["data"]["description"].encode('utf-8'))
284 sys.exit(1)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600285# if(sys.version_info < (3,0)):
286# urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
287# if sys.version_info >= (3,0):
288# requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)
Sunitha Harish336cda22019-07-23 02:02:52 -0500289 return mysess
290 else:
291 return None
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600292 except(requests.exceptions.Timeout):
Justin Thaler115bca72018-05-25 19:29:08 -0500293 return (connectionErrHandler(jsonFormat, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600294 except(requests.exceptions.ConnectionError) as err:
Justin Thaler115bca72018-05-25 19:29:08 -0500295 return (connectionErrHandler(jsonFormat, "ConnectionError", err))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600296
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600297
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600298def logout(host, username, pw, session, jsonFormat):
Justin Thalere412dc22018-01-12 16:28:24 -0600299 """
300 Logs out of the bmc and terminates the session
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600301
Justin Thalere412dc22018-01-12 16:28:24 -0600302 @param host: string, the hostname or IP address of the bmc to log out of
303 @param username: The user name for the bmc to log out of
304 @param pw: The password for the BMC to log out of
305 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600306 @param jsonFormat: boolean, flag that will only allow relevant data from user command to be display. This function becomes silent when set to true.
307 """
Justin Thalere412dc22018-01-12 16:28:24 -0600308 try:
Justin Thaler27197622019-01-23 14:42:11 -0600309 r = session.post('https://'+host+'/logout', headers=jsonHeader,json = {"data": [username, pw]}, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600310 except(requests.exceptions.Timeout):
311 print(connectionErrHandler(jsonFormat, "Timeout", None))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600312
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600313 if(jsonFormat==False):
Matt Spinlereae05b02019-01-24 12:59:34 -0600314 if r.status_code == 200:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600315 print('User ' +username + ' has been logged out')
316
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600317
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600318def fru(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -0600319 """
320 prints out the system inventory. deprecated see fruPrint and fruList
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600321
Justin Thalere412dc22018-01-12 16:28:24 -0600322 @param host: string, the hostname or IP address of the bmc
323 @param args: contains additional arguments used by the fru sub command
324 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600325 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
326 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600327 #url="https://"+host+"/org/openbmc/inventory/system/chassis/enumerate"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600328
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600329 #print(url)
330 #res = session.get(url, headers=httpHeader, verify=False)
331 #print(res.text)
332 #sample = res.text
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600333
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600334 #inv_list = json.loads(sample)["data"]
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600335
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600336 url="https://"+host+"/xyz/openbmc_project/inventory/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600337 try:
Justin Thaler27197622019-01-23 14:42:11 -0600338 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600339 except(requests.exceptions.Timeout):
340 return(connectionErrHandler(args.json, "Timeout", None))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600341
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600342 sample = res.text
343# inv_list.update(json.loads(sample)["data"])
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600344#
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600345# #determine column width's
346# colNames = ["FRU Name", "FRU Type", "Has Fault", "Is FRU", "Present", "Version"]
347# colWidths = setColWidth(["FRU Name", "fru_type", "fault", "is_fru", "present", "version"], 6, inv_list, colNames)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600348#
349# 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 -0600350# "Present".ljust(colWidths[4]) + "Version".ljust(colWidths[5]))
351# format the output
352# for key in sorted(inv_list.keys()):
353# keyParts = key.split("/")
354# isFRU = "True" if (inv_list[key]["is_fru"]==1) else "False"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600355#
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600356# fruEntry = (keyParts[len(keyParts) - 1].ljust(colWidths[0]) + inv_list[key]["fru_type"].ljust(colWidths[1])+
357# inv_list[key]["fault"].ljust(colWidths[2])+isFRU.ljust(colWidths[3])+
358# inv_list[key]["present"].ljust(colWidths[4])+ inv_list[key]["version"].ljust(colWidths[5]))
359# if(isTTY):
360# if(inv_list[key]["is_fru"] == 1):
361# color = "green"
362# bold = True
363# else:
364# color='black'
365# bold = False
366# fruEntry = hilight(fruEntry, color, bold)
367# print (fruEntry)
368 return sample
Justin Thalere412dc22018-01-12 16:28:24 -0600369
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600370def fruPrint(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -0600371 """
372 prints out all inventory
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600373
Justin Thalere412dc22018-01-12 16:28:24 -0600374 @param host: string, the hostname or IP address of the bmc
375 @param args: contains additional arguments used by the fru sub command
376 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600377 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
378 @return returns the total fru list.
379 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600380 url="https://"+host+"/xyz/openbmc_project/inventory/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600381 try:
Justin Thaler27197622019-01-23 14:42:11 -0600382 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600383 except(requests.exceptions.Timeout):
384 return(connectionErrHandler(args.json, "Timeout", None))
385
Justin Thaler3a5771b2019-01-23 14:31:52 -0600386 frulist={}
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600387# print(res.text)
Justin Thaler3a5771b2019-01-23 14:31:52 -0600388 if res.status_code==200:
389 frulist['Hardware'] = res.json()['data']
390 else:
391 if not args.json:
392 return "Error retrieving the system inventory. BMC message: {msg}".format(msg=res.json()['message'])
393 else:
394 return res.json()
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600395 url="https://"+host+"/xyz/openbmc_project/software/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600396 try:
Justin Thaler27197622019-01-23 14:42:11 -0600397 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600398 except(requests.exceptions.Timeout):
399 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600400# print(res.text)
Justin Thaler3a5771b2019-01-23 14:31:52 -0600401 if res.status_code==200:
402 frulist['Software'] = res.json()['data']
403 else:
404 if not args.json():
405 return "Error retrieving the system inventory. BMC message: {msg}".format(msg=res.json()['message'])
406 else:
407 return res.json()
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600408 return frulist
409
Justin Thalere412dc22018-01-12 16:28:24 -0600410
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600411def fruList(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -0600412 """
413 prints out all inventory or only a specific specified item
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600414
Justin Thalere412dc22018-01-12 16:28:24 -0600415 @param host: string, the hostname or IP address of the bmc
416 @param args: contains additional arguments used by the fru sub command
417 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600418 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
419 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600420 if(args.items==True):
421 return fruPrint(host, args, session)
422 else:
Justin Thalere412dc22018-01-12 16:28:24 -0600423 return fruPrint(host, args, session)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600424
425
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600426
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600427def fruStatus(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -0600428 """
429 prints out the status of all FRUs
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600430
Justin Thalere412dc22018-01-12 16:28:24 -0600431 @param host: string, the hostname or IP address of the bmc
432 @param args: contains additional arguments used by the fru sub command
433 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600434 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
435 """
Justin Thalere412dc22018-01-12 16:28:24 -0600436 url="https://"+host+"/xyz/openbmc_project/inventory/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600437 try:
Matt Spinler220c3c42019-01-04 15:09:29 -0600438 res = session.get(url, headers=jsonHeader, verify=False)
Justin Thalere412dc22018-01-12 16:28:24 -0600439 except(requests.exceptions.Timeout):
440 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600441# print(res.text)
Justin Thaler3a5771b2019-01-23 14:31:52 -0600442 frulist = res.json()['data']
Justin Thalere412dc22018-01-12 16:28:24 -0600443 frus = {}
444 for key in frulist:
445 component = frulist[key]
446 isFru = False
447 present = False
448 func = False
449 hasSels = False
450 keyPieces = key.split('/')
451 fruName = keyPieces[-1]
452 if 'core' in fruName: #associate cores to cpus
453 fruName = keyPieces[-2] + '-' + keyPieces[-1]
454 if 'Functional' in component:
455 if('Present' in component):
Justin Thalere412dc22018-01-12 16:28:24 -0600456 if 'FieldReplaceable' in component:
457 if component['FieldReplaceable'] == 1:
458 isFru = True
459 if "fan" in fruName:
460 isFru = True;
461 if component['Present'] == 1:
462 present = True
463 if component['Functional'] == 1:
464 func = True
465 if ((key + "/fault") in frulist):
466 hasSels = True;
467 if args.verbose:
468 if hasSels:
469 loglist = []
470 faults = frulist[key+"/fault"]['endpoints']
471 for item in faults:
472 loglist.append(item.split('/')[-1])
473 frus[fruName] = {"compName": fruName, "Functional": boolToString(func), "Present":boolToString(present), "IsFru": boolToString(isFru), "selList": ', '.join(loglist).strip() }
474 else:
475 frus[fruName] = {"compName": fruName, "Functional": boolToString(func), "Present":boolToString(present), "IsFru": boolToString(isFru), "selList": "None" }
476 else:
477 frus[fruName] = {"compName": fruName, "Functional": boolToString(func), "Present":boolToString(present), "IsFru": boolToString(isFru), "hasSEL": boolToString(hasSels) }
Justin Thalerfb9c81c2018-07-16 11:14:37 -0500478 elif "power_supply" in fruName or "powersupply" in fruName:
Justin Thalere412dc22018-01-12 16:28:24 -0600479 if component['Present'] ==1:
480 present = True
481 isFru = True
482 if ((key + "/fault") in frulist):
483 hasSels = True;
484 if args.verbose:
485 if hasSels:
486 loglist = []
487 faults = frulist[key+"/fault"]['endpoints']
Obihörnchenff8035f2018-12-05 21:07:37 +0100488 for item in faults:
489 loglist.append(item.split('/')[-1])
Justin Thalere412dc22018-01-12 16:28:24 -0600490 frus[fruName] = {"compName": fruName, "Functional": "No", "Present":boolToString(present), "IsFru": boolToString(isFru), "selList": ', '.join(loglist).strip() }
491 else:
492 frus[fruName] = {"compName": fruName, "Functional": "Yes", "Present":boolToString(present), "IsFru": boolToString(isFru), "selList": "None" }
493 else:
494 frus[fruName] = {"compName": fruName, "Functional": boolToString(not hasSels), "Present":boolToString(present), "IsFru": boolToString(isFru), "hasSEL": boolToString(hasSels) }
495 if not args.json:
496 if not args.verbose:
497 colNames = ["Component", "Is a FRU", "Present", "Functional", "Has Logs"]
498 keylist = ["compName", "IsFru", "Present", "Functional", "hasSEL"]
499 else:
500 colNames = ["Component", "Is a FRU", "Present", "Functional", "Assoc. Log Number(s)"]
501 keylist = ["compName", "IsFru", "Present", "Functional", "selList"]
502 return tableDisplay(keylist, colNames, frus)
503 else:
504 return str(json.dumps(frus, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600505
Justin Thalere412dc22018-01-12 16:28:24 -0600506def sensor(host, args, session):
507 """
508 prints out all sensors
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600509
Justin Thalere412dc22018-01-12 16:28:24 -0600510 @param host: string, the hostname or IP address of the bmc
511 @param args: contains additional arguments used by the sensor sub command
512 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600513 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
514 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600515 url="https://"+host+"/xyz/openbmc_project/sensors/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600516 try:
Justin Thaler27197622019-01-23 14:42:11 -0600517 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600518 except(requests.exceptions.Timeout):
519 return(connectionErrHandler(args.json, "Timeout", None))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600520
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600521 #Get OCC status
522 url="https://"+host+"/org/open_power/control/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600523 try:
Justin Thaler27197622019-01-23 14:42:11 -0600524 occres = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600525 except(requests.exceptions.Timeout):
526 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600527 if not args.json:
528 colNames = ['sensor', 'type', 'units', 'value', 'target']
Justin Thaler3a5771b2019-01-23 14:31:52 -0600529 sensors = res.json()["data"]
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600530 output = {}
531 for key in sensors:
532 senDict = {}
533 keyparts = key.split("/")
Matt Spinler596ef742019-09-20 08:54:36 -0500534
535 # Associations like the following also show up here:
536 # /xyz/openbmc_project/sensors/<type>/<name>/<assoc-name>
537 # Skip them.
538 # Note: keyparts[0] = '' which is why there are 7 segments.
539 if len(keyparts) > 6:
540 continue
541
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600542 senDict['sensorName'] = keyparts[-1]
543 senDict['type'] = keyparts[-2]
Justin Thalere412dc22018-01-12 16:28:24 -0600544 try:
545 senDict['units'] = sensors[key]['Unit'].split('.')[-1]
546 except KeyError:
Justin Thaler22b1bb52018-03-15 13:31:32 -0500547 senDict['units'] = "N/A"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600548 if('Scale' in sensors[key]):
549 scale = 10 ** sensors[key]['Scale']
550 else:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600551 scale = 1
Justin Thaler22b1bb52018-03-15 13:31:32 -0500552 try:
553 senDict['value'] = str(sensors[key]['Value'] * scale)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600554 except KeyError:
Justin Thaler22b1bb52018-03-15 13:31:32 -0500555 if 'value' in sensors[key]:
556 senDict['value'] = sensors[key]['value']
557 else:
558 senDict['value'] = "N/A"
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600559 if 'Target' in sensors[key]:
560 senDict['target'] = str(sensors[key]['Target'])
561 else:
562 senDict['target'] = 'N/A'
563 output[senDict['sensorName']] = senDict
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600564
Justin Thaler3a5771b2019-01-23 14:31:52 -0600565 occstatus = occres.json()["data"]
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600566 if '/org/open_power/control/occ0' in occstatus:
567 occ0 = occstatus["/org/open_power/control/occ0"]['OccActive']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600568 if occ0 == 1:
569 occ0 = 'Active'
570 else:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600571 occ0 = 'Inactive'
572 output['OCC0'] = {'sensorName':'OCC0', 'type': 'Discrete', 'units': 'N/A', 'value': occ0, 'target': 'Active'}
573 occ1 = occstatus["/org/open_power/control/occ1"]['OccActive']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600574 if occ1 == 1:
575 occ1 = 'Active'
576 else:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600577 occ1 = 'Inactive'
578 output['OCC1'] = {'sensorName':'OCC1', 'type': 'Discrete', 'units': 'N/A', 'value': occ0, 'target': 'Active'}
579 else:
580 output['OCC0'] = {'sensorName':'OCC0', 'type': 'Discrete', 'units': 'N/A', 'value': 'Inactive', 'target': 'Inactive'}
581 output['OCC1'] = {'sensorName':'OCC1', 'type': 'Discrete', 'units': 'N/A', 'value': 'Inactive', 'target': 'Inactive'}
582 keylist = ['sensorName', 'type', 'units', 'value', 'target']
Justin Thalere412dc22018-01-12 16:28:24 -0600583
584 return tableDisplay(keylist, colNames, output)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600585 else:
586 return res.text + occres.text
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600587
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600588def sel(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -0600589 """
590 prints out the bmc alerts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600591
Justin Thalere412dc22018-01-12 16:28:24 -0600592 @param host: string, the hostname or IP address of the bmc
593 @param args: contains additional arguments used by the sel sub command
594 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600595 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
596 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600597
598 url="https://"+host+"/xyz/openbmc_project/logging/entry/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600599 try:
Justin Thaler27197622019-01-23 14:42:11 -0600600 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600601 except(requests.exceptions.Timeout):
602 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600603 return res.text
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600604
605
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600606def parseESEL(args, eselRAW):
Justin Thalere412dc22018-01-12 16:28:24 -0600607 """
608 parses the esel data and gets predetermined search terms
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600609
Justin Thalere412dc22018-01-12 16:28:24 -0600610 @param eselRAW: string, the raw esel string from the bmc
611 @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 -0600612 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600613 eselParts = {}
614 esel_bin = binascii.unhexlify(''.join(eselRAW.split()[16:]))
615 #search terms contains the search term as the key and the return dictionary key as it's value
616 searchTerms = { 'Signature Description':'signatureDescription', 'devdesc':'devdesc',
Justin Thaler22b1bb52018-03-15 13:31:32 -0500617 'Callout type': 'calloutType', 'Procedure':'procedure', 'Sensor Type': 'sensorType'}
Justin Thaler24d4efa2018-11-08 22:48:10 -0600618 uniqueID = str(uuid.uuid4())
619 eselBinPath = tempfile.gettempdir() + os.sep + uniqueID + 'esel.bin'
Justin Thalercf1deae2018-05-25 19:35:21 -0500620 with open(eselBinPath, 'wb') as f:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600621 f.write(esel_bin)
622 errlPath = ""
623 #use the right errl file for the machine architecture
624 arch = platform.machine()
625 if(arch =='x86_64' or arch =='AMD64'):
626 if os.path.exists('/opt/ibm/ras/bin/x86_64/errl'):
627 errlPath = '/opt/ibm/ras/bin/x86_64/errl'
628 elif os.path.exists('errl/x86_64/errl'):
629 errlPath = 'errl/x86_64/errl'
630 else:
631 errlPath = 'x86_64/errl'
632 elif (platform.machine()=='ppc64le'):
633 if os.path.exists('/opt/ibm/ras/bin/ppc64le/errl'):
634 errlPath = '/opt/ibm/ras/bin/ppc64le/errl'
635 elif os.path.exists('errl/ppc64le/errl'):
636 errlPath = 'errl/ppc64le/errl'
637 else:
638 errlPath = 'ppc64le/errl'
639 else:
640 print("machine architecture not supported for parsing eSELs")
641 return eselParts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600642
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600643 if(os.path.exists(errlPath)):
Justin Thalercf1deae2018-05-25 19:35:21 -0500644 output= subprocess.check_output([errlPath, '-d', '--file='+eselBinPath]).decode('utf-8')
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600645# output = proc.communicate()[0]
646 lines = output.split('\n')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600647
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600648 if(hasattr(args, 'fullEsel')):
649 return output
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600650
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600651 for i in range(0, len(lines)):
652 lineParts = lines[i].split(':')
653 if(len(lineParts)>1): #ignore multi lines, output formatting lines, and other information
654 for term in searchTerms:
655 if(term in lineParts[0]):
656 temp = lines[i][lines[i].find(':')+1:].strip()[:-1].strip()
657 if lines[i+1].find(':') != -1:
658 if (len(lines[i+1].split(':')[0][1:].strip())==0):
659 while(len(lines[i][:lines[i].find(':')].strip())>2):
Justin Thaler43030422018-11-08 22:50:21 -0600660 #has multiple lines, process and update line counter
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600661 if((i+1) <= len(lines)):
662 i+=1
663 else:
664 i=i-1
665 break
Justin Thaler43030422018-11-08 22:50:21 -0600666 #Append the content from the next line removing the pretty display characters
667 #Finds the first colon then starts 2 characters after, then removes all whitespace
668 temp = temp + lines[i][lines[i].find(':')+2:].strip()[:-1].strip()[:-1].strip()
Justin Thaler22b1bb52018-03-15 13:31:32 -0500669 if(searchTerms[term] in eselParts):
670 eselParts[searchTerms[term]] = eselParts[searchTerms[term]] + ", " + temp
671 else:
672 eselParts[searchTerms[term]] = temp
Justin Thalercf1deae2018-05-25 19:35:21 -0500673 os.remove(eselBinPath)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600674 else:
675 print("errl file cannot be found")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600676
677 return eselParts
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600678
Justin Thalere412dc22018-01-12 16:28:24 -0600679
Matt Spinler02d0dff2018-08-29 13:19:25 -0500680def getESELSeverity(esel):
681 """
682 Finds the severity type in an eSEL from the User Header section.
683 @param esel - the eSEL data
684 @return severity - e.g. 'Critical'
685 """
686
687 # everything but 1 and 2 are Critical
688 # '1': 'recovered',
689 # '2': 'predictive',
690 # '4': 'unrecoverable',
691 # '5': 'critical',
692 # '6': 'diagnostic',
693 # '7': 'symptom'
694 severities = {
695 '1': 'Informational',
696 '2': 'Warning'
697 }
698
699 try:
700 headerPosition = esel.index('55 48') # 'UH'
701 # The severity is the last byte in the 8 byte section (a byte is ' bb')
702 severity = esel[headerPosition:headerPosition+32].split(' ')[-1]
703 type = severity[0]
704 except ValueError:
705 print("Could not find severity value in UH section in eSEL")
706 type = 'x';
707
708 return severities.get(type, 'Critical')
709
710
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600711def sortSELs(events):
Justin Thalere412dc22018-01-12 16:28:24 -0600712 """
713 sorts the sels by timestamp, then log entry number
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600714
Justin Thalere412dc22018-01-12 16:28:24 -0600715 @param events: Dictionary containing events
716 @return: list containing a list of the ordered log entries, and dictionary of keys
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600717 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600718 logNumList = []
719 timestampList = []
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600720 eventKeyDict = {}
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600721 eventsWithTimestamp = {}
722 logNum2events = {}
723 for key in events:
724 if key == 'numAlerts': continue
725 if 'callout' in key: continue
726 timestamp = (events[key]['timestamp'])
727 if timestamp not in timestampList:
728 eventsWithTimestamp[timestamp] = [events[key]['logNum']]
729 else:
730 eventsWithTimestamp[timestamp].append(events[key]['logNum'])
731 #map logNumbers to the event dictionary keys
732 eventKeyDict[str(events[key]['logNum'])] = key
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600733
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600734 timestampList = list(eventsWithTimestamp.keys())
735 timestampList.sort()
736 for ts in timestampList:
737 if len(eventsWithTimestamp[ts]) > 1:
738 tmplist = eventsWithTimestamp[ts]
739 tmplist.sort()
740 logNumList = logNumList + tmplist
741 else:
742 logNumList = logNumList + eventsWithTimestamp[ts]
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600743
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600744 return [logNumList, eventKeyDict]
745
Justin Thalere412dc22018-01-12 16:28:24 -0600746
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600747def parseAlerts(policyTable, selEntries, args):
Justin Thalere412dc22018-01-12 16:28:24 -0600748 """
749 parses alerts in the IBM CER format, using an IBM policy Table
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600750
Justin Thalere412dc22018-01-12 16:28:24 -0600751 @param policyTable: dictionary, the policy table entries
752 @param selEntries: dictionary, the alerts retrieved from the bmc
753 @return: A dictionary of the parsed entries, in chronological order
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600754 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600755 eventDict = {}
756 eventNum =""
757 count = 0
758 esel = ""
759 eselParts = {}
760 i2cdevice= ""
Matt Spinler02d0dff2018-08-29 13:19:25 -0500761 eselSeverity = None
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600762
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600763 'prepare and sort the event entries'
764 for key in selEntries:
765 if 'callout' not in key:
766 selEntries[key]['logNum'] = key.split('/')[-1]
767 selEntries[key]['timestamp'] = selEntries[key]['Timestamp']
768 sortedEntries = sortSELs(selEntries)
769 logNumList = sortedEntries[0]
770 eventKeyDict = sortedEntries[1]
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600771
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600772 for logNum in logNumList:
773 key = eventKeyDict[logNum]
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600774 hasEsel=False
775 i2creadFail = False
776 if 'callout' in key:
777 continue
778 else:
779 messageID = str(selEntries[key]['Message'])
780 addDataPiece = selEntries[key]['AdditionalData']
781 calloutIndex = 0
782 calloutFound = False
783 for i in range(len(addDataPiece)):
784 if("CALLOUT_INVENTORY_PATH" in addDataPiece[i]):
785 calloutIndex = i
786 calloutFound = True
787 fruCallout = str(addDataPiece[calloutIndex]).split('=')[1]
788 if("CALLOUT_DEVICE_PATH" in addDataPiece[i]):
789 i2creadFail = True
Matt Spinlerd178a472018-08-31 09:48:52 -0500790
791 fruCallout = str(addDataPiece[calloutIndex]).split('=')[1]
792
793 # Fall back to "I2C"/"FSI" if dev path isn't in policy table
794 if (messageID + '||' + fruCallout) not in policyTable:
795 i2cdevice = str(addDataPiece[i]).strip().split('=')[1]
796 i2cdevice = '/'.join(i2cdevice.split('/')[-4:])
797 if 'fsi' in str(addDataPiece[calloutIndex]).split('=')[1]:
798 fruCallout = 'FSI'
799 else:
800 fruCallout = 'I2C'
Justin Thalere34c43a2018-05-25 19:37:55 -0500801 calloutFound = True
802 if("CALLOUT_GPIO_NUM" in addDataPiece[i]):
803 if not calloutFound:
804 fruCallout = 'GPIO'
805 calloutFound = True
806 if("CALLOUT_IIC_BUS" in addDataPiece[i]):
807 if not calloutFound:
808 fruCallout = "I2C"
809 calloutFound = True
810 if("CALLOUT_IPMI_SENSOR_NUM" in addDataPiece[i]):
811 if not calloutFound:
812 fruCallout = "IPMI"
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600813 calloutFound = True
814 if("ESEL" in addDataPiece[i]):
815 esel = str(addDataPiece[i]).strip().split('=')[1]
Matt Spinler02d0dff2018-08-29 13:19:25 -0500816 eselSeverity = getESELSeverity(esel)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600817 if args.devdebug:
818 eselParts = parseESEL(args, esel)
819 hasEsel=True
820 if("GPU" in addDataPiece[i]):
821 fruCallout = '/xyz/openbmc_project/inventory/system/chassis/motherboard/gpu' + str(addDataPiece[i]).strip()[-1]
822 calloutFound = True
823 if("PROCEDURE" in addDataPiece[i]):
824 fruCallout = str(hex(int(str(addDataPiece[i]).split('=')[1])))[2:]
825 calloutFound = True
Justin Thalere412dc22018-01-12 16:28:24 -0600826 if("RAIL_NAME" in addDataPiece[i]):
827 calloutFound=True
828 fruCallout = str(addDataPiece[i]).split('=')[1].strip()
829 if("INPUT_NAME" in addDataPiece[i]):
830 calloutFound=True
831 fruCallout = str(addDataPiece[i]).split('=')[1].strip()
832 if("SENSOR_TYPE" in addDataPiece[i]):
833 calloutFound=True
834 fruCallout = str(addDataPiece[i]).split('=')[1].strip()
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600835
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600836 if(calloutFound):
Justin Thaler22b1bb52018-03-15 13:31:32 -0500837 if fruCallout != "":
838 policyKey = messageID +"||" + fruCallout
Matt Spinler02d0dff2018-08-29 13:19:25 -0500839
840 # Also use the severity for hostboot errors
841 if eselSeverity and messageID == 'org.open_power.Host.Error.Event':
842 policyKey += '||' + eselSeverity
843
844 # if not in the table, fall back to the original key
845 if policyKey not in policyTable:
846 policyKey = policyKey.replace('||'+eselSeverity, '')
847
Justin Thalere34c43a2018-05-25 19:37:55 -0500848 if policyKey not in policyTable:
849 policyKey = messageID
Justin Thaler22b1bb52018-03-15 13:31:32 -0500850 else:
851 policyKey = messageID
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600852 else:
853 policyKey = messageID
854 event = {}
855 eventNum = str(count)
856 if policyKey in policyTable:
857 for pkey in policyTable[policyKey]:
858 if(type(policyTable[policyKey][pkey])== bool):
859 event[pkey] = boolToString(policyTable[policyKey][pkey])
860 else:
861 if (i2creadFail and pkey == 'Message'):
862 event[pkey] = policyTable[policyKey][pkey] + ' ' +i2cdevice
863 else:
864 event[pkey] = policyTable[policyKey][pkey]
865 event['timestamp'] = selEntries[key]['Timestamp']
866 event['resolved'] = bool(selEntries[key]['Resolved'])
867 if(hasEsel):
868 if args.devdebug:
869 event['eselParts'] = eselParts
870 event['raweSEL'] = esel
871 event['logNum'] = key.split('/')[-1]
872 eventDict['event' + eventNum] = event
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600873
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600874 else:
875 severity = str(selEntries[key]['Severity']).split('.')[-1]
876 if severity == 'Error':
877 severity = 'Critical'
878 eventDict['event'+eventNum] = {}
879 eventDict['event' + eventNum]['error'] = "error: Not found in policy table: " + policyKey
880 eventDict['event' + eventNum]['timestamp'] = selEntries[key]['Timestamp']
881 eventDict['event' + eventNum]['Severity'] = severity
882 if(hasEsel):
883 if args.devdebug:
884 eventDict['event' +eventNum]['eselParts'] = eselParts
885 eventDict['event' +eventNum]['raweSEL'] = esel
886 eventDict['event' +eventNum]['logNum'] = key.split('/')[-1]
887 eventDict['event' +eventNum]['resolved'] = bool(selEntries[key]['Resolved'])
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600888 count += 1
889 return eventDict
890
891
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600892def selDisplay(events, args):
Justin Thalere412dc22018-01-12 16:28:24 -0600893 """
894 displays alerts in human readable format
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600895
Justin Thalere412dc22018-01-12 16:28:24 -0600896 @param events: Dictionary containing events
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600897 @return:
898 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600899 activeAlerts = []
900 historyAlerts = []
901 sortedEntries = sortSELs(events)
902 logNumList = sortedEntries[0]
903 eventKeyDict = sortedEntries[1]
904 keylist = ['Entry', 'ID', 'Timestamp', 'Serviceable', 'Severity','Message']
905 if(args.devdebug):
906 colNames = ['Entry', 'ID', 'Timestamp', 'Serviceable', 'Severity','Message', 'eSEL contents']
907 keylist.append('eSEL')
908 else:
909 colNames = ['Entry', 'ID', 'Timestamp', 'Serviceable', 'Severity', 'Message']
910 for log in logNumList:
911 selDict = {}
912 alert = events[eventKeyDict[str(log)]]
913 if('error' in alert):
914 selDict['Entry'] = alert['logNum']
915 selDict['ID'] = 'Unknown'
916 selDict['Timestamp'] = datetime.datetime.fromtimestamp(int(alert['timestamp']/1000)).strftime("%Y-%m-%d %H:%M:%S")
917 msg = alert['error']
918 polMsg = msg.split("policy table:")[0]
919 msg = msg.split("policy table:")[1]
920 msgPieces = msg.split("||")
921 err = msgPieces[0]
922 if(err.find("org.open_power.")!=-1):
923 err = err.split("org.open_power.")[1]
924 elif(err.find("xyz.openbmc_project.")!=-1):
925 err = err.split("xyz.openbmc_project.")[1]
926 else:
927 err = msgPieces[0]
928 callout = ""
929 if len(msgPieces) >1:
930 callout = msgPieces[1]
931 if(callout.find("/org/open_power/")!=-1):
932 callout = callout.split("/org/open_power/")[1]
933 elif(callout.find("/xyz/openbmc_project/")!=-1):
934 callout = callout.split("/xyz/openbmc_project/")[1]
935 else:
936 callout = msgPieces[1]
937 selDict['Message'] = polMsg +"policy table: "+ err + "||" + callout
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600938 selDict['Serviceable'] = 'Unknown'
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600939 selDict['Severity'] = alert['Severity']
940 else:
941 selDict['Entry'] = alert['logNum']
942 selDict['ID'] = alert['CommonEventID']
943 selDict['Timestamp'] = datetime.datetime.fromtimestamp(int(alert['timestamp']/1000)).strftime("%Y-%m-%d %H:%M:%S")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600944 selDict['Message'] = alert['Message']
945 selDict['Serviceable'] = alert['Serviceable']
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600946 selDict['Severity'] = alert['Severity']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600947
948
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600949 eselOrder = ['refCode','signatureDescription', 'eselType', 'devdesc', 'calloutType', 'procedure']
950 if ('eselParts' in alert and args.devdebug):
951 eselOutput = ""
952 for item in eselOrder:
953 if item in alert['eselParts']:
954 eselOutput = eselOutput + item + ": " + alert['eselParts'][item] + " | "
955 selDict['eSEL'] = eselOutput
956 else:
957 if args.devdebug:
958 selDict['eSEL'] = "None"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600959
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600960 if not alert['resolved']:
961 activeAlerts.append(selDict)
962 else:
963 historyAlerts.append(selDict)
964 mergedOutput = activeAlerts + historyAlerts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600965 colWidth = setColWidth(keylist, len(colNames), dict(enumerate(mergedOutput)), colNames)
966
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600967 output = ""
968 if(len(activeAlerts)>0):
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600969 row = ""
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600970 output +="----Active Alerts----\n"
971 for i in range(0, len(colNames)):
972 if i!=0: row =row + "| "
973 row = row + colNames[i].ljust(colWidth[i])
974 output += row + "\n"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600975
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600976 for i in range(0,len(activeAlerts)):
977 row = ""
978 for j in range(len(activeAlerts[i])):
979 if (j != 0): row = row + "| "
980 row = row + activeAlerts[i][keylist[j]].ljust(colWidth[j])
981 output += row + "\n"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600982
983 if(len(historyAlerts)>0):
984 row = ""
985 output+= "----Historical Alerts----\n"
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600986 for i in range(len(colNames)):
987 if i!=0: row =row + "| "
988 row = row + colNames[i].ljust(colWidth[i])
989 output += row + "\n"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600990
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600991 for i in range(0, len(historyAlerts)):
992 row = ""
993 for j in range(len(historyAlerts[i])):
994 if (j != 0): row = row + "| "
995 row = row + historyAlerts[i][keylist[j]].ljust(colWidth[j])
996 output += row + "\n"
997# print(events[eventKeyDict[str(log)]])
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600998 return output
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600999
Justin Thalere412dc22018-01-12 16:28:24 -06001000
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001001def selPrint(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001002 """
1003 prints out all bmc alerts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001004
Justin Thalere412dc22018-01-12 16:28:24 -06001005 @param host: string, the hostname or IP address of the bmc
1006 @param args: contains additional arguments used by the fru sub command
1007 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001008 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1009 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001010 if(args.policyTableLoc is None):
1011 if os.path.exists('policyTable.json'):
1012 ptableLoc = "policyTable.json"
1013 elif os.path.exists('/opt/ibm/ras/lib/policyTable.json'):
1014 ptableLoc = '/opt/ibm/ras/lib/policyTable.json'
1015 else:
1016 ptableLoc = 'lib/policyTable.json'
1017 else:
1018 ptableLoc = args.policyTableLoc
1019 policyTable = loadPolicyTable(ptableLoc)
1020 rawselEntries = ""
1021 if(hasattr(args, 'fileloc') and args.fileloc is not None):
1022 if os.path.exists(args.fileloc):
1023 with open(args.fileloc, 'r') as selFile:
1024 selLines = selFile.readlines()
1025 rawselEntries = ''.join(selLines)
1026 else:
1027 print("Error: File not found")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001028 sys.exit(1)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001029 else:
1030 rawselEntries = sel(host, args, session)
1031 loadFailed = False
1032 try:
1033 selEntries = json.loads(rawselEntries)
1034 except ValueError:
1035 loadFailed = True
1036 if loadFailed:
1037 cleanSels = json.dumps(rawselEntries).replace('\\n', '')
1038 #need to load json twice as original content was string escaped a second time
1039 selEntries = json.loads(json.loads(cleanSels))
1040 selEntries = selEntries['data']
Justin Thalere412dc22018-01-12 16:28:24 -06001041
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001042 if 'description' in selEntries:
1043 if(args.json):
1044 return("{\n\t\"numAlerts\": 0\n}")
1045 else:
1046 return("No log entries found")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001047
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001048 else:
1049 if(len(policyTable)>0):
1050 events = parseAlerts(policyTable, selEntries, args)
1051 if(args.json):
1052 events["numAlerts"] = len(events)
1053 retValue = str(json.dumps(events, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False))
1054 return retValue
1055 elif(hasattr(args, 'fullSel')):
1056 return events
1057 else:
1058 #get log numbers to order event entries sequentially
1059 return selDisplay(events, args)
1060 else:
1061 if(args.json):
1062 return selEntries
1063 else:
1064 print("error: Policy Table not found.")
1065 return selEntries
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001066
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001067def selList(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001068 """
1069 prints out all all bmc alerts, or only prints out the specified alerts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001070
Justin Thalere412dc22018-01-12 16:28:24 -06001071 @param host: string, the hostname or IP address of the bmc
1072 @param args: contains additional arguments used by the fru sub command
1073 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001074 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1075 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001076 return(sel(host, args, session))
1077
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001078
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001079def selClear(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001080 """
1081 clears all alerts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001082
Justin Thalere412dc22018-01-12 16:28:24 -06001083 @param host: string, the hostname or IP address of the bmc
1084 @param args: contains additional arguments used by the fru sub command
1085 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001086 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1087 """
Matt Spinler47b13e92019-01-04 14:58:53 -06001088 url="https://"+host+"/xyz/openbmc_project/logging/action/DeleteAll"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001089 data = "{\"data\": [] }"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001090
Justin Thalere412dc22018-01-12 16:28:24 -06001091 try:
Justin Thaler27197622019-01-23 14:42:11 -06001092 res = session.post(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001093 except(requests.exceptions.Timeout):
1094 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001095 if res.status_code == 200:
1096 return "The Alert Log has been cleared. Please allow a few minutes for the action to complete."
1097 else:
1098 print("Unable to clear the logs, trying to clear 1 at a time")
1099 sels = json.loads(sel(host, args, session))['data']
1100 for key in sels:
1101 if 'callout' not in key:
1102 logNum = key.split('/')[-1]
1103 url = "https://"+ host+ "/xyz/openbmc_project/logging/entry/"+logNum+"/action/Delete"
1104 try:
Justin Thaler27197622019-01-23 14:42:11 -06001105 session.post(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001106 except(requests.exceptions.Timeout):
1107 return connectionErrHandler(args.json, "Timeout", None)
1108 sys.exit(1)
1109 except(requests.exceptions.ConnectionError) as err:
1110 return connectionErrHandler(args.json, "ConnectionError", err)
1111 sys.exit(1)
1112 return ('Sel clearing complete')
1113
1114def selSetResolved(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001115 """
1116 sets a sel entry to resolved
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001117
Justin Thalere412dc22018-01-12 16:28:24 -06001118 @param host: string, the hostname or IP address of the bmc
1119 @param args: contains additional arguments used by the fru sub command
1120 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001121 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1122 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001123 url="https://"+host+"/xyz/openbmc_project/logging/entry/" + str(args.selNum) + "/attr/Resolved"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001124 data = "{\"data\": 1 }"
Justin Thalere412dc22018-01-12 16:28:24 -06001125 try:
Justin Thaler27197622019-01-23 14:42:11 -06001126 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001127 except(requests.exceptions.Timeout):
1128 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001129 if res.status_code == 200:
1130 return "Sel entry "+ str(args.selNum) +" is now set to resolved"
1131 else:
1132 return "Unable to set the alert to resolved"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001133
Justin Thalere412dc22018-01-12 16:28:24 -06001134def selResolveAll(host, args, session):
1135 """
1136 sets a sel entry to resolved
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001137
Justin Thalere412dc22018-01-12 16:28:24 -06001138 @param host: string, the hostname or IP address of the bmc
1139 @param args: contains additional arguments used by the fru sub command
1140 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001141 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1142 """
Justin Thalere412dc22018-01-12 16:28:24 -06001143 rawselEntries = sel(host, args, session)
1144 loadFailed = False
1145 try:
1146 selEntries = json.loads(rawselEntries)
1147 except ValueError:
1148 loadFailed = True
1149 if loadFailed:
1150 cleanSels = json.dumps(rawselEntries).replace('\\n', '')
1151 #need to load json twice as original content was string escaped a second time
1152 selEntries = json.loads(json.loads(cleanSels))
1153 selEntries = selEntries['data']
1154
1155 if 'description' in selEntries:
1156 if(args.json):
1157 return("{\n\t\"selsResolved\": 0\n}")
1158 else:
1159 return("No log entries found")
1160 else:
1161 d = vars(args)
1162 successlist = []
1163 failedlist = []
1164 for key in selEntries:
1165 if 'callout' not in key:
1166 d['selNum'] = key.split('/')[-1]
1167 resolved = selSetResolved(host,args,session)
1168 if 'Sel entry' in resolved:
1169 successlist.append(d['selNum'])
1170 else:
1171 failedlist.append(d['selNum'])
1172 output = ""
1173 successlist.sort()
1174 failedlist.sort()
1175 if len(successlist)>0:
1176 output = "Successfully resolved: " +', '.join(successlist) +"\n"
1177 if len(failedlist)>0:
1178 output += "Failed to resolve: " + ', '.join(failedlist) + "\n"
1179 return output
1180
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001181def chassisPower(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001182 """
1183 called by the chassis function. Controls the power state of the chassis, or gets the status
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001184
Justin Thalere412dc22018-01-12 16:28:24 -06001185 @param host: string, the hostname or IP address of the bmc
1186 @param args: contains additional arguments used by the fru sub command
1187 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001188 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1189 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001190 if(args.powcmd == 'on'):
Justin Thaler22b1bb52018-03-15 13:31:32 -05001191 if checkFWactivation(host, args, session):
1192 return ("Chassis Power control disabled during firmware activation")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001193 print("Attempting to Power on...:")
1194 url="https://"+host+"/xyz/openbmc_project/state/host0/attr/RequestedHostTransition"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001195 data = '{"data":"xyz.openbmc_project.State.Host.Transition.On"}'
Justin Thalere412dc22018-01-12 16:28:24 -06001196 try:
Justin Thaler27197622019-01-23 14:42:11 -06001197 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001198 except(requests.exceptions.Timeout):
1199 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001200 return res.text
Justin Thalere412dc22018-01-12 16:28:24 -06001201 elif(args.powcmd == 'softoff'):
Justin Thaler22b1bb52018-03-15 13:31:32 -05001202 if checkFWactivation(host, args, session):
1203 return ("Chassis Power control disabled during firmware activation")
Justin Thalere412dc22018-01-12 16:28:24 -06001204 print("Attempting to Power off gracefully...:")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001205 url="https://"+host+"/xyz/openbmc_project/state/host0/attr/RequestedHostTransition"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001206 data = '{"data":"xyz.openbmc_project.State.Host.Transition.Off"}'
Justin Thalere412dc22018-01-12 16:28:24 -06001207 try:
Justin Thaler27197622019-01-23 14:42:11 -06001208 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001209 except(requests.exceptions.Timeout):
1210 return(connectionErrHandler(args.json, "Timeout", None))
1211 return res.text
1212 elif(args.powcmd == 'hardoff'):
Justin Thaler22b1bb52018-03-15 13:31:32 -05001213 if checkFWactivation(host, args, session):
1214 return ("Chassis Power control disabled during firmware activation")
Justin Thalere412dc22018-01-12 16:28:24 -06001215 print("Attempting to Power off immediately...:")
1216 url="https://"+host+"/xyz/openbmc_project/state/chassis0/attr/RequestedPowerTransition"
Justin Thalere412dc22018-01-12 16:28:24 -06001217 data = '{"data":"xyz.openbmc_project.State.Chassis.Transition.Off"}'
1218 try:
Justin Thaler27197622019-01-23 14:42:11 -06001219 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001220 except(requests.exceptions.Timeout):
1221 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001222 return res.text
1223 elif(args.powcmd == 'status'):
1224 url="https://"+host+"/xyz/openbmc_project/state/chassis0/attr/CurrentPowerState"
Justin Thalere412dc22018-01-12 16:28:24 -06001225 try:
Justin Thaler27197622019-01-23 14:42:11 -06001226 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001227 except(requests.exceptions.Timeout):
1228 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001229 chassisState = json.loads(res.text)['data'].split('.')[-1]
1230 url="https://"+host+"/xyz/openbmc_project/state/host0/attr/CurrentHostState"
Justin Thalere412dc22018-01-12 16:28:24 -06001231 try:
Justin Thaler27197622019-01-23 14:42:11 -06001232 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001233 except(requests.exceptions.Timeout):
1234 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001235 hostState = json.loads(res.text)['data'].split('.')[-1]
1236 url="https://"+host+"/xyz/openbmc_project/state/bmc0/attr/CurrentBMCState"
Justin Thalere412dc22018-01-12 16:28:24 -06001237 try:
Justin Thaler27197622019-01-23 14:42:11 -06001238 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001239 except(requests.exceptions.Timeout):
1240 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001241 bmcState = json.loads(res.text)['data'].split('.')[-1]
1242 if(args.json):
1243 outDict = {"Chassis Power State" : chassisState, "Host Power State" : hostState, "BMC Power State":bmcState}
1244 return json.dumps(outDict, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False)
1245 else:
1246 return "Chassis Power State: " +chassisState + "\nHost Power State: " + hostState + "\nBMC Power State: " + bmcState
1247 else:
1248 return "Invalid chassis power command"
1249
Justin Thalere412dc22018-01-12 16:28:24 -06001250
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001251def chassisIdent(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001252 """
1253 called by the chassis function. Controls the identify led of the chassis. Sets or gets the state
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001254
Justin Thalere412dc22018-01-12 16:28:24 -06001255 @param host: string, the hostname or IP address of the bmc
1256 @param args: contains additional arguments used by the fru sub command
1257 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001258 @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 -06001259 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001260 if(args.identcmd == 'on'):
1261 print("Attempting to turn identify light on...:")
1262 url="https://"+host+"/xyz/openbmc_project/led/groups/enclosure_identify/attr/Asserted"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001263 data = '{"data":true}'
Justin Thalere412dc22018-01-12 16:28:24 -06001264 try:
Justin Thaler27197622019-01-23 14:42:11 -06001265 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001266 except(requests.exceptions.Timeout):
1267 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001268 return res.text
1269 elif(args.identcmd == 'off'):
1270 print("Attempting to turn identify light off...:")
1271 url="https://"+host+"/xyz/openbmc_project/led/groups/enclosure_identify/attr/Asserted"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001272 data = '{"data":false}'
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 == 'status'):
1279 url="https://"+host+"/xyz/openbmc_project/led/groups/enclosure_identify"
Justin Thalere412dc22018-01-12 16:28:24 -06001280 try:
Justin Thaler27197622019-01-23 14:42:11 -06001281 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001282 except(requests.exceptions.Timeout):
1283 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001284 status = json.loads(res.text)['data']
1285 if(args.json):
1286 return status
1287 else:
1288 if status['Asserted'] == 0:
1289 return "Identify light is off"
1290 else:
1291 return "Identify light is blinking"
1292 else:
1293 return "Invalid chassis identify command"
1294
Justin Thalere412dc22018-01-12 16:28:24 -06001295
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001296def chassis(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001297 """
1298 controls the different chassis commands
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001299
Justin Thalere412dc22018-01-12 16:28:24 -06001300 @param host: string, the hostname or IP address of the bmc
1301 @param args: contains additional arguments used by the fru sub command
1302 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001303 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1304 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001305 if(hasattr(args, 'powcmd')):
1306 result = chassisPower(host,args,session)
1307 elif(hasattr(args, 'identcmd')):
1308 result = chassisIdent(host, args, session)
1309 else:
Justin Thaler22b1bb52018-03-15 13:31:32 -05001310 return "This feature is not yet implemented"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001311 return result
Justin Thalere412dc22018-01-12 16:28:24 -06001312
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001313def bmcDumpRetrieve(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001314 """
1315 Downloads a dump file from the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001316
Justin Thalere412dc22018-01-12 16:28:24 -06001317 @param host: string, the hostname or IP address of the bmc
1318 @param args: contains additional arguments used by the collectServiceData sub command
1319 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001320 @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 -06001321 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001322 dumpNum = args.dumpNum
1323 if (args.dumpSaveLoc is not None):
1324 saveLoc = args.dumpSaveLoc
1325 else:
Justin Thalercf1deae2018-05-25 19:35:21 -05001326 saveLoc = tempfile.gettempdir()
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001327 url ='https://'+host+'/download/dump/' + str(dumpNum)
1328 try:
Justin Thaler27197622019-01-23 14:42:11 -06001329 r = session.get(url, headers=jsonHeader, stream=True, verify=False, timeout=baseTimeout)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001330 if (args.dumpSaveLoc is not None):
1331 if os.path.exists(saveLoc):
1332 if saveLoc[-1] != os.path.sep:
1333 saveLoc = saveLoc + os.path.sep
1334 filename = saveLoc + host+'-dump' + str(dumpNum) + '.tar.xz'
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001335
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001336 else:
1337 return 'Invalid save location specified'
1338 else:
Justin Thalercf1deae2018-05-25 19:35:21 -05001339 filename = tempfile.gettempdir()+os.sep + host+'-dump' + str(dumpNum) + '.tar.xz'
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001340
1341 with open(filename, 'wb') as f:
1342 for chunk in r.iter_content(chunk_size =1024):
1343 if chunk:
1344 f.write(chunk)
1345 return 'Saved as ' + filename
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001346
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001347 except(requests.exceptions.Timeout):
1348 return connectionErrHandler(args.json, "Timeout", None)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001349
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001350 except(requests.exceptions.ConnectionError) as err:
1351 return connectionErrHandler(args.json, "ConnectionError", err)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001352
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001353def bmcDumpList(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001354 """
1355 Lists the number of dump files on the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001356
Justin Thalere412dc22018-01-12 16:28:24 -06001357 @param host: string, the hostname or IP address of the bmc
1358 @param args: contains additional arguments used by the collectServiceData sub command
1359 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001360 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1361 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001362 url ='https://'+host+'/xyz/openbmc_project/dump/list'
1363 try:
Justin Thaler27197622019-01-23 14:42:11 -06001364 r = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thaler3a5771b2019-01-23 14:31:52 -06001365 dumpList = r.json()
1366 return dumpList
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001367 except(requests.exceptions.Timeout):
1368 return connectionErrHandler(args.json, "Timeout", None)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001369
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001370 except(requests.exceptions.ConnectionError) as err:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001371 return connectionErrHandler(args.json, "ConnectionError", err)
1372
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001373def bmcDumpDelete(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001374 """
1375 Deletes BMC dump files from the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001376
Justin Thalere412dc22018-01-12 16:28:24 -06001377 @param host: string, the hostname or IP address of the bmc
1378 @param args: contains additional arguments used by the collectServiceData sub command
1379 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001380 @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 -06001381 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001382 dumpList = []
1383 successList = []
1384 failedList = []
1385 if args.dumpNum is not None:
1386 if isinstance(args.dumpNum, list):
1387 dumpList = args.dumpNum
1388 else:
1389 dumpList.append(args.dumpNum)
1390 for dumpNum in dumpList:
1391 url ='https://'+host+'/xyz/openbmc_project/dump/entry/'+str(dumpNum)+'/action/Delete'
1392 try:
Justin Thaler27197622019-01-23 14:42:11 -06001393 r = session.post(url, headers=jsonHeader, json = {"data": []}, verify=False, timeout=baseTimeout)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001394 if r.status_code == 200:
1395 successList.append(str(dumpNum))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001396 else:
1397 failedList.append(str(dumpNum))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001398 except(requests.exceptions.Timeout):
1399 return connectionErrHandler(args.json, "Timeout", None)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001400 except(requests.exceptions.ConnectionError) as err:
1401 return connectionErrHandler(args.json, "ConnectionError", err)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001402 output = "Successfully deleted dumps: " + ', '.join(successList)
1403 if(len(failedList)>0):
1404 output+= '\nFailed to delete dumps: ' + ', '.join(failedList)
1405 return output
1406 else:
1407 return 'You must specify an entry number to delete'
1408
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001409def bmcDumpDeleteAll(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001410 """
1411 Deletes All BMC dump files from the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001412
Justin Thalere412dc22018-01-12 16:28:24 -06001413 @param host: string, the hostname or IP address of the bmc
1414 @param args: contains additional arguments used by the collectServiceData sub command
1415 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001416 @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 -06001417 """
1418 dumpResp = bmcDumpList(host, args, session)
1419 if 'FQPSPIN0000M' in dumpResp or 'FQPSPIN0001M'in dumpResp:
1420 return dumpResp
Justin Thaler3a5771b2019-01-23 14:31:52 -06001421 dumpList = dumpResp['data']
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001422 d = vars(args)
1423 dumpNums = []
1424 for dump in dumpList:
1425 if '/xyz/openbmc_project/dump/internal/manager' not in dump:
1426 dumpNums.append(int(dump.strip().split('/')[-1]))
1427 d['dumpNum'] = dumpNums
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001428
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001429 return bmcDumpDelete(host, args, session)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001430
Justin Thalere412dc22018-01-12 16:28:24 -06001431
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001432def bmcDumpCreate(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001433 """
1434 Creates a bmc dump file
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001435
Justin Thalere412dc22018-01-12 16:28:24 -06001436 @param host: string, the hostname or IP address of the bmc
1437 @param args: contains additional arguments used by the collectServiceData sub command
1438 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001439 @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 -06001440 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001441 url = 'https://'+host+'/xyz/openbmc_project/dump/action/CreateDump'
1442 try:
Justin Thaler27197622019-01-23 14:42:11 -06001443 r = session.post(url, headers=jsonHeader, json = {"data": []}, verify=False, timeout=baseTimeout)
Matt Spinlereae05b02019-01-24 12:59:34 -06001444 if(r.status_code == 200 and not args.json):
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001445 return ('Dump successfully created')
Justin Thaler3a5771b2019-01-23 14:31:52 -06001446 elif(args.json):
1447 return r.json()
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001448 else:
1449 return ('Failed to create dump')
1450 except(requests.exceptions.Timeout):
1451 return connectionErrHandler(args.json, "Timeout", None)
1452 except(requests.exceptions.ConnectionError) as err:
1453 return connectionErrHandler(args.json, "ConnectionError", err)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001454
1455
Justin Thaler666cf342019-01-23 14:44:27 -06001456def csdDumpInitiate(host, args, session):
1457 """
1458 Starts the process of getting the current list of dumps then initiates the creation of one.
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001459
Justin Thaler666cf342019-01-23 14:44:27 -06001460 @param host: string, the hostname or IP address of the bmc
1461 @param args: contains additional arguments used by the collectServiceData sub command
1462 @param session: the active session to use
1463 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1464 """
1465 errorInfo = ""
1466 dumpcount = 0
1467 try:
1468 d = vars(args)
1469 d['json'] = True
1470 except Exception as e:
1471 errorInfo += "Failed to set the json flag to True \n Exception: {eInfo}\n".format(eInfo=e)
1472
1473 try:
1474 for i in range(3):
1475 dumpInfo = bmcDumpList(host, args, session)
1476 if 'data' in dumpInfo:
1477 dumpcount = len(dumpInfo['data'])
1478 break
1479 else:
1480 errorInfo+= "Dump List Message returned: " + json.dumps(dumpInfo,indent=0, separators=(',', ':')).replace('\n','') +"\n"
1481 except Exception as e:
1482 errorInfo+= "Failed to collect the list of dumps.\nException: {eInfo}\n".format(eInfo=e)
1483
1484 #Create a user initiated dump
1485 try:
1486 for i in range(3):
1487 dumpcreated = bmcDumpCreate(host, args, session)
1488 if 'message' in dumpcreated:
1489 if 'ok' in dumpcreated['message'].lower():
1490 break
1491 else:
1492 errorInfo+= "Dump create message returned: " + json.dumps(dumpInfo,indent=0, separators=(',', ':')).replace('\n','') +"\n"
1493 else:
1494 errorInfo+= "Dump create message returned: " + json.dumps(dumpInfo,indent=0, separators=(',', ':')).replace('\n','') +"\n"
1495 except Exception as e:
1496 errorInfo+= "Dump create exception encountered: {eInfo}\n".format(eInfo=e)
1497
1498 output = {}
1499 output['errors'] = errorInfo
1500 output['dumpcount'] = dumpcount
1501 return output
1502
1503def csdInventory(host, args,session, fileDir):
1504 """
1505 Collects the BMC inventory, retrying if necessary
1506
1507 @param host: string, the hostname or IP address of the bmc
1508 @param args: contains additional arguments used by the collectServiceData sub command
1509 @param session: the active session to use
1510 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1511 @param fileDir: string representation of the path to use for putting files created
1512 """
1513 errorInfo = "===========Inventory =============\n"
1514 output={}
1515 inventoryCollected = False
1516 try:
1517 for i in range(3):
1518 frulist = fruPrint(host, args, session)
1519 if 'Hardware' in frulist:
1520 inventoryCollected = True
1521 break
1522 else:
1523 errorInfo += json.dumps(frulist, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n'
1524 except Exception as e:
1525 errorInfo += "Inventory collection exception: {eInfo}\n".format(eInfo=e)
1526 if inventoryCollected:
1527 try:
1528 with open(fileDir +os.sep+'inventory.txt', 'w') as f:
1529 f.write(json.dumps(frulist, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n')
1530 print("Inventory collected and stored in " + fileDir + os.sep + "inventory.txt")
1531 output['fileLoc'] = fileDir+os.sep+'inventory.txt'
1532 except Exception as e:
1533 print("Failed to write inventory to file.")
1534 errorInfo += "Error writing inventory to the file. Exception: {eInfo}\n".format(eInfo=e)
1535
1536 output['errors'] = errorInfo
1537
1538 return output
1539
1540def csdSensors(host, args,session, fileDir):
1541 """
1542 Collects the BMC sensor readings, retrying if necessary
1543
1544 @param host: string, the hostname or IP address of the bmc
1545 @param args: contains additional arguments used by the collectServiceData sub command
1546 @param session: the active session to use
1547 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1548 @param fileDir: string representation of the path to use for putting files created
1549 """
1550 errorInfo = "===========Sensors =============\n"
1551 sensorsCollected = False
1552 output={}
1553 try:
1554 d = vars(args)
1555 d['json'] = False
1556 except Exception as e:
1557 errorInfo += "Failed to set the json flag to False \n Exception: {eInfo}\n".format(eInfo=e)
1558
1559 try:
1560 for i in range(3):
1561 sensorReadings = sensor(host, args, session)
1562 if 'OCC0' in sensorReadings:
1563 sensorsCollected = True
1564 break
1565 else:
1566 errorInfo += sensorReadings
1567 except Exception as e:
1568 errorInfo += "Sensor reading collection exception: {eInfo}\n".format(eInfo=e)
1569 if sensorsCollected:
1570 try:
1571 with open(fileDir +os.sep+'sensorReadings.txt', 'w') as f:
1572 f.write(sensorReadings)
1573 print("Sensor readings collected and stored in " + fileDir + os.sep+ "sensorReadings.txt")
1574 output['fileLoc'] = fileDir+os.sep+'sensorReadings.txt'
1575 except Exception as e:
1576 print("Failed to write sensor readings to file system.")
1577 errorInfo += "Error writing sensor readings to the file. Exception: {eInfo}\n".format(eInfo=e)
1578
1579 output['errors'] = errorInfo
1580 return output
1581
1582def csdLEDs(host,args, session, fileDir):
1583 """
1584 Collects the BMC LED status, retrying if necessary
1585
1586 @param host: string, the hostname or IP address of the bmc
1587 @param args: contains additional arguments used by the collectServiceData sub command
1588 @param session: the active session to use
1589 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1590 @param fileDir: string representation of the path to use for putting files created
1591 """
1592 errorInfo = "===========LEDs =============\n"
1593 ledsCollected = False
1594 output={}
1595 try:
1596 d = vars(args)
1597 d['json'] = True
1598 except Exception as e:
1599 errorInfo += "Failed to set the json flag to False \n Exception: {eInfo}\n".format(eInfo=e)
1600 try:
1601 url="https://"+host+"/xyz/openbmc_project/led/enumerate"
1602 httpHeader = {'Content-Type':'application/json'}
1603 for i in range(3):
1604 try:
1605 ledRes = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
1606 if ledRes.status_code == 200:
1607 ledsCollected = True
1608 leds = ledRes.json()['data']
1609 break
1610 else:
1611 errorInfo += ledRes.text
1612 except(requests.exceptions.Timeout):
1613 errorInfo+=json.dumps( connectionErrHandler(args.json, "Timeout", None), sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n'
1614 except(requests.exceptions.ConnectionError) as err:
1615 errorInfo += json.dumps(connectionErrHandler(args.json, "ConnectionError", err), sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n'
1616 except Exception as e:
1617 errorInfo += "LED status collection exception: {eInfo}\n".format(eInfo=e)
1618
1619 if ledsCollected:
1620 try:
1621 with open(fileDir +os.sep+'ledStatus.txt', 'w') as f:
1622 f.write(json.dumps(leds, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n')
1623 print("LED status collected and stored in " + fileDir + os.sep+ "ledStatus.txt")
1624 output['fileLoc'] = fileDir+os.sep+'ledStatus.txt'
1625 except Exception as e:
1626 print("Failed to write LED status to file system.")
1627 errorInfo += "Error writing LED status to the file. Exception: {eInfo}\n".format(eInfo=e)
1628
1629 output['errors'] = errorInfo
1630 return output
1631
1632def csdSelShortList(host, args, session, fileDir):
1633 """
1634 Collects the BMC log entries, retrying if necessary
1635
1636 @param host: string, the hostname or IP address of the bmc
1637 @param args: contains additional arguments used by the collectServiceData sub command
1638 @param session: the active session to use
1639 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1640 @param fileDir: string representation of the path to use for putting files created
1641 """
1642 errorInfo = "===========SEL Short List =============\n"
1643 selsCollected = False
1644 output={}
1645 try:
1646 d = vars(args)
1647 d['json'] = False
1648 except Exception as e:
1649 errorInfo += "Failed to set the json flag to False \n Exception: {eInfo}\n".format(eInfo=e)
1650
1651 try:
1652 for i in range(3):
1653 sels = selPrint(host,args,session)
1654 if '----Active Alerts----' in sels or 'No log entries found' in sels or '----Historical Alerts----' in sels:
1655 selsCollected = True
1656 break
1657 else:
1658 errorInfo += sels + '\n'
1659 except Exception as e:
1660 errorInfo += "SEL short list collection exception: {eInfo}\n".format(eInfo=e)
1661
1662 if selsCollected:
1663 try:
1664 with open(fileDir +os.sep+'SELshortlist.txt', 'w') as f:
1665 f.write(sels)
1666 print("SEL short list collected and stored in " + fileDir + os.sep+ "SELshortlist.txt")
1667 output['fileLoc'] = fileDir+os.sep+'SELshortlist.txt'
1668 except Exception as e:
1669 print("Failed to write SEL short list to file system.")
1670 errorInfo += "Error writing SEL short list to the file. Exception: {eInfo}\n".format(eInfo=e)
1671
1672 output['errors'] = errorInfo
1673 return output
1674
1675def csdParsedSels(host, args, session, fileDir):
1676 """
1677 Collects the BMC log entries, retrying if necessary
1678
1679 @param host: string, the hostname or IP address of the bmc
1680 @param args: contains additional arguments used by the collectServiceData sub command
1681 @param session: the active session to use
1682 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1683 @param fileDir: string representation of the path to use for putting files created
1684 """
1685 errorInfo = "===========SEL Parsed List =============\n"
1686 selsCollected = False
1687 output={}
1688 try:
1689 d = vars(args)
1690 d['json'] = True
1691 d['fullEsel'] = True
1692 except Exception as e:
1693 errorInfo += "Failed to set the json flag to True \n Exception: {eInfo}\n".format(eInfo=e)
1694
1695 try:
1696 for i in range(3):
1697 parsedfullsels = json.loads(selPrint(host,args,session))
1698 if 'numAlerts' in parsedfullsels:
1699 selsCollected = True
1700 break
1701 else:
1702 errorInfo += parsedfullsels + '\n'
1703 except Exception as e:
1704 errorInfo += "Parsed full SELs collection exception: {eInfo}\n".format(eInfo=e)
1705
1706 if selsCollected:
1707 try:
1708 sortedSELs = sortSELs(parsedfullsels)
1709 with open(fileDir +os.sep+'parsedSELs.txt', 'w') as f:
1710 for log in sortedSELs[0]:
1711 esel = ""
1712 parsedfullsels[sortedSELs[1][str(log)]]['timestamp'] = datetime.datetime.fromtimestamp(int(parsedfullsels[sortedSELs[1][str(log)]]['timestamp']/1000)).strftime("%Y-%m-%d %H:%M:%S")
1713 if ('raweSEL' in parsedfullsels[sortedSELs[1][str(log)]] and args.devdebug):
1714 esel = parsedfullsels[sortedSELs[1][str(log)]]['raweSEL']
1715 del parsedfullsels[sortedSELs[1][str(log)]]['raweSEL']
1716 f.write(json.dumps(parsedfullsels[sortedSELs[1][str(log)]],sort_keys=True, indent=4, separators=(',', ': ')))
1717 if(args.devdebug and esel != ""):
1718 f.write(parseESEL(args, esel))
1719 print("Parsed SELs collected and stored in " + fileDir + os.sep+ "parsedSELs.txt")
1720 output['fileLoc'] = fileDir+os.sep+'parsedSELs.txt'
1721 except Exception as e:
1722 print("Failed to write fully parsed SELs to file system.")
1723 errorInfo += "Error writing fully parsed SELs to the file. Exception: {eInfo}\n".format(eInfo=e)
1724
1725 output['errors'] = errorInfo
1726 return output
1727
1728def csdFullEnumeration(host, args, session, fileDir):
1729 """
1730 Collects a full enumeration of /xyz/openbmc_project/, retrying if necessary
1731
1732 @param host: string, the hostname or IP address of the bmc
1733 @param args: contains additional arguments used by the collectServiceData sub command
1734 @param session: the active session to use
1735 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1736 @param fileDir: string representation of the path to use for putting files created
1737 """
1738 errorInfo = "===========BMC Full Enumeration =============\n"
1739 bmcFullCollected = False
1740 output={}
1741 try:
1742 d = vars(args)
1743 d['json'] = True
1744 except Exception as e:
1745 errorInfo += "Failed to set the json flag to False \n Exception: {eInfo}\n".format(eInfo=e)
1746 try:
1747 print("Attempting to get a full BMC enumeration")
1748 url="https://"+host+"/xyz/openbmc_project/enumerate"
1749 httpHeader = {'Content-Type':'application/json'}
1750 for i in range(3):
1751 try:
1752 bmcRes = session.get(url, headers=jsonHeader, verify=False, timeout=180)
1753 if bmcRes.status_code == 200:
1754 bmcFullCollected = True
1755 fullEnumeration = bmcRes.json()
1756 break
1757 else:
1758 errorInfo += bmcRes.text
1759 except(requests.exceptions.Timeout):
1760 errorInfo+=json.dumps( connectionErrHandler(args.json, "Timeout", None), sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n'
1761 except(requests.exceptions.ConnectionError) as err:
1762 errorInfo += json.dumps(connectionErrHandler(args.json, "ConnectionError", err), sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n'
1763 except Exception as e:
1764 errorInfo += "RAW BMC data collection exception: {eInfo}\n".format(eInfo=e)
1765
1766 if bmcFullCollected:
1767 try:
1768 with open(fileDir +os.sep+'bmcFullRaw.txt', 'w') as f:
1769 f.write(json.dumps(fullEnumeration, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n')
1770 print("RAW BMC data collected and saved into " + fileDir + os.sep+ "bmcFullRaw.txt")
1771 output['fileLoc'] = fileDir+os.sep+'bmcFullRaw.txt'
1772 except Exception as e:
1773 print("Failed to write RAW BMC data to file system.")
1774 errorInfo += "Error writing RAW BMC data collection to the file. Exception: {eInfo}\n".format(eInfo=e)
1775
1776 output['errors'] = errorInfo
1777 return output
1778
1779def csdCollectAllDumps(host, args, session, fileDir):
1780 """
1781 Collects all of the bmc dump files and stores them in fileDir
1782
1783 @param host: string, the hostname or IP address of the bmc
1784 @param args: contains additional arguments used by the collectServiceData sub command
1785 @param session: the active session to use
1786 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1787 @param fileDir: string representation of the path to use for putting files created
1788 """
1789
1790 errorInfo = "===========BMC Dump Collection =============\n"
1791 dumpListCollected = False
1792 output={}
1793 dumpList = {}
1794 try:
1795 d = vars(args)
1796 d['json'] = True
1797 d['dumpSaveLoc'] = fileDir
1798 except Exception as e:
1799 errorInfo += "Failed to set the json flag to True, or failed to set the dumpSave Location \n Exception: {eInfo}\n".format(eInfo=e)
1800
1801 print('Collecting bmc dump files')
1802
1803 try:
1804 for i in range(3):
1805 dumpResp = bmcDumpList(host, args, session)
1806 if 'message' in dumpResp:
1807 if 'ok' in dumpResp['message'].lower():
1808 dumpList = dumpResp['data']
1809 dumpListCollected = True
1810 break
1811 else:
1812 errorInfo += "Status was not OK when retrieving the list of dumps available. \n Response: \n{resp}\n".format(resp=dumpResp)
1813 else:
1814 errorInfo += "Invalid response received from the BMC while retrieving the list of dumps available.\n {resp}\n".format(resp=dumpResp)
1815 except Exception as e:
1816 errorInfo += "BMC dump list exception: {eInfo}\n".format(eInfo=e)
1817
1818 if dumpListCollected:
1819 output['fileList'] = []
1820 for dump in dumpList:
1821 try:
1822 if '/xyz/openbmc_project/dump/internal/manager' not in dump:
1823 d['dumpNum'] = int(dump.strip().split('/')[-1])
1824 print('retrieving dump file ' + str(d['dumpNum']))
1825 filename = bmcDumpRetrieve(host, args, session).split('Saved as ')[-1]
1826 output['fileList'].append(filename)
1827 except Exception as e:
1828 print("Unable to collect dump: {dumpInfo}".format(dumpInfo=dump))
1829 errorInfo += "Exception collecting a bmc dump {dumpInfo}\n {eInfo}\n".format(dumpInfo=dump, eInfo=e)
1830 output['errors'] = errorInfo
1831 return output
Justin Thalere412dc22018-01-12 16:28:24 -06001832
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001833def collectServiceData(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001834 """
1835 Collects all data needed for service from the BMC
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001836
Justin Thalere412dc22018-01-12 16:28:24 -06001837 @param host: string, the hostname or IP address of the bmc
1838 @param args: contains additional arguments used by the collectServiceData sub command
1839 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001840 @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 -06001841 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001842
Justin Thaler22b1bb52018-03-15 13:31:32 -05001843 global toolVersion
Justin Thaler666cf342019-01-23 14:44:27 -06001844 filelist = []
1845 errorInfo = ""
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001846
Justin Thaler666cf342019-01-23 14:44:27 -06001847 #get current number of bmc dumps and create a new bmc dump
1848 dumpInitdata = csdDumpInitiate(host, args, session)
1849 dumpcount = dumpInitdata['dumpcount']
1850 errorInfo += dumpInitdata['errors']
1851 #create the directory to put files
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001852 try:
1853 args.silent = True
Justin Thalercf1deae2018-05-25 19:35:21 -05001854 myDir = tempfile.gettempdir()+os.sep + host + "--" + datetime.datetime.now().strftime("%Y-%m-%d_%H.%M.%S")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001855 os.makedirs(myDir)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001856
Justin Thaler666cf342019-01-23 14:44:27 -06001857 except Exception as e:
1858 print('Unable to create the temporary directory for data collection. Ensure sufficient privileges to create temporary directory. Aborting.')
1859 return("Python exception: {eInfo}".format(eInfo = e))
1860
1861 #Collect Inventory
1862 inventoryData = csdInventory(host, args, session, myDir)
1863 if 'fileLoc' in inventoryData:
1864 filelist.append(inventoryData['fileLoc'])
1865 errorInfo += inventoryData['errors']
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001866 #Read all the sensor and OCC status
Justin Thaler666cf342019-01-23 14:44:27 -06001867 sensorData = csdSensors(host,args,session,myDir)
1868 if 'fileLoc' in sensorData:
1869 filelist.append(sensorData['fileLoc'])
1870 errorInfo += sensorData['errors']
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001871 #Collect all of the LEDs status
Justin Thaler666cf342019-01-23 14:44:27 -06001872 ledStatus = csdLEDs(host, args, session, myDir)
1873 if 'fileLoc' in ledStatus:
1874 filelist.append(ledStatus['fileLoc'])
1875 errorInfo += ledStatus['errors']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001876
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001877 #Collect the bmc logs
Justin Thaler666cf342019-01-23 14:44:27 -06001878 selShort = csdSelShortList(host, args, session, myDir)
1879 if 'fileLoc' in selShort:
1880 filelist.append(selShort['fileLoc'])
1881 errorInfo += selShort['errors']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001882
Justin Thaler666cf342019-01-23 14:44:27 -06001883 parsedSELs = csdParsedSels(host, args, session, myDir)
1884 if 'fileLoc' in parsedSELs:
1885 filelist.append(parsedSELs['fileLoc'])
1886 errorInfo += parsedSELs['errors']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001887
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001888 #collect RAW bmc enumeration
Justin Thaler666cf342019-01-23 14:44:27 -06001889 bmcRaw = csdFullEnumeration(host, args, session, myDir)
1890 if 'fileLoc' in bmcRaw:
1891 filelist.append(bmcRaw['fileLoc'])
1892 errorInfo += bmcRaw['errors']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001893
Justin Thaler666cf342019-01-23 14:44:27 -06001894 #wait for new dump to finish being created
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001895 waitingForNewDump = True
1896 count = 0;
Justin Thaler666cf342019-01-23 14:44:27 -06001897 print("Waiting for new BMC dump to finish being created.")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001898 while(waitingForNewDump):
Justin Thaler666cf342019-01-23 14:44:27 -06001899 dumpList = bmcDumpList(host, args, session)['data']
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001900 if len(dumpList) > dumpcount:
1901 waitingForNewDump = False
1902 break;
1903 elif(count>30):
1904 print("Timed out waiting for bmc to make a new dump file. Dump space may be full.")
1905 break;
1906 else:
1907 time.sleep(2)
1908 count += 1
Justin Thaler666cf342019-01-23 14:44:27 -06001909
1910 #collect all of the dump files
1911 getBMCDumps = csdCollectAllDumps(host, args, session, myDir)
1912 if 'fileList' in getBMCDumps:
1913 filelist+= getBMCDumps['fileList']
1914 errorInfo += getBMCDumps['errors']
1915
1916 #write the runtime errors to a file
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001917 try:
Justin Thaler666cf342019-01-23 14:44:27 -06001918 with open(myDir +os.sep+'openbmctoolRuntimeErrors.txt', 'w') as f:
1919 f.write(errorInfo)
1920 print("OpenBMC tool runtime errors collected and stored in " + myDir + os.sep+ "openbmctoolRuntimeErrors.txt")
1921 filelist.append(myDir+os.sep+'openbmctoolRuntimeErrors.txt')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001922 except Exception as e:
Justin Thaler666cf342019-01-23 14:44:27 -06001923 print("Failed to write OpenBMC tool runtime errors to file system.")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001924
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001925 #create the zip file
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001926 try:
Justin Thalercf1deae2018-05-25 19:35:21 -05001927 filename = myDir.split(tempfile.gettempdir()+os.sep)[-1] + "_" + toolVersion + '_openbmc.zip'
Justin Thaler666cf342019-01-23 14:44:27 -06001928 zf = zipfile.ZipFile(myDir+os.sep + filename, 'w')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001929 for myfile in filelist:
1930 zf.write(myfile, os.path.basename(myfile))
1931 zf.close()
Justin Thaler666cf342019-01-23 14:44:27 -06001932 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 -06001933 except Exception as e:
1934 print("Failed to create zip file with collected information")
Justin Thaler666cf342019-01-23 14:44:27 -06001935 return "data collection finished"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001936
Justin Thalere412dc22018-01-12 16:28:24 -06001937
1938def healthCheck(host, args, session):
1939 """
1940 runs a health check on the platform
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001941
Justin Thalere412dc22018-01-12 16:28:24 -06001942 @param host: string, the hostname or IP address of the bmc
1943 @param args: contains additional arguments used by the bmc sub command
1944 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001945 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1946 """
Justin Thalere412dc22018-01-12 16:28:24 -06001947 #check fru status and get as json to easily work through
1948 d = vars(args)
1949 useJson = d['json']
1950 d['json'] = True
1951 d['verbose']= False
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001952
Justin Thalere412dc22018-01-12 16:28:24 -06001953 frus = json.loads(fruStatus(host, args, session))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001954
Justin Thalere412dc22018-01-12 16:28:24 -06001955 hwStatus= "OK"
1956 performanceStatus = "OK"
1957 for key in frus:
1958 if frus[key]["Functional"] == "No" and frus[key]["Present"] == "Yes":
1959 hwStatus= "Degraded"
Justin Thalerfb9c81c2018-07-16 11:14:37 -05001960 if("power_supply" in key or "powersupply" in key):
1961 gpuCount =0
1962 for comp in frus:
Justin Thalere412dc22018-01-12 16:28:24 -06001963 if "gv100card" in comp:
1964 gpuCount +=1
1965 if gpuCount > 4:
1966 hwStatus = "Critical"
1967 performanceStatus="Degraded"
1968 break;
1969 elif("fan" in key):
1970 hwStatus = "Degraded"
1971 else:
1972 performanceStatus = "Degraded"
1973 if useJson:
1974 output = {"Hardware Status": hwStatus, "Performance": performanceStatus}
1975 output = json.dumps(output, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False)
1976 else:
1977 output = ("Hardware Status: " + hwStatus +
1978 "\nPerformance: " +performanceStatus )
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001979
1980
Justin Thalere412dc22018-01-12 16:28:24 -06001981 #SW407886: Clear the duplicate entries
1982 #collect the dups
1983 d['devdebug'] = False
1984 sels = json.loads(selPrint(host, args, session))
1985 logNums2Clr = []
1986 oldestLogNum={"logNum": "bogus" ,"key" : ""}
1987 count = 0
1988 if sels['numAlerts'] > 0:
1989 for key in sels:
1990 if "numAlerts" in key:
1991 continue
1992 try:
1993 if "slave@00:00/00:00:00:06/sbefifo1-dev0/occ1-dev0" in sels[key]['Message']:
1994 count += 1
1995 if count > 1:
1996 #preserve first occurrence
1997 if sels[key]['timestamp'] < sels[oldestLogNum['key']]['timestamp']:
1998 oldestLogNum['key']=key
1999 oldestLogNum['logNum'] = sels[key]['logNum']
2000 else:
2001 oldestLogNum['key']=key
2002 oldestLogNum['logNum'] = sels[key]['logNum']
2003 logNums2Clr.append(sels[key]['logNum'])
2004 except KeyError:
2005 continue
2006 if(count >0):
2007 logNums2Clr.remove(oldestLogNum['logNum'])
2008 #delete the dups
2009 if count >1:
Justin Thalere412dc22018-01-12 16:28:24 -06002010 data = "{\"data\": [] }"
2011 for logNum in logNums2Clr:
2012 url = "https://"+ host+ "/xyz/openbmc_project/logging/entry/"+logNum+"/action/Delete"
2013 try:
Justin Thaler27197622019-01-23 14:42:11 -06002014 session.post(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002015 except(requests.exceptions.Timeout):
2016 deleteFailed = True
2017 except(requests.exceptions.ConnectionError) as err:
2018 deleteFailed = True
2019 #End of defect resolve code
2020 d['json'] = useJson
2021 return output
2022
2023
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002024
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002025def bmc(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06002026 """
2027 handles various bmc level commands, currently bmc rebooting
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002028
Justin Thalere412dc22018-01-12 16:28:24 -06002029 @param host: string, the hostname or IP address of the bmc
2030 @param args: contains additional arguments used by the bmc sub command
2031 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002032 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
2033 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002034 if(args.type is not None):
2035 return bmcReset(host, args, session)
Justin Thalere412dc22018-01-12 16:28:24 -06002036 if(args.info):
2037 return "Not implemented at this time"
2038
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002039
Justin Thalere412dc22018-01-12 16:28:24 -06002040
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002041def bmcReset(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06002042 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002043 controls resetting the bmc. warm reset reboots the bmc, cold reset removes the configuration and reboots.
2044
Justin Thalere412dc22018-01-12 16:28:24 -06002045 @param host: string, the hostname or IP address of the bmc
2046 @param args: contains additional arguments used by the bmcReset sub command
2047 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002048 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
2049 """
Justin Thaler22b1bb52018-03-15 13:31:32 -05002050 if checkFWactivation(host, args, session):
2051 return ("BMC reset control disabled during firmware activation")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002052 if(args.type == "warm"):
2053 print("\nAttempting to reboot the BMC...:")
2054 url="https://"+host+"/xyz/openbmc_project/state/bmc0/attr/RequestedBMCTransition"
Justin Thalere412dc22018-01-12 16:28:24 -06002055 data = '{"data":"xyz.openbmc_project.State.BMC.Transition.Reboot"}'
Justin Thaler27197622019-01-23 14:42:11 -06002056 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002057 return res.text
2058 elif(args.type =="cold"):
Justin Thalere412dc22018-01-12 16:28:24 -06002059 print("\nAttempting to reboot the BMC...:")
2060 url="https://"+host+"/xyz/openbmc_project/state/bmc0/attr/RequestedBMCTransition"
Justin Thalere412dc22018-01-12 16:28:24 -06002061 data = '{"data":"xyz.openbmc_project.State.BMC.Transition.Reboot"}'
Justin Thaler27197622019-01-23 14:42:11 -06002062 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002063 return res.text
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002064 else:
2065 return "invalid command"
Justin Thalere412dc22018-01-12 16:28:24 -06002066
2067def gardClear(host, args, session):
2068 """
2069 clears the gard records from the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002070
Justin Thalere412dc22018-01-12 16:28:24 -06002071 @param host: string, the hostname or IP address of the bmc
2072 @param args: contains additional arguments used by the gardClear sub command
2073 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002074 """
Justin Thalere412dc22018-01-12 16:28:24 -06002075 url="https://"+host+"/org/open_power/control/gard/action/Reset"
Justin Thalere412dc22018-01-12 16:28:24 -06002076 data = '{"data":[]}'
2077 try:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002078
Justin Thaler27197622019-01-23 14:42:11 -06002079 res = session.post(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002080 if res.status_code == 404:
2081 return "Command not supported by this firmware version"
2082 else:
2083 return res.text
2084 except(requests.exceptions.Timeout):
2085 return connectionErrHandler(args.json, "Timeout", None)
2086 except(requests.exceptions.ConnectionError) as err:
2087 return connectionErrHandler(args.json, "ConnectionError", err)
2088
2089def activateFWImage(host, args, session):
2090 """
2091 activates a firmware image on the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002092
Justin Thalere412dc22018-01-12 16:28:24 -06002093 @param host: string, the hostname or IP address of the bmc
2094 @param args: contains additional arguments used by the fwflash sub command
2095 @param session: the active session to use
2096 @param fwID: the unique ID of the fw image to activate
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002097 """
Justin Thalere412dc22018-01-12 16:28:24 -06002098 fwID = args.imageID
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002099
Justin Thalere412dc22018-01-12 16:28:24 -06002100 #determine the existing versions
Justin Thalere412dc22018-01-12 16:28:24 -06002101 url="https://"+host+"/xyz/openbmc_project/software/enumerate"
2102 try:
Justin Thaler27197622019-01-23 14:42:11 -06002103 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002104 except(requests.exceptions.Timeout):
2105 return connectionErrHandler(args.json, "Timeout", None)
2106 except(requests.exceptions.ConnectionError) as err:
2107 return connectionErrHandler(args.json, "ConnectionError", err)
2108 existingSoftware = json.loads(resp.text)['data']
2109 altVersionID = ''
2110 versionType = ''
2111 imageKey = '/xyz/openbmc_project/software/'+fwID
2112 if imageKey in existingSoftware:
2113 versionType = existingSoftware[imageKey]['Purpose']
2114 for key in existingSoftware:
2115 if imageKey == key:
2116 continue
2117 if 'Purpose' in existingSoftware[key]:
2118 if versionType == existingSoftware[key]['Purpose']:
2119 altVersionID = key.split('/')[-1]
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002120
2121
2122
2123
Justin Thalere412dc22018-01-12 16:28:24 -06002124 url="https://"+host+"/xyz/openbmc_project/software/"+ fwID + "/attr/Priority"
2125 url1="https://"+host+"/xyz/openbmc_project/software/"+ altVersionID + "/attr/Priority"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002126 data = "{\"data\": 0}"
Justin Thalere412dc22018-01-12 16:28:24 -06002127 data1 = "{\"data\": 1 }"
2128 try:
Justin Thaler27197622019-01-23 14:42:11 -06002129 resp = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
2130 resp1 = session.put(url1, headers=jsonHeader, data=data1, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002131 except(requests.exceptions.Timeout):
2132 return connectionErrHandler(args.json, "Timeout", None)
2133 except(requests.exceptions.ConnectionError) as err:
2134 return connectionErrHandler(args.json, "ConnectionError", err)
2135 if(not args.json):
2136 if resp.status_code == 200 and resp1.status_code == 200:
Justin Thaler22b1bb52018-03-15 13:31:32 -05002137 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 -06002138 else:
2139 return "Firmware activation failed."
2140 else:
2141 return resp.text + resp1.text
Justin Thaler22b1bb52018-03-15 13:31:32 -05002142
2143def activateStatus(host, args, session):
2144 if checkFWactivation(host, args, session):
2145 return("Firmware is currently being activated. Do not reboot the BMC or start the Host OS")
2146 else:
2147 return("No firmware activations are pending")
2148
2149def extractFWimage(path, imageType):
2150 """
2151 extracts the bmc image and returns information about the package
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002152
Justin Thaler22b1bb52018-03-15 13:31:32 -05002153 @param path: the path and file name of the firmware image
2154 @param imageType: The type of image the user is trying to flash. Host or BMC
2155 @return: the image id associated with the package. returns an empty string on error.
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002156 """
Justin Thaler22b1bb52018-03-15 13:31:32 -05002157 f = tempfile.TemporaryFile()
2158 tmpDir = tempfile.gettempdir()
2159 newImageID = ""
2160 if os.path.exists(path):
2161 try:
2162 imageFile = tarfile.open(path,'r')
2163 contents = imageFile.getmembers()
2164 for tf in contents:
2165 if 'MANIFEST' in tf.name:
2166 imageFile.extract(tf.name, path=tmpDir)
2167 with open(tempfile.gettempdir() +os.sep+ tf.name, 'r') as imageInfo:
2168 for line in imageInfo:
2169 if 'purpose' in line:
2170 purpose = line.split('=')[1]
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002171 if imageType not in purpose.split('.')[-1]:
Justin Thaler22b1bb52018-03-15 13:31:32 -05002172 print('The specified image is not for ' + imageType)
2173 print('Please try again with the image for ' + imageType)
2174 return ""
2175 if 'version' == line.split('=')[0]:
2176 version = line.split('=')[1].strip().encode('utf-8')
2177 m = hashlib.sha512()
2178 m.update(version)
2179 newImageID = m.hexdigest()[:8]
2180 break
2181 try:
2182 os.remove(tempfile.gettempdir() +os.sep+ tf.name)
2183 except OSError:
2184 pass
2185 return newImageID
2186 except tarfile.ExtractError as e:
2187 print('Unable to extract information from the firmware file.')
2188 print('Ensure you have write access to the directory: ' + tmpDir)
2189 return newImageID
2190 except tarfile.TarError as e:
2191 print('This is not a valid firmware file.')
2192 return newImageID
2193 print("This is not a valid firmware file.")
2194 return newImageID
2195 else:
2196 print('The filename and path provided are not valid.')
2197 return newImageID
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002198
Justin Thaler22b1bb52018-03-15 13:31:32 -05002199def getAllFWImageIDs(fwInvDict):
2200 """
2201 gets a list of all the firmware image IDs
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002202
Justin Thaler22b1bb52018-03-15 13:31:32 -05002203 @param fwInvDict: the dictionary to search for FW image IDs
2204 @return: list containing string representation of the found image ids
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002205 """
Justin Thaler22b1bb52018-03-15 13:31:32 -05002206 idList = []
2207 for key in fwInvDict:
2208 if 'Version' in fwInvDict[key]:
2209 idList.append(key.split('/')[-1])
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002210 return idList
2211
Justin Thalere412dc22018-01-12 16:28:24 -06002212def fwFlash(host, args, session):
2213 """
2214 updates the bmc firmware and pnor firmware
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002215
Justin Thalere412dc22018-01-12 16:28:24 -06002216 @param host: string, the hostname or IP address of the bmc
2217 @param args: contains additional arguments used by the fwflash sub command
2218 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002219 """
Justin Thaler22b1bb52018-03-15 13:31:32 -05002220 d = vars(args)
Justin Thalere412dc22018-01-12 16:28:24 -06002221 if(args.type == 'bmc'):
2222 purp = 'BMC'
2223 else:
2224 purp = 'Host'
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002225
2226 #check power state of the machine. No concurrent FW updates allowed
Justin Thaler22b1bb52018-03-15 13:31:32 -05002227 d['powcmd'] = 'status'
2228 powerstate = chassisPower(host, args, session)
2229 if 'Chassis Power State: On' in powerstate:
2230 return("Aborting firmware update. Host is powered on. Please turn off the host and try again.")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002231
Justin Thaler22b1bb52018-03-15 13:31:32 -05002232 #determine the existing images on the bmc
Justin Thalere412dc22018-01-12 16:28:24 -06002233 url="https://"+host+"/xyz/openbmc_project/software/enumerate"
2234 try:
Justin Thaler27197622019-01-23 14:42:11 -06002235 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002236 except(requests.exceptions.Timeout):
2237 return connectionErrHandler(args.json, "Timeout", None)
2238 except(requests.exceptions.ConnectionError) as err:
2239 return connectionErrHandler(args.json, "ConnectionError", err)
2240 oldsoftware = json.loads(resp.text)['data']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002241
Justin Thaler22b1bb52018-03-15 13:31:32 -05002242 #Extract the tar and get information from the manifest file
2243 newversionID = extractFWimage(args.fileloc, purp)
2244 if newversionID == "":
2245 return "Unable to verify FW image."
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002246
2247
Justin Thaler22b1bb52018-03-15 13:31:32 -05002248 #check if the new image is already on the bmc
2249 if newversionID not in getAllFWImageIDs(oldsoftware):
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002250
Justin Thaler22b1bb52018-03-15 13:31:32 -05002251 #upload the file
2252 httpHeader = {'Content-Type':'application/octet-stream'}
Matt Spinler220c3c42019-01-04 15:09:29 -06002253 httpHeader.update(xAuthHeader)
Justin Thaler22b1bb52018-03-15 13:31:32 -05002254 url="https://"+host+"/upload/image"
2255 data=open(args.fileloc,'rb').read()
2256 print("Uploading file to BMC")
Justin Thalere412dc22018-01-12 16:28:24 -06002257 try:
Justin Thaler22b1bb52018-03-15 13:31:32 -05002258 resp = session.post(url, headers=httpHeader, data=data, verify=False)
Justin Thalere412dc22018-01-12 16:28:24 -06002259 except(requests.exceptions.Timeout):
2260 return connectionErrHandler(args.json, "Timeout", None)
2261 except(requests.exceptions.ConnectionError) as err:
2262 return connectionErrHandler(args.json, "ConnectionError", err)
Justin Thaler22b1bb52018-03-15 13:31:32 -05002263 if resp.status_code != 200:
2264 return "Failed to upload the file to the bmc"
Justin Thalere412dc22018-01-12 16:28:24 -06002265 else:
Justin Thaler22b1bb52018-03-15 13:31:32 -05002266 print("Upload complete.")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002267
Justin Thaler22b1bb52018-03-15 13:31:32 -05002268 #verify bmc processed the image
2269 software ={}
2270 for i in range(0, 5):
Justin Thaler22b1bb52018-03-15 13:31:32 -05002271 url="https://"+host+"/xyz/openbmc_project/software/enumerate"
2272 try:
Justin Thaler27197622019-01-23 14:42:11 -06002273 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thaler22b1bb52018-03-15 13:31:32 -05002274 except(requests.exceptions.Timeout):
2275 return connectionErrHandler(args.json, "Timeout", None)
2276 except(requests.exceptions.ConnectionError) as err:
2277 return connectionErrHandler(args.json, "ConnectionError", err)
2278 software = json.loads(resp.text)['data']
2279 #check if bmc is done processing the new image
2280 if (newversionID in getAllFWImageIDs(software)):
Justin Thalere412dc22018-01-12 16:28:24 -06002281 break
Justin Thaler22b1bb52018-03-15 13:31:32 -05002282 else:
2283 time.sleep(15)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002284
Justin Thaler22b1bb52018-03-15 13:31:32 -05002285 #activate the new image
2286 print("Activating new image: "+newversionID)
2287 url="https://"+host+"/xyz/openbmc_project/software/"+ newversionID + "/attr/RequestedActivation"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002288 data = '{"data":"xyz.openbmc_project.Software.Activation.RequestedActivations.Active"}'
Justin Thaler22b1bb52018-03-15 13:31:32 -05002289 try:
Justin Thaler27197622019-01-23 14:42:11 -06002290 resp = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thaler22b1bb52018-03-15 13:31:32 -05002291 except(requests.exceptions.Timeout):
2292 return connectionErrHandler(args.json, "Timeout", None)
2293 except(requests.exceptions.ConnectionError) as err:
2294 return connectionErrHandler(args.json, "ConnectionError", err)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002295
Justin Thaler22b1bb52018-03-15 13:31:32 -05002296 #wait for the activation to complete, timeout after ~1 hour
2297 i=0
2298 while i < 360:
2299 url="https://"+host+"/xyz/openbmc_project/software/"+ newversionID
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002300 data = '{"data":"xyz.openbmc_project.Software.Activation.RequestedActivations.Active"}'
Justin Thaler22b1bb52018-03-15 13:31:32 -05002301 try:
Justin Thaler27197622019-01-23 14:42:11 -06002302 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thaler22b1bb52018-03-15 13:31:32 -05002303 except(requests.exceptions.Timeout):
2304 return connectionErrHandler(args.json, "Timeout", None)
2305 except(requests.exceptions.ConnectionError) as err:
2306 return connectionErrHandler(args.json, "ConnectionError", err)
2307 fwInfo = json.loads(resp.text)['data']
2308 if 'Activating' not in fwInfo['Activation'] and 'Activating' not in fwInfo['RequestedActivation']:
2309 print('')
2310 break
2311 else:
2312 sys.stdout.write('.')
2313 sys.stdout.flush()
2314 time.sleep(10) #check every 10 seconds
2315 return "Firmware flash and activation completed. Please reboot the bmc and then boot the host OS for the changes to take effect. "
2316 else:
2317 print("This image has been found on the bmc. Activating image: " + newversionID)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002318
Justin Thaler22b1bb52018-03-15 13:31:32 -05002319 d['imageID'] = newversionID
2320 return activateFWImage(host, args, session)
Justin Thalere412dc22018-01-12 16:28:24 -06002321
Justin Thaler3d71d402018-07-24 14:35:39 -05002322def getFWInventoryAttributes(rawFWInvItem, ID):
2323 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002324 gets and lists all of the firmware in the system.
2325
Justin Thaler3d71d402018-07-24 14:35:39 -05002326 @return: returns a dictionary containing the image attributes
2327 """
2328 reqActivation = rawFWInvItem["RequestedActivation"].split('.')[-1]
2329 pendingActivation = ""
2330 if reqActivation == "None":
2331 pendingActivation = "No"
2332 else:
2333 pendingActivation = "Yes"
2334 firmwareAttr = {ID: {
2335 "Purpose": rawFWInvItem["Purpose"].split('.')[-1],
2336 "Version": rawFWInvItem["Version"],
2337 "RequestedActivation": pendingActivation,
2338 "ID": ID}}
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002339
Justin Thaler3d71d402018-07-24 14:35:39 -05002340 if "ExtendedVersion" in rawFWInvItem:
2341 firmwareAttr[ID]['ExtendedVersion'] = rawFWInvItem['ExtendedVersion'].split(',')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002342 else:
Justin Thaler3d71d402018-07-24 14:35:39 -05002343 firmwareAttr[ID]['ExtendedVersion'] = ""
2344 return firmwareAttr
2345
2346def parseFWdata(firmwareDict):
2347 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002348 creates a dictionary with parsed firmware data
2349
Justin Thaler3d71d402018-07-24 14:35:39 -05002350 @return: returns a dictionary containing the image attributes
2351 """
2352 firmwareInfoDict = {"Functional": {}, "Activated":{}, "NeedsActivated":{}}
2353 for key in firmwareDict['data']:
2354 #check for valid endpoint
2355 if "Purpose" in firmwareDict['data'][key]:
2356 id = key.split('/')[-1]
2357 if firmwareDict['data'][key]['Activation'].split('.')[-1] == "Active":
2358 fwActivated = True
2359 else:
2360 fwActivated = False
Justin Thalercb68e062019-03-26 19:04:52 -05002361 if 'Priority' in firmwareDict['data'][key]:
2362 if firmwareDict['data'][key]['Priority'] == 0:
2363 firmwareInfoDict['Functional'].update(getFWInventoryAttributes(firmwareDict['data'][key], id))
2364 elif firmwareDict['data'][key]['Priority'] >= 0 and fwActivated:
2365 firmwareInfoDict['Activated'].update(getFWInventoryAttributes(firmwareDict['data'][key], id))
2366 else:
2367 firmwareInfoDict['NeedsActivated'].update(getFWInventoryAttributes(firmwareDict['data'][key], id))
Justin Thaler3d71d402018-07-24 14:35:39 -05002368 else:
Justin Thalercb68e062019-03-26 19:04:52 -05002369 firmwareInfoDict['NeedsActivated'].update(getFWInventoryAttributes(firmwareDict['data'][key], id))
Justin Thaler3d71d402018-07-24 14:35:39 -05002370 emptySections = []
2371 for key in firmwareInfoDict:
2372 if len(firmwareInfoDict[key])<=0:
2373 emptySections.append(key)
2374 for key in emptySections:
2375 del firmwareInfoDict[key]
2376 return firmwareInfoDict
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002377
Justin Thaler3d71d402018-07-24 14:35:39 -05002378def displayFWInvenory(firmwareInfoDict, args):
2379 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002380 gets and lists all of the firmware in the system.
2381
Justin Thaler3d71d402018-07-24 14:35:39 -05002382 @return: returns a string containing all of the firmware information
2383 """
2384 output = ""
2385 if not args.json:
2386 for key in firmwareInfoDict:
2387 for subkey in firmwareInfoDict[key]:
2388 firmwareInfoDict[key][subkey]['ExtendedVersion'] = str(firmwareInfoDict[key][subkey]['ExtendedVersion'])
2389 if not args.verbose:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002390 output = "---Running Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002391 colNames = ["Purpose", "Version", "ID"]
2392 keylist = ["Purpose", "Version", "ID"]
2393 output += tableDisplay(keylist, colNames, firmwareInfoDict["Functional"])
2394 if "Activated" in firmwareInfoDict:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002395 output += "\n---Available Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002396 output += tableDisplay(keylist, colNames, firmwareInfoDict["Activated"])
2397 if "NeedsActivated" in firmwareInfoDict:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002398 output += "\n---Needs Activated Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002399 output += tableDisplay(keylist, colNames, firmwareInfoDict["NeedsActivated"])
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002400
Justin Thaler3d71d402018-07-24 14:35:39 -05002401 else:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002402 output = "---Running Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002403 colNames = ["Purpose", "Version", "ID", "Pending Activation", "Extended Version"]
2404 keylist = ["Purpose", "Version", "ID", "RequestedActivation", "ExtendedVersion"]
2405 output += tableDisplay(keylist, colNames, firmwareInfoDict["Functional"])
2406 if "Activated" in firmwareInfoDict:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002407 output += "\n---Available Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002408 output += tableDisplay(keylist, colNames, firmwareInfoDict["Activated"])
2409 if "NeedsActivated" in firmwareInfoDict:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002410 output += "\n---Needs Activated Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002411 output += tableDisplay(keylist, colNames, firmwareInfoDict["NeedsActivated"])
2412 return output
2413 else:
2414 return str(json.dumps(firmwareInfoDict, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False))
2415
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002416def firmwareList(host, args, session):
Justin Thaler3d71d402018-07-24 14:35:39 -05002417 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002418 gets and lists all of the firmware in the system.
2419
Justin Thaler3d71d402018-07-24 14:35:39 -05002420 @return: returns a string containing all of the firmware information
2421 """
Justin Thaler3d71d402018-07-24 14:35:39 -05002422 url="https://{hostname}/xyz/openbmc_project/software/enumerate".format(hostname=host)
2423 try:
Justin Thaler27197622019-01-23 14:42:11 -06002424 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thaler3d71d402018-07-24 14:35:39 -05002425 except(requests.exceptions.Timeout):
2426 return(connectionErrHandler(args.json, "Timeout", None))
2427 firmwareDict = json.loads(res.text)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002428
Justin Thaler3d71d402018-07-24 14:35:39 -05002429 #sort the received information
2430 firmwareInfoDict = parseFWdata(firmwareDict)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002431
Justin Thaler3d71d402018-07-24 14:35:39 -05002432 #display the information
2433 return displayFWInvenory(firmwareInfoDict, args)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002434
2435
Adriana Kobylak5af2fad2018-11-08 12:33:43 -06002436def deleteFWVersion(host, args, session):
2437 """
2438 deletes a firmware version on the BMC
2439
2440 @param host: string, the hostname or IP address of the BMC
2441 @param args: contains additional arguments used by the fwflash sub command
2442 @param session: the active session to use
2443 @param fwID: the unique ID of the fw version to delete
2444 """
2445 fwID = args.versionID
2446
2447 print("Deleting version: "+fwID)
2448 url="https://"+host+"/xyz/openbmc_project/software/"+ fwID + "/action/Delete"
Adriana Kobylak5af2fad2018-11-08 12:33:43 -06002449 data = "{\"data\": [] }"
2450
2451 try:
Justin Thaler27197622019-01-23 14:42:11 -06002452 res = session.post(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Adriana Kobylak5af2fad2018-11-08 12:33:43 -06002453 except(requests.exceptions.Timeout):
2454 return(connectionErrHandler(args.json, "Timeout", None))
2455 if res.status_code == 200:
2456 return ('The firmware version has been deleted')
2457 else:
2458 return ('Unable to delete the specified firmware version')
2459
2460
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05002461def restLogging(host, args, session):
2462 """
2463 Called by the logging function. Turns REST API logging on/off.
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002464
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05002465 @param host: string, the hostname or IP address of the bmc
2466 @param args: contains additional arguments used by the logging sub command
2467 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002468 @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 -05002469 """
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05002470 url="https://"+host+"/xyz/openbmc_project/logging/rest_api_logs/attr/Enabled"
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05002471
2472 if(args.rest_logging == 'on'):
2473 data = '{"data": 1}'
2474 elif(args.rest_logging == 'off'):
2475 data = '{"data": 0}'
2476 else:
2477 return "Invalid logging rest_api command"
2478
2479 try:
Justin Thaler27197622019-01-23 14:42:11 -06002480 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05002481 except(requests.exceptions.Timeout):
2482 return(connectionErrHandler(args.json, "Timeout", None))
2483 return res.text
2484
2485
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002486def remoteLogging(host, args, session):
2487 """
2488 Called by the logging function. View config information for/disable remote logging (rsyslog).
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002489
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002490 @param host: string, the hostname or IP address of the bmc
2491 @param args: contains additional arguments used by the logging sub command
2492 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002493 @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 -05002494 """
2495
2496 url="https://"+host+"/xyz/openbmc_project/logging/config/remote"
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002497
2498 try:
2499 if(args.remote_logging == 'view'):
Justin Thaler27197622019-01-23 14:42:11 -06002500 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002501 elif(args.remote_logging == 'disable'):
Justin Thaler27197622019-01-23 14:42:11 -06002502 res = session.put(url + '/attr/Port', headers=jsonHeader, json = {"data": 0}, verify=False, timeout=baseTimeout)
2503 res = session.put(url + '/attr/Address', headers=jsonHeader, json = {"data": ""}, verify=False, timeout=baseTimeout)
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002504 else:
2505 return "Invalid logging remote_logging command"
2506 except(requests.exceptions.Timeout):
2507 return(connectionErrHandler(args.json, "Timeout", None))
2508 return res.text
2509
2510
2511def remoteLoggingConfig(host, args, session):
2512 """
2513 Called by the logging function. Configures remote logging (rsyslog).
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002514
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002515 @param host: string, the hostname or IP address of the bmc
2516 @param args: contains additional arguments used by the logging sub command
2517 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002518 @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 -05002519 """
2520
2521 url="https://"+host+"/xyz/openbmc_project/logging/config/remote"
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002522
2523 try:
Justin Thaler27197622019-01-23 14:42:11 -06002524 res = session.put(url + '/attr/Port', headers=jsonHeader, json = {"data": args.port}, verify=False, timeout=baseTimeout)
2525 res = session.put(url + '/attr/Address', headers=jsonHeader, json = {"data": args.address}, verify=False, timeout=baseTimeout)
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002526 except(requests.exceptions.Timeout):
2527 return(connectionErrHandler(args.json, "Timeout", None))
2528 return res.text
2529
Marri Devender Rao82590dc2019-06-06 04:54:22 -05002530def redfishSupportPresent(host, session):
2531 url = "https://" + host + "/redfish/v1"
2532 try:
2533 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
2534 except(requests.exceptions.Timeout):
2535 return False
2536 except(requests.exceptions.ConnectionError) as err:
2537 return False
2538 if resp.status_code != 200:
2539 return False
2540 else:
2541 return True
Ratan Gupta9166cd22018-10-01 18:09:40 +05302542
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002543def certificateUpdate(host, args, session):
2544 """
2545 Called by certificate management function. update server/client/authority certificates
2546 Example:
2547 certificate update server https -f cert.pem
2548 certificate update authority ldap -f Root-CA.pem
2549 certificate update client ldap -f cert.pem
2550 @param host: string, the hostname or IP address of the bmc
2551 @param args: contains additional arguments used by the certificate update sub command
2552 @param session: the active session to use
2553 """
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002554 httpHeader = {'Content-Type': 'application/octet-stream'}
Matt Spinler220c3c42019-01-04 15:09:29 -06002555 httpHeader.update(xAuthHeader)
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002556 data = open(args.fileloc, 'rb').read()
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002557 try:
Marri Devender Rao82590dc2019-06-06 04:54:22 -05002558 if redfishSupportPresent(host, session):
Marri Devender Rao62db08a2019-08-22 03:16:02 -05002559 if(args.type.lower() == 'server' and args.service.lower() != "https"):
2560 return "Invalid service type"
2561 if(args.type.lower() == 'client' and args.service.lower() != "ldap"):
2562 return "Invalid service type"
2563 if(args.type.lower() == 'authority' and args.service.lower() != "ldap"):
2564 return "Invalid service type"
Marri Devender Rao82590dc2019-06-06 04:54:22 -05002565 url = "";
2566 if(args.type.lower() == 'server'):
2567 url = "https://" + host + \
2568 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"
2569 elif(args.type.lower() == 'client'):
2570 url = "https://" + host + \
2571 "/redfish/v1/AccountService/LDAP/Certificates"
2572 elif(args.type.lower() == 'authority'):
2573 url = "https://" + host + \
2574 "/redfish/v1/Managers/bmc/Truststore/Certificates"
2575 else:
2576 return "Unsupported certificate type"
2577 resp = session.post(url, headers=httpHeader, data=data,
2578 verify=False)
2579 else:
2580 url = "https://" + host + "/xyz/openbmc_project/certs/" + \
2581 args.type.lower() + "/" + args.service.lower()
2582 resp = session.put(url, headers=httpHeader, data=data, verify=False)
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002583 except(requests.exceptions.Timeout):
2584 return(connectionErrHandler(args.json, "Timeout", None))
2585 except(requests.exceptions.ConnectionError) as err:
2586 return connectionErrHandler(args.json, "ConnectionError", err)
2587 if resp.status_code != 200:
2588 print(resp.text)
2589 return "Failed to update the certificate"
2590 else:
Marri Devender Rao82590dc2019-06-06 04:54:22 -05002591 print("Update complete.")
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002592
2593def certificateDelete(host, args, session):
2594 """
2595 Called by certificate management function to delete certificate
2596 Example:
2597 certificate delete server https
2598 certificate delete authority ldap
2599 certificate delete client ldap
2600 @param host: string, the hostname or IP address of the bmc
2601 @param args: contains additional arguments used by the certificate delete sub command
2602 @param session: the active session to use
2603 """
Marri Devender Rao77e78682019-07-17 03:18:35 -05002604 if redfishSupportPresent(host, session):
2605 return "Not supported, please use certificate replace instead";
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002606 httpHeader = {'Content-Type': 'multipart/form-data'}
Matt Spinler220c3c42019-01-04 15:09:29 -06002607 httpHeader.update(xAuthHeader)
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002608 url = "https://" + host + "/xyz/openbmc_project/certs/" + args.type.lower() + "/" + args.service.lower()
2609 print("Deleting certificate url=" + url)
2610 try:
2611 resp = session.delete(url, headers=httpHeader)
2612 except(requests.exceptions.Timeout):
2613 return(connectionErrHandler(args.json, "Timeout", None))
2614 except(requests.exceptions.ConnectionError) as err:
2615 return connectionErrHandler(args.json, "ConnectionError", err)
2616 if resp.status_code != 200:
2617 print(resp.text)
2618 return "Failed to delete the certificate"
2619 else:
Marri Devender Rao77e78682019-07-17 03:18:35 -05002620 print("Delete complete.")
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002621
Marri Devender Raodfe81ad2019-07-01 05:38:09 -05002622def certificateReplace(host, args, session):
2623 """
2624 Called by certificate management function. replace server/client/
2625 authority certificates
2626 Example:
2627 certificate replace server https -f cert.pem
2628 certificate replace authority ldap -f Root-CA.pem
2629 certificate replace client ldap -f cert.pem
2630 @param host: string, the hostname or IP address of the bmc
2631 @param args: contains additional arguments used by the certificate
2632 replace sub command
2633 @param session: the active session to use
2634 """
2635 cert = open(args.fileloc, 'rb').read()
2636 try:
2637 if redfishSupportPresent(host, session):
2638 httpHeader = {'Content-Type': 'application/json'}
2639 httpHeader.update(xAuthHeader)
2640 url = "";
Marri Devender Rao62db08a2019-08-22 03:16:02 -05002641 if(args.type.lower() == 'server' and args.service.lower() != "https"):
2642 return "Invalid service type"
2643 if(args.type.lower() == 'client' and args.service.lower() != "ldap"):
2644 return "Invalid service type"
2645 if(args.type.lower() == 'authority' and args.service.lower() != "ldap"):
2646 return "Invalid service type"
Marri Devender Raodfe81ad2019-07-01 05:38:09 -05002647 if(args.type.lower() == 'server'):
2648 url = "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/1"
2649 elif(args.type.lower() == 'client'):
2650 url = "/redfish/v1/AccountService/LDAP/Certificates/1"
2651 elif(args.type.lower() == 'authority'):
2652 url = "/redfish/v1/Managers/bmc/Truststore/Certificates/1"
2653 replaceUrl = "https://" + host + \
2654 "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate"
2655 data ={"CertificateUri":{"@odata.id":url}, "CertificateType":"PEM",
2656 "CertificateString":cert}
2657 resp = session.post(replaceUrl, headers=httpHeader, json=data, verify=False)
2658 else:
2659 httpHeader = {'Content-Type': 'application/octet-stream'}
2660 httpHeader.update(xAuthHeader)
2661 url = "https://" + host + "/xyz/openbmc_project/certs/" + \
2662 args.type.lower() + "/" + args.service.lower()
2663 resp = session.delete(url, headers=httpHeader)
2664 resp = session.put(url, headers=httpHeader, data=cert, verify=False)
2665 except(requests.exceptions.Timeout):
2666 return(connectionErrHandler(args.json, "Timeout", None))
2667 except(requests.exceptions.ConnectionError) as err:
2668 return connectionErrHandler(args.json, "ConnectionError", err)
2669 if resp.status_code != 200:
2670 print(resp.text)
2671 return "Failed to replace the certificate"
2672 else:
2673 print("Replace complete.")
2674 return resp.text
2675
Marri Devender Rao34646402019-07-01 05:46:03 -05002676def certificateDisplay(host, args, session):
2677 """
2678 Called by certificate management function. display server/client/
2679 authority certificates
2680 Example:
2681 certificate display server
2682 certificate display authority
2683 certificate display client
2684 @param host: string, the hostname or IP address of the bmc
2685 @param args: contains additional arguments used by the certificate
2686 display sub command
2687 @param session: the active session to use
2688 """
2689 if not redfishSupportPresent(host, session):
2690 return "Not supported";
2691
2692 httpHeader = {'Content-Type': 'application/octet-stream'}
2693 httpHeader.update(xAuthHeader)
2694 if(args.type.lower() == 'server'):
2695 url = "https://" + host + \
2696 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/1"
2697 elif(args.type.lower() == 'client'):
2698 url = "https://" + host + \
2699 "/redfish/v1/AccountService/LDAP/Certificates/1"
2700 elif(args.type.lower() == 'authority'):
2701 url = "https://" + host + \
2702 "/redfish/v1/Managers/bmc/Truststore/Certificates/1"
2703 try:
2704 resp = session.get(url, headers=httpHeader, verify=False)
2705 except(requests.exceptions.Timeout):
2706 return(connectionErrHandler(args.json, "Timeout", None))
2707 except(requests.exceptions.ConnectionError) as err:
2708 return connectionErrHandler(args.json, "ConnectionError", err)
2709 if resp.status_code != 200:
2710 print(resp.text)
2711 return "Failed to display the certificate"
2712 else:
2713 print("Display complete.")
2714 return resp.text
2715
Marri Devender Raoa208ff82019-07-01 05:51:27 -05002716def certificateList(host, args, session):
2717 """
2718 Called by certificate management function.
2719 Example:
2720 certificate list
2721 @param host: string, the hostname or IP address of the bmc
2722 @param args: contains additional arguments used by the certificate
2723 list sub command
2724 @param session: the active session to use
2725 """
2726 if not redfishSupportPresent(host, session):
2727 return "Not supported";
2728
2729 httpHeader = {'Content-Type': 'application/octet-stream'}
2730 httpHeader.update(xAuthHeader)
2731 url = "https://" + host + \
2732 "/redfish/v1/CertificateService/CertificateLocations/"
2733 try:
2734 resp = session.get(url, headers=httpHeader, verify=False)
2735 except(requests.exceptions.Timeout):
2736 return(connectionErrHandler(args.json, "Timeout", None))
2737 except(requests.exceptions.ConnectionError) as err:
2738 return connectionErrHandler(args.json, "ConnectionError", err)
2739 if resp.status_code != 200:
2740 print(resp.text)
2741 return "Failed to list certificates"
2742 else:
2743 print("List certificates complete.")
2744 return resp.text
2745
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05002746def certificateGenerateCSR(host, args, session):
2747 """
2748 Called by certificate management function. Generate CSR for server/
2749 client certificates
2750 Example:
Marri Devender Raodf0e1a42019-09-09 08:18:27 -05002751 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
2752 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 -05002753 @param host: string, the hostname or IP address of the bmc
2754 @param args: contains additional arguments used by the certificate replace sub command
2755 @param session: the active session to use
2756 """
2757 if not redfishSupportPresent(host, session):
2758 return "Not supported";
2759
2760 httpHeader = {'Content-Type': 'application/octet-stream'}
2761 httpHeader.update(xAuthHeader)
2762 url = "";
2763 if(args.type.lower() == 'server'):
2764 url = "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/"
Marri Devender Rao88064f02019-08-19 09:00:30 -05002765 usage_list = ["ServerAuthentication"]
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05002766 elif(args.type.lower() == 'client'):
2767 url = "/redfish/v1/AccountService/LDAP/Certificates/"
Marri Devender Rao88064f02019-08-19 09:00:30 -05002768 usage_list = ["ClientAuthentication"]
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05002769 elif(args.type.lower() == 'authority'):
2770 url = "/redfish/v1/Managers/bmc/Truststore/Certificates/"
2771 print("Generating CSR url=" + url)
2772 generateCSRUrl = "https://" + host + \
2773 "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR"
2774 try:
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05002775 alt_name_list = args.alternativeNames.split(",")
2776 data ={"CertificateCollection":{"@odata.id":url},
2777 "CommonName":args.commonName, "City":args.city,
2778 "Country":args.country, "Organization":args.organization,
2779 "OrganizationalUnit":args.organizationUnit, "State":args.state,
Marri Devender Raodf0e1a42019-09-09 08:18:27 -05002780 "KeyPairAlgorithm":args.keyPairAlgorithm, "KeyCurveId":args.keyCurveId,
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05002781 "AlternativeNames":alt_name_list, "ContactPerson":args.contactPerson,
2782 "Email":args.email, "GivenName":args.givenname, "Initials":args.initials,
2783 "KeyUsage":usage_list, "Surname":args.surname,
2784 "UnstructuredName":args.unstructuredname}
2785 resp = session.post(generateCSRUrl, headers=httpHeader,
2786 json=data, verify=False)
2787 except(requests.exceptions.Timeout):
2788 return(connectionErrHandler(args.json, "Timeout", None))
2789 except(requests.exceptions.ConnectionError) as err:
2790 return connectionErrHandler(args.json, "ConnectionError", err)
2791 if resp.status_code != 200:
2792 print(resp.text)
2793 return "Failed to generate CSR"
2794 else:
2795 print("GenerateCSR complete.")
2796 return resp.text
2797
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05002798def enableLDAPConfig(host, args, session):
Ratan Gupta9166cd22018-10-01 18:09:40 +05302799 """
2800 Called by the ldap function. Configures LDAP.
2801
2802 @param host: string, the hostname or IP address of the bmc
2803 @param args: contains additional arguments used by the ldap subcommand
2804 @param session: the active session to use
2805 @param args.json: boolean, if this flag is set to true, the output will
2806 be provided in json format for programmatic consumption
2807 """
2808
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05002809 if(isRedfishSupport):
2810 return enableLDAP(host, args, session)
2811 else:
2812 return enableLegacyLDAP(host, args, session)
2813
2814def enableLegacyLDAP(host, args, session):
2815 """
2816 Called by the ldap function. Configures LDAP on Lagecy systems.
2817
2818 @param host: string, the hostname or IP address of the bmc
2819 @param args: contains additional arguments used by the ldap subcommand
2820 @param session: the active session to use
2821 @param args.json: boolean, if this flag is set to true, the output will
2822 be provided in json format for programmatic consumption
2823 """
2824
Ratan Gupta9166cd22018-10-01 18:09:40 +05302825 url='https://'+host+'/xyz/openbmc_project/user/ldap/action/CreateConfig'
Ratan Gupta9166cd22018-10-01 18:09:40 +05302826 scope = {
2827 'sub' : 'xyz.openbmc_project.User.Ldap.Create.SearchScope.sub',
2828 'one' : 'xyz.openbmc_project.User.Ldap.Create.SearchScope.one',
2829 'base': 'xyz.openbmc_project.User.Ldap.Create.SearchScope.base'
2830 }
2831
2832 serverType = {
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05002833 'ActiveDirectory' : 'xyz.openbmc_project.User.Ldap.Create.Type.ActiveDirectory',
2834 'OpenLDAP' : 'xyz.openbmc_project.User.Ldap.Create.Type.OpenLdap'
Ratan Gupta9166cd22018-10-01 18:09:40 +05302835 }
2836
2837 data = {"data": [args.uri, args.bindDN, args.baseDN, args.bindPassword, scope[args.scope], serverType[args.serverType]]}
2838
2839 try:
Justin Thaler27197622019-01-23 14:42:11 -06002840 res = session.post(url, headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
Ratan Gupta9166cd22018-10-01 18:09:40 +05302841 except(requests.exceptions.Timeout):
2842 return(connectionErrHandler(args.json, "Timeout", None))
2843 except(requests.exceptions.ConnectionError) as err:
2844 return connectionErrHandler(args.json, "ConnectionError", err)
2845
2846 return res.text
2847
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05002848def enableLDAP(host, args, session):
2849 """
2850 Called by the ldap function. Configures LDAP for systems with latest user-manager design changes
2851
2852 @param host: string, the hostname or IP address of the bmc
2853 @param args: contains additional arguments used by the ldap subcommand
2854 @param session: the active session to use
2855 @param args.json: boolean, if this flag is set to true, the output will
2856 be provided in json format for programmatic consumption
2857 """
2858
2859 scope = {
2860 'sub' : 'xyz.openbmc_project.User.Ldap.Config.SearchScope.sub',
2861 'one' : 'xyz.openbmc_project.User.Ldap.Config.SearchScope.one',
2862 'base': 'xyz.openbmc_project.User.Ldap.Config.SearchScope.base'
2863 }
2864
2865 serverType = {
2866 'ActiveDirectory' : 'xyz.openbmc_project.User.Ldap.Config.Type.ActiveDirectory',
2867 'OpenLDAP' : 'xyz.openbmc_project.User.Ldap.Config.Type.OpenLdap'
2868 }
2869
2870 url = "https://"+host+"/xyz/openbmc_project/user/ldap/"
2871
2872 serverTypeEnabled = getLDAPTypeEnabled(host,session)
2873 serverTypeToBeEnabled = args.serverType
2874
2875 #If the given LDAP type is already enabled, then return
2876 if (serverTypeToBeEnabled == serverTypeEnabled):
2877 return("Server type " + serverTypeToBeEnabled + " is already enabled...")
2878
2879 try:
2880
2881 # Copy the role map from the currently enabled LDAP server type
2882 # to the newly enabled server type
2883 # Disable the currently enabled LDAP server type. Unless
2884 # it is disabled, we cannot enable a new LDAP server type
2885 if (serverTypeEnabled is not None):
2886
2887 if (serverTypeToBeEnabled != serverTypeEnabled):
2888 res = syncRoleMap(host,args,session,serverTypeEnabled,serverTypeToBeEnabled)
2889
2890 data = "{\"data\": 0 }"
2891 res = session.put(url + serverTypeMap[serverTypeEnabled] + '/attr/Enabled', headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
2892
2893 data = {"data": args.baseDN}
2894 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/LDAPBaseDN', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
2895 if (res.status_code != requests.codes.ok):
2896 print("Updates to the property LDAPBaseDN failed...")
2897 return(res.text)
2898
2899 data = {"data": args.bindDN}
2900 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/LDAPBindDN', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
2901 if (res.status_code != requests.codes.ok):
2902 print("Updates to the property LDAPBindDN failed...")
2903 return(res.text)
2904
2905 data = {"data": args.bindPassword}
2906 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/LDAPBindDNPassword', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
2907 if (res.status_code != requests.codes.ok):
2908 print("Updates to the property LDAPBindDNPassword failed...")
2909 return(res.text)
2910
2911 data = {"data": scope[args.scope]}
2912 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/LDAPSearchScope', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
2913 if (res.status_code != requests.codes.ok):
2914 print("Updates to the property LDAPSearchScope failed...")
2915 return(res.text)
2916
2917 data = {"data": args.uri}
2918 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/LDAPServerURI', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
2919 if (res.status_code != requests.codes.ok):
2920 print("Updates to the property LDAPServerURI failed...")
2921 return(res.text)
2922
2923 data = {"data": args.groupAttrName}
2924 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/GroupNameAttribute', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
2925 if (res.status_code != requests.codes.ok):
2926 print("Updates to the property GroupNameAttribute failed...")
2927 return(res.text)
2928
2929 data = {"data": args.userAttrName}
2930 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/UserNameAttribute', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
2931 if (res.status_code != requests.codes.ok):
2932 print("Updates to the property UserNameAttribute failed...")
2933 return(res.text)
2934
2935 #After updating the properties, enable the new server type
2936 data = "{\"data\": 1 }"
2937 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/Enabled', headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
2938
2939 except(requests.exceptions.Timeout):
2940 return(connectionErrHandler(args.json, "Timeout", None))
2941 except(requests.exceptions.ConnectionError) as err:
2942 return connectionErrHandler(args.json, "ConnectionError", err)
2943 return res.text
Ratan Gupta9166cd22018-10-01 18:09:40 +05302944
2945def disableLDAP(host, args, session):
2946 """
2947 Called by the ldap function. Deletes the LDAP Configuration.
2948
2949 @param host: string, the hostname or IP address of the bmc
2950 @param args: contains additional arguments used by the ldap subcommand
2951 @param session: the active session to use
2952 @param args.json: boolean, if this flag is set to true, the output
2953 will be provided in json format for programmatic consumption
2954 """
2955
Ratan Gupta9166cd22018-10-01 18:09:40 +05302956 try:
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05002957 if (isRedfishSupport) :
2958
2959 url = "https://"+host+"/xyz/openbmc_project/user/ldap/"
2960
2961 serverTypeEnabled = getLDAPTypeEnabled(host,session)
2962
2963 if (serverTypeEnabled is not None):
2964 #To keep the role map in sync,
2965 #If the server type being disabled has role map, then
2966 # - copy the role map to the other server type(s)
2967 for serverType in serverTypeMap.keys():
2968 if (serverType != serverTypeEnabled):
2969 res = syncRoleMap(host,args,session,serverTypeEnabled,serverType)
2970
2971 #Disable the currently enabled LDAP server type
2972 data = "{\"data\": 0 }"
2973 res = session.put(url + serverTypeMap[serverTypeEnabled] + '/attr/Enabled', headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
2974
2975 else:
2976 return("LDAP server has not been enabled...")
2977
2978 else :
2979 url='https://'+host+'/xyz/openbmc_project/user/ldap/config/action/delete'
2980 data = {"data": []}
2981 res = session.post(url, headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
2982
Ratan Gupta9166cd22018-10-01 18:09:40 +05302983 except(requests.exceptions.Timeout):
2984 return(connectionErrHandler(args.json, "Timeout", None))
2985 except(requests.exceptions.ConnectionError) as err:
2986 return connectionErrHandler(args.json, "ConnectionError", err)
2987
2988 return res.text
2989
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06002990def enableDHCP(host, args, session):
2991
2992 """
2993 Called by the network function. Enables DHCP.
2994
2995 @param host: string, the hostname or IP address of the bmc
2996 @param args: contains additional arguments used by the ldap subcommand
2997 args.json: boolean, if this flag is set to true, the output
2998 will be provided in json format for programmatic consumption
2999 @param session: the active session to use
3000 """
3001
3002 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3003 "/attr/DHCPEnabled"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003004 data = "{\"data\": 1 }"
3005 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003006 res = session.put(url, headers=jsonHeader, data=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003007 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003008
3009 except(requests.exceptions.Timeout):
3010 return(connectionErrHandler(args.json, "Timeout", None))
3011 except(requests.exceptions.ConnectionError) as err:
3012 return connectionErrHandler(args.json, "ConnectionError", err)
3013 if res.status_code == 403:
3014 return "The specified Interface"+"("+args.Interface+")"+\
3015 " doesn't exist"
3016
3017 return res.text
3018
3019
3020def disableDHCP(host, args, session):
3021 """
3022 Called by the network function. Disables DHCP.
3023
3024 @param host: string, the hostname or IP address of the bmc
3025 @param args: contains additional arguments used by the ldap subcommand
3026 args.json: boolean, if this flag is set to true, the output
3027 will be provided in json format for programmatic consumption
3028 @param session: the active session to use
3029 """
3030
3031 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3032 "/attr/DHCPEnabled"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003033 data = "{\"data\": 0 }"
3034 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003035 res = session.put(url, headers=jsonHeader, data=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003036 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003037 except(requests.exceptions.Timeout):
3038 return(connectionErrHandler(args.json, "Timeout", None))
3039 except(requests.exceptions.ConnectionError) as err:
3040 return connectionErrHandler(args.json, "ConnectionError", err)
3041 if res.status_code == 403:
3042 return "The specified Interface"+"("+args.Interface+")"+\
3043 " doesn't exist"
3044 return res.text
3045
3046
3047def getHostname(host, args, session):
3048
3049 """
3050 Called by the network function. Prints out the Hostname.
3051
3052 @param host: string, the hostname or IP address of the bmc
3053 @param args: contains additional arguments used by the ldap subcommand
3054 args.json: boolean, if this flag is set to true, the output
3055 will be provided in json format for programmatic consumption
3056 @param session: the active session to use
3057 """
3058
3059 url = "https://"+host+"/xyz/openbmc_project/network/config/attr/HostName"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003060
3061 try:
Justin Thaler27197622019-01-23 14:42:11 -06003062 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003063 except(requests.exceptions.Timeout):
3064 return(connectionErrHandler(args.json, "Timeout", None))
3065 except(requests.exceptions.ConnectionError) as err:
3066 return connectionErrHandler(args.json, "ConnectionError", err)
3067
3068 return res.text
3069
3070
3071def setHostname(host, args, session):
3072 """
3073 Called by the network function. Sets the Hostname.
3074
3075 @param host: string, the hostname or IP address of the bmc
3076 @param args: contains additional arguments used by the ldap subcommand
3077 args.json: boolean, if this flag is set to true, the output
3078 will be provided in json format for programmatic consumption
3079 @param session: the active session to use
3080 """
3081
3082 url = "https://"+host+"/xyz/openbmc_project/network/config/attr/HostName"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003083
3084 data = {"data": args.HostName}
3085
3086 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003087 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003088 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003089 except(requests.exceptions.Timeout):
3090 return(connectionErrHandler(args.json, "Timeout", None))
3091 except(requests.exceptions.ConnectionError) as err:
3092 return connectionErrHandler(args.json, "ConnectionError", err)
3093
3094 return res.text
3095
3096
3097def getDomainName(host, args, session):
3098
3099 """
3100 Called by the network function. Prints out the DomainName.
3101
3102 @param host: string, the hostname or IP address of the bmc
3103 @param args: contains additional arguments used by the ldap subcommand
3104 args.json: boolean, if this flag is set to true, the output
3105 will be provided in json format for programmatic consumption
3106 @param session: the active session to use
3107 """
3108
3109 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3110 "/attr/DomainName"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003111
3112 try:
Justin Thaler27197622019-01-23 14:42:11 -06003113 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003114 except(requests.exceptions.Timeout):
3115 return(connectionErrHandler(args.json, "Timeout", None))
3116 except(requests.exceptions.ConnectionError) as err:
3117 return connectionErrHandler(args.json, "ConnectionError", err)
3118 if res.status_code == 404:
Sunitha Harishf9bb2fa2019-09-19 01:48:00 -05003119 return "The DomainName is not configured on Interface"+"("+args.Interface+")"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003120
3121 return res.text
3122
3123
3124def setDomainName(host, args, session):
3125 """
3126 Called by the network function. Sets the DomainName.
3127
3128 @param host: string, the hostname or IP address of the bmc
3129 @param args: contains additional arguments used by the ldap subcommand
3130 args.json: boolean, if this flag is set to true, the output
3131 will be provided in json format for programmatic consumption
3132 @param session: the active session to use
3133 """
3134
3135 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3136 "/attr/DomainName"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003137
3138 data = {"data": args.DomainName.split(",")}
3139
3140 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003141 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003142 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003143 except(requests.exceptions.Timeout):
3144 return(connectionErrHandler(args.json, "Timeout", None))
3145 except(requests.exceptions.ConnectionError) as err:
3146 return connectionErrHandler(args.json, "ConnectionError", err)
3147 if res.status_code == 403:
3148 return "The specified Interface"+"("+args.Interface+")"+\
3149 " doesn't exist"
3150
3151 return res.text
3152
3153
3154def getMACAddress(host, args, session):
3155
3156 """
3157 Called by the network function. Prints out the MACAddress.
3158
3159 @param host: string, the hostname or IP address of the bmc
3160 @param args: contains additional arguments used by the ldap subcommand
3161 args.json: boolean, if this flag is set to true, the output
3162 will be provided in json format for programmatic consumption
3163 @param session: the active session to use
3164 """
3165
3166 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3167 "/attr/MACAddress"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003168
3169 try:
Justin Thaler27197622019-01-23 14:42:11 -06003170 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003171 except(requests.exceptions.Timeout):
3172 return(connectionErrHandler(args.json, "Timeout", None))
3173 except(requests.exceptions.ConnectionError) as err:
3174 return connectionErrHandler(args.json, "ConnectionError", err)
3175 if res.status_code == 404:
3176 return "The specified Interface"+"("+args.Interface+")"+\
3177 " doesn't exist"
3178
3179 return res.text
3180
3181
3182def setMACAddress(host, args, session):
3183 """
3184 Called by the network function. Sets the MACAddress.
3185
3186 @param host: string, the hostname or IP address of the bmc
3187 @param args: contains additional arguments used by the ldap subcommand
3188 args.json: boolean, if this flag is set to true, the output
3189 will be provided in json format for programmatic consumption
3190 @param session: the active session to use
3191 """
3192
3193 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3194 "/attr/MACAddress"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003195
3196 data = {"data": args.MACAddress}
3197
3198 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003199 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003200 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003201 except(requests.exceptions.Timeout):
3202 return(connectionErrHandler(args.json, "Timeout", None))
3203 except(requests.exceptions.ConnectionError) as err:
3204 return connectionErrHandler(args.json, "ConnectionError", err)
3205 if res.status_code == 403:
3206 return "The specified Interface"+"("+args.Interface+")"+\
3207 " doesn't exist"
3208
3209 return res.text
3210
3211
3212def getDefaultGateway(host, args, session):
3213
3214 """
3215 Called by the network function. Prints out the DefaultGateway.
3216
3217 @param host: string, the hostname or IP address of the bmc
3218 @param args: contains additional arguments used by the ldap subcommand
3219 args.json: boolean, if this flag is set to true, the output
3220 will be provided in json format for programmatic consumption
3221 @param session: the active session to use
3222 """
3223
3224 url = "https://"+host+"/xyz/openbmc_project/network/config/attr/DefaultGateway"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003225
3226 try:
Justin Thaler27197622019-01-23 14:42:11 -06003227 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003228 except(requests.exceptions.Timeout):
3229 return(connectionErrHandler(args.json, "Timeout", None))
3230 except(requests.exceptions.ConnectionError) as err:
3231 return connectionErrHandler(args.json, "ConnectionError", err)
3232 if res.status_code == 404:
3233 return "Failed to get Default Gateway info!!"
3234
3235 return res.text
3236
3237
3238def setDefaultGateway(host, args, session):
3239 """
3240 Called by the network function. Sets the DefaultGateway.
3241
3242 @param host: string, the hostname or IP address of the bmc
3243 @param args: contains additional arguments used by the ldap subcommand
3244 args.json: boolean, if this flag is set to true, the output
3245 will be provided in json format for programmatic consumption
3246 @param session: the active session to use
3247 """
3248
3249 url = "https://"+host+"/xyz/openbmc_project/network/config/attr/DefaultGateway"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003250
3251 data = {"data": args.DefaultGW}
3252
3253 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003254 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003255 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003256 except(requests.exceptions.Timeout):
3257 return(connectionErrHandler(args.json, "Timeout", None))
3258 except(requests.exceptions.ConnectionError) as err:
3259 return connectionErrHandler(args.json, "ConnectionError", err)
3260 if res.status_code == 403:
3261 return "Failed to set Default Gateway!!"
3262
3263 return res.text
3264
3265
3266def viewNWConfig(host, args, session):
3267 """
3268 Called by the ldap function. Prints out network configured properties
3269
3270 @param host: string, the hostname or IP address of the bmc
3271 @param args: contains additional arguments used by the ldap subcommand
3272 args.json: boolean, if this flag is set to true, the output
3273 will be provided in json format for programmatic consumption
3274 @param session: the active session to use
3275 @return returns LDAP's configured properties.
3276 """
3277 url = "https://"+host+"/xyz/openbmc_project/network/enumerate"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003278 try:
Justin Thaler27197622019-01-23 14:42:11 -06003279 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003280 except(requests.exceptions.Timeout):
3281 return(connectionErrHandler(args.json, "Timeout", None))
3282 except(requests.exceptions.ConnectionError) as err:
3283 return connectionErrHandler(args.json, "ConnectionError", err)
3284 except(requests.exceptions.RequestException) as err:
3285 return connectionErrHandler(args.json, "RequestException", err)
3286 if res.status_code == 404:
3287 return "LDAP server config has not been created"
3288 return res.text
3289
3290
3291def getDNS(host, args, session):
3292
3293 """
3294 Called by the network function. Prints out DNS servers on the interface
3295
3296 @param host: string, the hostname or IP address of the bmc
3297 @param args: contains additional arguments used by the ldap subcommand
3298 args.json: boolean, if this flag is set to true, the output
3299 will be provided in json format for programmatic consumption
3300 @param session: the active session to use
3301 """
3302
3303 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
3304 + "/attr/Nameservers"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003305
3306 try:
Justin Thaler27197622019-01-23 14:42:11 -06003307 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003308 except(requests.exceptions.Timeout):
3309 return(connectionErrHandler(args.json, "Timeout", None))
3310 except(requests.exceptions.ConnectionError) as err:
3311 return connectionErrHandler(args.json, "ConnectionError", err)
3312 if res.status_code == 404:
Sunitha Harishf9bb2fa2019-09-19 01:48:00 -05003313 return "The NameServer is not configured on Interface"+"("+args.Interface+")"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003314
3315 return res.text
3316
3317
3318def setDNS(host, args, session):
3319 """
3320 Called by the network function. Sets DNS servers on the interface.
3321
3322 @param host: string, the hostname or IP address of the bmc
3323 @param args: contains additional arguments used by the ldap subcommand
3324 args.json: boolean, if this flag is set to true, the output
3325 will be provided in json format for programmatic consumption
3326 @param session: the active session to use
3327 """
3328
3329 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
3330 + "/attr/Nameservers"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003331
3332 data = {"data": args.DNSServers.split(",")}
3333
3334 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003335 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003336 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003337 except(requests.exceptions.Timeout):
3338 return(connectionErrHandler(args.json, "Timeout", None))
3339 except(requests.exceptions.ConnectionError) as err:
3340 return connectionErrHandler(args.json, "ConnectionError", err)
3341 if res.status_code == 403:
3342 return "The specified Interface"+"("+args.Interface+")" +\
3343 " doesn't exist"
3344
3345 return res.text
3346
3347
3348def getNTP(host, args, session):
3349
3350 """
3351 Called by the network function. Prints out NTP servers on the interface
3352
3353 @param host: string, the hostname or IP address of the bmc
3354 @param args: contains additional arguments used by the ldap subcommand
3355 args.json: boolean, if this flag is set to true, the output
3356 will be provided in json format for programmatic consumption
3357 @param session: the active session to use
3358 """
3359
3360 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
3361 + "/attr/NTPServers"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003362 try:
Justin Thaler27197622019-01-23 14:42:11 -06003363 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003364 except(requests.exceptions.Timeout):
3365 return(connectionErrHandler(args.json, "Timeout", None))
3366 except(requests.exceptions.ConnectionError) as err:
3367 return connectionErrHandler(args.json, "ConnectionError", err)
3368 if res.status_code == 404:
Sunitha Harishf9bb2fa2019-09-19 01:48:00 -05003369 return "The NTPServer is not configured on Interface"+"("+args.Interface+")"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003370
3371 return res.text
3372
3373
3374def setNTP(host, args, session):
3375 """
3376 Called by the network function. Sets NTP servers on the interface.
3377
3378 @param host: string, the hostname or IP address of the bmc
3379 @param args: contains additional arguments used by the ldap subcommand
3380 args.json: boolean, if this flag is set to true, the output
3381 will be provided in json format for programmatic consumption
3382 @param session: the active session to use
3383 """
3384
3385 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
3386 + "/attr/NTPServers"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003387
3388 data = {"data": args.NTPServers.split(",")}
3389
3390 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003391 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003392 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003393 except(requests.exceptions.Timeout):
3394 return(connectionErrHandler(args.json, "Timeout", None))
3395 except(requests.exceptions.ConnectionError) as err:
3396 return connectionErrHandler(args.json, "ConnectionError", err)
3397 if res.status_code == 403:
3398 return "The specified Interface"+"("+args.Interface+")" +\
3399 " doesn't exist"
3400
3401 return res.text
3402
3403
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003404def addIP(host, args, session):
3405 """
3406 Called by the network function. Configures IP address on given interface
3407
3408 @param host: string, the hostname or IP address of the bmc
3409 @param args: contains additional arguments used by the ldap subcommand
3410 args.json: boolean, if this flag is set to true, the output
3411 will be provided in json format for programmatic consumption
3412 @param session: the active session to use
3413 """
3414
3415 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
3416 + "/action/IP"
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003417 protocol = {
3418 'ipv4': 'xyz.openbmc_project.Network.IP.Protocol.IPv4',
3419 'ipv6': 'xyz.openbmc_project.Network.IP.Protocol.IPv6'
3420 }
3421
3422 data = {"data": [protocol[args.type], args.address, int(args.prefixLength),
3423 args.gateway]}
3424
3425 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003426 res = session.post(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003427 timeout=baseTimeout)
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003428 except(requests.exceptions.Timeout):
3429 return(connectionErrHandler(args.json, "Timeout", None))
3430 except(requests.exceptions.ConnectionError) as err:
3431 return connectionErrHandler(args.json, "ConnectionError", err)
3432 if res.status_code == 404:
3433 return "The specified Interface" + "(" + args.Interface + ")" +\
3434 " doesn't exist"
3435
3436 return res.text
3437
3438
3439def getIP(host, args, session):
3440 """
3441 Called by the network function. Prints out IP address of given interface
3442
3443 @param host: string, the hostname or IP address of the bmc
3444 @param args: contains additional arguments used by the ldap subcommand
3445 args.json: boolean, if this flag is set to true, the output
3446 will be provided in json format for programmatic consumption
3447 @param session: the active session to use
3448 """
3449
3450 url = "https://" + host+"/xyz/openbmc_project/network/" + args.Interface +\
3451 "/enumerate"
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003452 try:
Justin Thaler27197622019-01-23 14:42:11 -06003453 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003454 except(requests.exceptions.Timeout):
3455 return(connectionErrHandler(args.json, "Timeout", None))
3456 except(requests.exceptions.ConnectionError) as err:
3457 return connectionErrHandler(args.json, "ConnectionError", err)
3458 if res.status_code == 404:
3459 return "The specified Interface" + "(" + args.Interface + ")" +\
3460 " doesn't exist"
3461
3462 return res.text
3463
3464
3465def deleteIP(host, args, session):
3466 """
3467 Called by the network function. Deletes the IP address from given Interface
3468
3469 @param host: string, the hostname or IP address of the bmc
3470 @param args: contains additional arguments used by the ldap subcommand
3471 @param session: the active session to use
3472 @param args.json: boolean, if this flag is set to true, the output
3473 will be provided in json format for programmatic consumption
3474 """
3475
3476 url = "https://"+host+"/xyz/openbmc_project/network/" + args.Interface+\
3477 "/enumerate"
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003478 data = {"data": []}
3479 try:
Justin Thaler27197622019-01-23 14:42:11 -06003480 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003481 except(requests.exceptions.Timeout):
3482 return(connectionErrHandler(args.json, "Timeout", None))
3483 except(requests.exceptions.ConnectionError) as err:
3484 return connectionErrHandler(args.json, "ConnectionError", err)
3485 if res.status_code == 404:
3486 return "The specified Interface" + "(" + args.Interface + ")" +\
3487 " doesn't exist"
3488 objDict = json.loads(res.text)
3489 if not objDict['data']:
3490 return "No object found for given address on given Interface"
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003491 for obj in objDict['data']:
Sunitha Harish0baf6372019-07-31 03:59:03 -05003492 try:
3493 if args.address in objDict['data'][obj]['Address']:
3494 url = "https://"+host+obj+"/action/Delete"
3495 try:
3496 res = session.post(url, headers=jsonHeader, json=data,
3497 verify=False, timeout=baseTimeout)
3498 except(requests.exceptions.Timeout):
3499 return(connectionErrHandler(args.json, "Timeout", None))
3500 except(requests.exceptions.ConnectionError) as err:
3501 return connectionErrHandler(args.json, "ConnectionError", err)
3502 return res.text
3503 else:
3504 continue
3505 except KeyError:
Sunitha Harishf9bb2fa2019-09-19 01:48:00 -05003506 continue
3507 return "No object found for address " + args.address + \
3508 " on Interface(" + args.Interface + ")"
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003509
3510
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003511def addVLAN(host, args, session):
3512 """
3513 Called by the network function. Creates VLAN on given interface.
3514
3515 @param host: string, the hostname or IP address of the bmc
3516 @param args: contains additional arguments used by the ldap subcommand
3517 args.json: boolean, if this flag is set to true, the output
3518 will be provided in json format for programmatic consumption
3519 @param session: the active session to use
3520 """
3521
3522 url = "https://" + host+"/xyz/openbmc_project/network/action/VLAN"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003523
Sunitha Harish0baf6372019-07-31 03:59:03 -05003524 data = {"data": [args.Interface,int(args.Identifier)]}
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003525 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003526 res = session.post(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003527 timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003528 except(requests.exceptions.Timeout):
3529 return(connectionErrHandler(args.json, "Timeout", None))
3530 except(requests.exceptions.ConnectionError) as err:
3531 return connectionErrHandler(args.json, "ConnectionError", err)
3532 if res.status_code == 400:
Sunitha Harish0baf6372019-07-31 03:59:03 -05003533 return "Adding VLAN to interface" + "(" + args.Interface + ")" +\
3534 " failed"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003535
3536 return res.text
3537
3538
3539def deleteVLAN(host, args, session):
3540 """
3541 Called by the network function. Creates VLAN on given interface.
3542
3543 @param host: string, the hostname or IP address of the bmc
3544 @param args: contains additional arguments used by the ldap subcommand
3545 args.json: boolean, if this flag is set to true, the output
3546 will be provided in json format for programmatic consumption
3547 @param session: the active session to use
3548 """
3549
Sunitha Harish577a5032019-08-08 06:27:40 -05003550 url = "https://" + host+"/xyz/openbmc_project/network/"+args.Interface+"/action/Delete"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003551 data = {"data": []}
3552
3553 try:
Justin Thaler27197622019-01-23 14:42:11 -06003554 res = session.post(url, headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003555 except(requests.exceptions.Timeout):
3556 return(connectionErrHandler(args.json, "Timeout", None))
3557 except(requests.exceptions.ConnectionError) as err:
3558 return connectionErrHandler(args.json, "ConnectionError", err)
3559 if res.status_code == 404:
Sunitha Harish577a5032019-08-08 06:27:40 -05003560 return "The specified VLAN"+"("+args.Interface+")" +" doesn't exist"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003561
3562 return res.text
3563
3564
3565def viewDHCPConfig(host, args, session):
3566 """
3567 Called by the network function. Shows DHCP configured Properties.
3568
3569 @param host: string, the hostname or IP address of the bmc
3570 @param args: contains additional arguments used by the ldap subcommand
3571 args.json: boolean, if this flag is set to true, the output
3572 will be provided in json format for programmatic consumption
3573 @param session: the active session to use
3574 """
3575
3576 url="https://"+host+"/xyz/openbmc_project/network/config/dhcp"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003577
3578 try:
Justin Thaler27197622019-01-23 14:42:11 -06003579 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003580 except(requests.exceptions.Timeout):
3581 return(connectionErrHandler(args.json, "Timeout", None))
3582 except(requests.exceptions.ConnectionError) as err:
3583 return connectionErrHandler(args.json, "ConnectionError", err)
3584
3585 return res.text
3586
3587
3588def configureDHCP(host, args, session):
3589 """
3590 Called by the network function. Configures/updates DHCP Properties.
3591
3592 @param host: string, the hostname or IP address of the bmc
3593 @param args: contains additional arguments used by the ldap subcommand
3594 args.json: boolean, if this flag is set to true, the output
3595 will be provided in json format for programmatic consumption
3596 @param session: the active session to use
3597 """
3598
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003599
3600 try:
3601 url="https://"+host+"/xyz/openbmc_project/network/config/dhcp"
3602 if(args.DNSEnabled == True):
3603 data = '{"data": 1}'
3604 else:
3605 data = '{"data": 0}'
Matt Spinler220c3c42019-01-04 15:09:29 -06003606 res = session.put(url + '/attr/DNSEnabled', headers=jsonHeader,
Justin Thaler27197622019-01-23 14:42:11 -06003607 data=data, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003608 if(args.HostNameEnabled == True):
3609 data = '{"data": 1}'
3610 else:
3611 data = '{"data": 0}'
Matt Spinler220c3c42019-01-04 15:09:29 -06003612 res = session.put(url + '/attr/HostNameEnabled', headers=jsonHeader,
Justin Thaler27197622019-01-23 14:42:11 -06003613 data=data, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003614 if(args.NTPEnabled == True):
3615 data = '{"data": 1}'
3616 else:
3617 data = '{"data": 0}'
Matt Spinler220c3c42019-01-04 15:09:29 -06003618 res = session.put(url + '/attr/NTPEnabled', headers=jsonHeader,
Justin Thaler27197622019-01-23 14:42:11 -06003619 data=data, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003620 if(args.SendHostNameEnabled == True):
3621 data = '{"data": 1}'
3622 else:
3623 data = '{"data": 0}'
Matt Spinler220c3c42019-01-04 15:09:29 -06003624 res = session.put(url + '/attr/SendHostNameEnabled', headers=jsonHeader,
Justin Thaler27197622019-01-23 14:42:11 -06003625 data=data, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003626 except(requests.exceptions.Timeout):
3627 return(connectionErrHandler(args.json, "Timeout", None))
3628 except(requests.exceptions.ConnectionError) as err:
3629 return connectionErrHandler(args.json, "ConnectionError", err)
3630
3631 return res.text
3632
3633
3634def nwReset(host, args, session):
3635
3636 """
3637 Called by the network function. Resets networks setting to factory defaults.
3638
3639 @param host: string, the hostname or IP address of the bmc
3640 @param args: contains additional arguments used by the ldap subcommand
3641 args.json: boolean, if this flag is set to true, the output
3642 will be provided in json format for programmatic consumption
3643 @param session: the active session to use
3644 """
3645
3646 url = "https://"+host+"/xyz/openbmc_project/network/action/Reset"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003647 data = '{"data":[] }'
3648 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003649 res = session.post(url, headers=jsonHeader, data=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003650 timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003651
3652 except(requests.exceptions.Timeout):
3653 return(connectionErrHandler(args.json, "Timeout", None))
3654 except(requests.exceptions.ConnectionError) as err:
3655 return connectionErrHandler(args.json, "ConnectionError", err)
3656
3657 return res.text
3658
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003659def getLDAPTypeEnabled(host,session):
3660
3661 """
3662 Called by LDAP related functions to find the LDAP server type that has been enabled.
3663 Returns None if LDAP has not been configured.
3664
3665 @param host: string, the hostname or IP address of the bmc
3666 @param session: the active session to use
3667 """
3668
3669 enabled = False
3670 url = 'https://'+host+'/xyz/openbmc_project/user/ldap/'
3671 for key,value in serverTypeMap.items():
3672 data = {"data": []}
3673 try:
3674 res = session.get(url + value + '/attr/Enabled', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
3675 except(requests.exceptions.Timeout):
3676 print(connectionErrHandler(args.json, "Timeout", None))
3677 return
3678 except(requests.exceptions.ConnectionError) as err:
3679 print(connectionErrHandler(args.json, "ConnectionError", err))
3680 return
3681
3682 enabled = res.json()['data']
3683 if (enabled):
3684 return key
3685
3686def syncRoleMap(host,args,session,fromServerType,toServerType):
3687
3688 """
3689 Called by LDAP related functions to sync the role maps
3690 Returns False if LDAP has not been configured.
3691
3692 @param host: string, the hostname or IP address of the bmc
3693 @param session: the active session to use
3694 @param fromServerType : Server type whose role map has to be copied
3695 @param toServerType : Server type to which role map has to be copied
3696 """
3697
3698 url = "https://"+host+"/xyz/openbmc_project/user/ldap/"
3699
3700 try:
3701 #Note: If the fromServerType has no role map, then
3702 #the toServerType will not have any role map.
3703
3704 #delete the privilege mapping from the toServerType and
3705 #then copy the privilege mapping from fromServerType to
3706 #toServerType.
3707 args.serverType = toServerType
3708 res = deleteAllPrivilegeMapping(host, args, session)
3709
3710 data = {"data": []}
3711 res = session.get(url + serverTypeMap[fromServerType] + '/role_map/enumerate', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
3712 #Previously enabled server type has no role map
3713 if (res.status_code != requests.codes.ok):
3714
3715 #fromServerType has no role map; So, no need to copy
3716 #role map to toServerType.
3717 return
3718
3719 objDict = json.loads(res.text)
3720 dataDict = objDict['data']
3721 for key,value in dataDict.items():
3722 data = {"data": [value["GroupName"], value["Privilege"]]}
3723 res = session.post(url + serverTypeMap[toServerType] + '/action/Create', headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
3724
3725 except(requests.exceptions.Timeout):
3726 return(connectionErrHandler(args.json, "Timeout", None))
3727 except(requests.exceptions.ConnectionError) as err:
3728 return connectionErrHandler(args.json, "ConnectionError", err)
3729 return res.text
3730
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003731
Ratan Guptafeee6372018-10-17 23:25:51 +05303732def createPrivilegeMapping(host, args, session):
3733 """
3734 Called by the ldap function. Creates the group and the privilege mapping.
3735
3736 @param host: string, the hostname or IP address of the bmc
3737 @param args: contains additional arguments used by the ldap subcommand
3738 @param session: the active session to use
3739 @param args.json: boolean, if this flag is set to true, the output
3740 will be provided in json format for programmatic consumption
3741 """
3742
Ratan Guptafeee6372018-10-17 23:25:51 +05303743 try:
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003744 if (isRedfishSupport):
3745 url = 'https://'+host+'/xyz/openbmc_project/user/ldap/'
3746
3747 #To maintain the interface compatibility between op930 and op940, the server type has been made
3748 #optional. If the server type is not specified, then create the role-mapper for the currently
3749 #enabled server type.
3750 serverType = args.serverType
3751 if (serverType is None):
3752 serverType = getLDAPTypeEnabled(host,session)
3753 if (serverType is None):
3754 return("LDAP server has not been enabled. Please specify LDAP serverType to proceed further...")
3755
3756 data = {"data": [args.groupName,args.privilege]}
3757 res = session.post(url + serverTypeMap[serverType] + '/action/Create', headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
3758
3759 else:
3760 url = 'https://'+host+'/xyz/openbmc_project/user/ldap/action/Create'
3761 data = {"data": [args.groupName,args.privilege]}
3762 res = session.post(url, headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
3763
Ratan Guptafeee6372018-10-17 23:25:51 +05303764 except(requests.exceptions.Timeout):
3765 return(connectionErrHandler(args.json, "Timeout", None))
3766 except(requests.exceptions.ConnectionError) as err:
3767 return connectionErrHandler(args.json, "ConnectionError", err)
3768 return res.text
3769
3770def listPrivilegeMapping(host, args, session):
3771 """
3772 Called by the ldap function. Lists the group and the privilege mapping.
3773
3774 @param host: string, the hostname or IP address of the bmc
3775 @param args: contains additional arguments used by the ldap subcommand
3776 @param session: the active session to use
3777 @param args.json: boolean, if this flag is set to true, the output
3778 will be provided in json format for programmatic consumption
3779 """
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003780
3781 if (isRedfishSupport):
3782 serverType = args.serverType
3783 if (serverType is None):
3784 serverType = getLDAPTypeEnabled(host,session)
3785 if (serverType is None):
3786 return("LDAP has not been enabled. Please specify LDAP serverType to proceed further...")
3787
3788 url = 'https://'+host+'/xyz/openbmc_project/user/ldap/'+serverTypeMap[serverType]+'/role_map/enumerate'
3789
3790 else:
3791 url = 'https://'+host+'/xyz/openbmc_project/user/ldap/enumerate'
3792
Ratan Guptafeee6372018-10-17 23:25:51 +05303793 data = {"data": []}
3794
3795 try:
Justin Thaler27197622019-01-23 14:42:11 -06003796 res = session.get(url, headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
Ratan Guptafeee6372018-10-17 23:25:51 +05303797 except(requests.exceptions.Timeout):
3798 return(connectionErrHandler(args.json, "Timeout", None))
3799 except(requests.exceptions.ConnectionError) as err:
3800 return connectionErrHandler(args.json, "ConnectionError", err)
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003801
Ratan Guptafeee6372018-10-17 23:25:51 +05303802 return res.text
3803
3804def deletePrivilegeMapping(host, args, session):
3805 """
3806 Called by the ldap function. Deletes the mapping associated with the group.
3807
3808 @param host: string, the hostname or IP address of the bmc
3809 @param args: contains additional arguments used by the ldap subcommand
3810 @param session: the active session to use
3811 @param args.json: boolean, if this flag is set to true, the output
3812 will be provided in json format for programmatic consumption
3813 """
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003814
3815 ldapNameSpaceObjects = listPrivilegeMapping(host, args, session)
Ratan Guptafeee6372018-10-17 23:25:51 +05303816 ldapNameSpaceObjects = json.loads(ldapNameSpaceObjects)["data"]
3817 path = ''
Ratan Guptafeee6372018-10-17 23:25:51 +05303818 data = {"data": []}
3819
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003820 if (isRedfishSupport):
3821 if (args.serverType is None):
3822 serverType = getLDAPTypeEnabled(host,session)
3823 if (serverType is None):
3824 return("LDAP has not been enabled. Please specify LDAP serverType to proceed further...")
3825 # search for the object having the mapping for the given group
3826 for key,value in ldapNameSpaceObjects.items():
3827 if value['GroupName'] == args.groupName:
3828 path = key
3829 break
3830
3831 if path == '':
3832 return "No privilege mapping found for this group."
3833
3834 # delete the object
3835 url = 'https://'+host+path+'/action/Delete'
3836
3837 else:
3838 # not interested in the config objet
3839 ldapNameSpaceObjects.pop('/xyz/openbmc_project/user/ldap/config', None)
3840
3841 # search for the object having the mapping for the given group
3842 for key,value in ldapNameSpaceObjects.items():
3843 if value['GroupName'] == args.groupName:
3844 path = key
3845 break
3846
3847 if path == '':
3848 return "No privilege mapping found for this group."
3849
3850 # delete the object
3851 url = 'https://'+host+path+'/action/delete'
3852
Ratan Guptafeee6372018-10-17 23:25:51 +05303853 try:
Justin Thaler27197622019-01-23 14:42:11 -06003854 res = session.post(url, headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
Ratan Guptafeee6372018-10-17 23:25:51 +05303855 except(requests.exceptions.Timeout):
3856 return(connectionErrHandler(args.json, "Timeout", None))
3857 except(requests.exceptions.ConnectionError) as err:
3858 return connectionErrHandler(args.json, "ConnectionError", err)
3859 return res.text
Ratan Gupta9166cd22018-10-01 18:09:40 +05303860
Sivas SRR78835272018-11-27 05:27:19 -06003861def deleteAllPrivilegeMapping(host, args, session):
3862 """
3863 Called by the ldap function. Deletes all the privilege mapping and group defined.
3864 @param host: string, the hostname or IP address of the bmc
3865 @param args: contains additional arguments used by the ldap subcommand
3866 @param session: the active session to use
3867 @param args.json: boolean, if this flag is set to true, the output
3868 will be provided in json format for programmatic consumption
3869 """
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003870
Sivas SRR78835272018-11-27 05:27:19 -06003871 ldapNameSpaceObjects = listPrivilegeMapping(host, args, session)
3872 ldapNameSpaceObjects = json.loads(ldapNameSpaceObjects)["data"]
3873 path = ''
Sivas SRR78835272018-11-27 05:27:19 -06003874 data = {"data": []}
3875
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003876 if (isRedfishSupport):
3877 if (args.serverType is None):
3878 serverType = getLDAPTypeEnabled(host,session)
3879 if (serverType is None):
3880 return("LDAP has not been enabled. Please specify LDAP serverType to proceed further...")
3881
3882 else:
3883 # Remove the config object.
3884 ldapNameSpaceObjects.pop('/xyz/openbmc_project/user/ldap/config', None)
3885
Sivas SRR78835272018-11-27 05:27:19 -06003886 try:
3887 # search for GroupName property and delete if it is available.
3888 for path in ldapNameSpaceObjects.keys():
3889 # delete the object
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003890 url = 'https://'+host+path+'/action/Delete'
Justin Thaler27197622019-01-23 14:42:11 -06003891 res = session.post(url, headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003892
Sivas SRR78835272018-11-27 05:27:19 -06003893 except(requests.exceptions.Timeout):
3894 return(connectionErrHandler(args.json, "Timeout", None))
3895 except(requests.exceptions.ConnectionError) as err:
3896 return connectionErrHandler(args.json, "ConnectionError", err)
3897 return res.text
3898
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06003899def viewLDAPConfig(host, args, session):
3900 """
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003901 Called by the ldap function. Prints out active LDAP configuration properties
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06003902
3903 @param host: string, the hostname or IP address of the bmc
3904 @param args: contains additional arguments used by the ldap subcommand
3905 args.json: boolean, if this flag is set to true, the output
3906 will be provided in json format for programmatic consumption
3907 @param session: the active session to use
3908 @return returns LDAP's configured properties.
3909 """
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003910
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06003911 try:
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003912 if (isRedfishSupport):
3913
3914 url = "https://"+host+"/xyz/openbmc_project/user/ldap/"
3915
3916 serverTypeEnabled = getLDAPTypeEnabled(host,session)
3917
3918 if (serverTypeEnabled is not None):
3919 data = {"data": []}
3920 res = session.get(url + serverTypeMap[serverTypeEnabled], headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
3921 else:
3922 return("LDAP server has not been enabled...")
3923
3924 else :
3925 url = "https://"+host+"/xyz/openbmc_project/user/ldap/config"
3926 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
3927
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06003928 except(requests.exceptions.Timeout):
3929 return(connectionErrHandler(args.json, "Timeout", None))
3930 except(requests.exceptions.ConnectionError) as err:
3931 return connectionErrHandler(args.json, "ConnectionError", err)
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06003932 if res.status_code == 404:
3933 return "LDAP server config has not been created"
3934 return res.text
3935
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003936def str2bool(v):
3937 if v.lower() in ('yes', 'true', 't', 'y', '1'):
3938 return True
3939 elif v.lower() in ('no', 'false', 'f', 'n', '0'):
3940 return False
3941 else:
3942 raise argparse.ArgumentTypeError('Boolean value expected.')
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06003943
Matt Spinler7d426c22018-09-24 14:42:07 -05003944def localUsers(host, args, session):
3945 """
3946 Enables and disables local BMC users.
3947
3948 @param host: string, the hostname or IP address of the bmc
3949 @param args: contains additional arguments used by the logging sub command
3950 @param session: the active session to use
3951 """
3952
Matt Spinler7d426c22018-09-24 14:42:07 -05003953 url="https://{hostname}/xyz/openbmc_project/user/enumerate".format(hostname=host)
3954 try:
Justin Thaler27197622019-01-23 14:42:11 -06003955 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Matt Spinler7d426c22018-09-24 14:42:07 -05003956 except(requests.exceptions.Timeout):
3957 return(connectionErrHandler(args.json, "Timeout", None))
3958 usersDict = json.loads(res.text)
3959
3960 if not usersDict['data']:
3961 return "No users found"
3962
3963 output = ""
3964 for user in usersDict['data']:
Matt Spinler015adc22018-10-23 14:30:19 -05003965
3966 # Skip LDAP and another non-local users
3967 if 'UserEnabled' not in usersDict['data'][user]:
3968 continue
3969
Matt Spinler7d426c22018-09-24 14:42:07 -05003970 name = user.split('/')[-1]
3971 url = "https://{hostname}{user}/attr/UserEnabled".format(hostname=host, user=user)
3972
3973 if args.local_users == "queryenabled":
3974 try:
Justin Thaler27197622019-01-23 14:42:11 -06003975 res = session.get(url, headers=jsonHeader,verify=False, timeout=baseTimeout)
Matt Spinler7d426c22018-09-24 14:42:07 -05003976 except(requests.exceptions.Timeout):
3977 return(connectionErrHandler(args.json, "Timeout", None))
3978
3979 result = json.loads(res.text)
3980 output += ("User: {name} Enabled: {result}\n").format(name=name, result=result['data'])
3981
3982 elif args.local_users in ["enableall", "disableall"]:
3983 action = ""
3984 if args.local_users == "enableall":
3985 data = '{"data": true}'
3986 action = "Enabling"
3987 else:
3988 data = '{"data": false}'
3989 action = "Disabling"
3990
3991 output += "{action} {name}\n".format(action=action, name=name)
3992
3993 try:
Justin Thaler27197622019-01-23 14:42:11 -06003994 resp = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Matt Spinler7d426c22018-09-24 14:42:07 -05003995 except(requests.exceptions.Timeout):
3996 return connectionErrHandler(args.json, "Timeout", None)
3997 except(requests.exceptions.ConnectionError) as err:
3998 return connectionErrHandler(args.json, "ConnectionError", err)
3999 else:
4000 return "Invalid local users argument"
4001
4002 return output
4003
Marri Devender Rao2c2a5162018-11-05 08:57:11 -06004004def setPassword(host, args, session):
4005 """
4006 Set local user password
4007 @param host: string, the hostname or IP address of the bmc
4008 @param args: contains additional arguments used by the logging sub
4009 command
4010 @param session: the active session to use
4011 @param args.json: boolean, if this flag is set to true, the output
4012 will be provided in json format for programmatic consumption
4013 @return: Session object
4014 """
Marri Devender Rao2c2a5162018-11-05 08:57:11 -06004015 try:
Sunitha Harishc99faba2019-07-19 06:55:22 -05004016 if(isRedfishSupport):
4017 url = "https://" + host + "/redfish/v1/AccountService/Accounts/"+ \
4018 args.user
4019 data = {"Password":args.password}
4020 res = session.patch(url, headers=jsonHeader, json=data,
4021 verify=False, timeout=baseTimeout)
4022 else:
4023 url = "https://" + host + "/xyz/openbmc_project/user/" + args.user + \
4024 "/action/SetPassword"
4025 res = session.post(url, headers=jsonHeader,
Marri Devender Rao2c2a5162018-11-05 08:57:11 -06004026 json={"data": [args.password]}, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06004027 timeout=baseTimeout)
Marri Devender Rao2c2a5162018-11-05 08:57:11 -06004028 except(requests.exceptions.Timeout):
4029 return(connectionErrHandler(args.json, "Timeout", None))
4030 except(requests.exceptions.ConnectionError) as err:
4031 return connectionErrHandler(args.json, "ConnectionError", err)
4032 except(requests.exceptions.RequestException) as err:
4033 return connectionErrHandler(args.json, "RequestException", err)
Sunitha Harishc99faba2019-07-19 06:55:22 -05004034 return res.status_code
Matthew Barth368e83c2019-02-01 13:48:25 -06004035
4036def getThermalZones(host, args, session):
4037 """
4038 Get the available thermal control zones
4039 @param host: string, the hostname or IP address of the bmc
4040 @param args: contains additional arguments used to get the thermal
4041 control zones
4042 @param session: the active session to use
4043 @return: Session object
4044 """
4045 url = "https://" + host + "/xyz/openbmc_project/control/thermal/enumerate"
4046
4047 try:
4048 res = session.get(url, headers=jsonHeader, verify=False, timeout=30)
4049 except(requests.exceptions.Timeout):
4050 return(connectionErrHandler(args.json, "Timeout", None))
4051 except(requests.exceptions.ConnectionError) as err:
4052 return connectionErrHandler(args.json, "ConnectionError", err)
4053 except(requests.exceptions.RequestException) as err:
4054 return connectionErrHandler(args.json, "RequestException", err)
4055
4056 if (res.status_code == 404):
Matthew Barth0939e822019-09-27 15:47:50 -05004057 return "No thermal control zones found"
Matthew Barth368e83c2019-02-01 13:48:25 -06004058
4059 zonesDict = json.loads(res.text)
4060 if not zonesDict['data']:
4061 return "No thermal control zones found"
4062 for zone in zonesDict['data']:
4063 z = ",".join(str(zone.split('/')[-1]) for zone in zonesDict['data'])
4064
4065 return "Zones: [ " + z + " ]"
4066
4067
4068def getThermalMode(host, args, session):
4069 """
4070 Get thermal control mode
4071 @param host: string, the hostname or IP address of the bmc
4072 @param args: contains additional arguments used to get the thermal
4073 control mode
4074 @param session: the active session to use
4075 @param args.zone: the zone to get the mode on
4076 @return: Session object
4077 """
4078 url = "https://" + host + "/xyz/openbmc_project/control/thermal/" + \
4079 args.zone
4080
4081 try:
4082 res = session.get(url, headers=jsonHeader, verify=False, timeout=30)
4083 except(requests.exceptions.Timeout):
4084 return(connectionErrHandler(args.json, "Timeout", None))
4085 except(requests.exceptions.ConnectionError) as err:
4086 return connectionErrHandler(args.json, "ConnectionError", err)
4087 except(requests.exceptions.RequestException) as err:
4088 return connectionErrHandler(args.json, "RequestException", err)
4089
4090 if (res.status_code == 404):
Matthew Barth0939e822019-09-27 15:47:50 -05004091 return "Thermal control zone(" + args.zone + ") not found"
Matthew Barth368e83c2019-02-01 13:48:25 -06004092
4093 propsDict = json.loads(res.text)
4094 if not propsDict['data']:
4095 return "No thermal control properties found on zone(" + args.zone + ")"
4096 curMode = "Current"
4097 supModes = "Supported"
4098 result = "\n"
4099 for prop in propsDict['data']:
4100 if (prop.casefold() == curMode.casefold()):
4101 result += curMode + " Mode: " + propsDict['data'][curMode] + "\n"
4102 if (prop.casefold() == supModes.casefold()):
4103 s = ", ".join(str(sup) for sup in propsDict['data'][supModes])
4104 result += supModes + " Modes: [ " + s + " ]\n"
4105
4106 return result
4107
4108def setThermalMode(host, args, session):
4109 """
4110 Set thermal control mode
4111 @param host: string, the hostname or IP address of the bmc
4112 @param args: contains additional arguments used for setting the thermal
4113 control mode
4114 @param session: the active session to use
4115 @param args.zone: the zone to set the mode on
4116 @param args.mode: the mode to enable
4117 @return: Session object
4118 """
4119 url = "https://" + host + "/xyz/openbmc_project/control/thermal/" + \
4120 args.zone + "/attr/Current"
4121
4122 # Check args.mode against supported modes using `getThermalMode` output
4123 modes = getThermalMode(host, args, session)
4124 modes = os.linesep.join([m for m in modes.splitlines() if m])
4125 modes = modes.replace("\n", ";").strip()
4126 modesDict = dict(m.split(': ') for m in modes.split(';'))
4127 sModes = ''.join(s for s in modesDict['Supported Modes'] if s not in '[ ]')
4128 if args.mode.casefold() not in \
4129 (m.casefold() for m in sModes.split(',')) or not args.mode:
4130 result = ("Unsupported mode('" + args.mode + "') given, " +
4131 "select a supported mode: \n" +
4132 getThermalMode(host, args, session))
4133 return result
4134
4135 data = '{"data":"' + args.mode + '"}'
4136 try:
4137 res = session.get(url, headers=jsonHeader, verify=False, timeout=30)
4138 except(requests.exceptions.Timeout):
4139 return(connectionErrHandler(args.json, "Timeout", None))
4140 except(requests.exceptions.ConnectionError) as err:
4141 return connectionErrHandler(args.json, "ConnectionError", err)
4142 except(requests.exceptions.RequestException) as err:
4143 return connectionErrHandler(args.json, "RequestException", err)
4144
4145 if (data and res.status_code != 404):
4146 try:
4147 res = session.put(url, headers=jsonHeader,
4148 data=data, verify=False,
4149 timeout=30)
4150 except(requests.exceptions.Timeout):
4151 return(connectionErrHandler(args.json, "Timeout", None))
4152 except(requests.exceptions.ConnectionError) as err:
4153 return connectionErrHandler(args.json, "ConnectionError", err)
4154 except(requests.exceptions.RequestException) as err:
4155 return connectionErrHandler(args.json, "RequestException", err)
4156
4157 if res.status_code == 403:
4158 return "The specified thermal control zone(" + args.zone + ")" + \
4159 " does not exist"
4160
4161 return res.text
4162 else:
4163 return "Setting thermal control mode(" + args.mode + ")" + \
Matthew Barth0939e822019-09-27 15:47:50 -05004164 " not supported or operation not available"
Matthew Barth368e83c2019-02-01 13:48:25 -06004165
4166
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004167def createCommandParser():
Justin Thalere412dc22018-01-12 16:28:24 -06004168 """
4169 creates the parser for the command line along with help for each command and subcommand
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004170
Justin Thalere412dc22018-01-12 16:28:24 -06004171 @return: returns the parser for the command line
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004172 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004173 parser = argparse.ArgumentParser(description='Process arguments')
Justin Thalere412dc22018-01-12 16:28:24 -06004174 parser.add_argument("-H", "--host", help='A hostname or IP for the BMC')
4175 parser.add_argument("-U", "--user", help='The username to login with')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004176 group = parser.add_mutually_exclusive_group()
4177 group.add_argument("-A", "--askpw", action='store_true', help='prompt for password')
4178 group.add_argument("-P", "--PW", help='Provide the password in-line')
Joseph Reynoldsa2d54c52019-06-11 22:02:57 -05004179 group.add_argument("-E", "--PWenvvar", action='store_true', help='Get password from envvar OPENBMCTOOL_PASSWORD')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004180 parser.add_argument('-j', '--json', action='store_true', help='output json data only')
4181 parser.add_argument('-t', '--policyTableLoc', help='The location of the policy table to parse alerts')
4182 parser.add_argument('-c', '--CerFormat', action='store_true', help=argparse.SUPPRESS)
4183 parser.add_argument('-T', '--procTime', action='store_true', help= argparse.SUPPRESS)
Justin Thalere412dc22018-01-12 16:28:24 -06004184 parser.add_argument('-V', '--version', action='store_true', help='Display the version number of the openbmctool')
4185 subparsers = parser.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004186
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004187 #fru command
4188 parser_inv = subparsers.add_parser("fru", help='Work with platform inventory')
Justin Thalere412dc22018-01-12 16:28:24 -06004189 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 -05004190 inv_subparser.required = True
4191 #fru print
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004192 inv_print = inv_subparser.add_parser("print", help="prints out a list of all FRUs")
4193 inv_print.set_defaults(func=fruPrint)
4194 #fru list [0....n]
4195 inv_list = inv_subparser.add_parser("list", help="print out details on selected FRUs. Specifying no items will list the entire inventory")
4196 inv_list.add_argument('items', nargs='?', help="print out details on selected FRUs. Specifying no items will list the entire inventory")
4197 inv_list.set_defaults(func=fruList)
4198 #fru status
4199 inv_status = inv_subparser.add_parser("status", help="prints out the status of all FRUs")
Justin Thalere412dc22018-01-12 16:28:24 -06004200 inv_status.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004201 inv_status.set_defaults(func=fruStatus)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004202
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004203 #sensors command
4204 parser_sens = subparsers.add_parser("sensors", help="Work with platform sensors")
Justin Thalere412dc22018-01-12 16:28:24 -06004205 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 -05004206 sens_subparser.required = True
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004207 #sensor print
4208 sens_print= sens_subparser.add_parser('print', help="prints out a list of all Sensors.")
4209 sens_print.set_defaults(func=sensor)
4210 #sensor list[0...n]
4211 sens_list=sens_subparser.add_parser("list", help="Lists all Sensors in the platform. Specify a sensor for full details. ")
4212 sens_list.add_argument("sensNum", nargs='?', help="The Sensor number to get full details on" )
4213 sens_list.set_defaults(func=sensor)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004214
Matthew Barth368e83c2019-02-01 13:48:25 -06004215 #thermal control commands
4216 parser_therm = subparsers.add_parser("thermal", help="Work with thermal control parameters")
4217 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')
4218 #thermal control zones
4219 parser_thermZones = therm_subparser.add_parser("zones", help="Get a list of available thermal control zones")
4220 parser_thermZones.set_defaults(func=getThermalZones)
4221 #thermal control modes
4222 parser_thermMode = therm_subparser.add_parser("modes", help="Work with thermal control modes")
4223 thermMode_sub = parser_thermMode.add_subparsers(title='subactions', description='Work with thermal control modes', help="Work with thermal control modes")
4224 #get thermal control mode
4225 parser_getThermMode = thermMode_sub.add_parser("get", help="Get current and supported thermal control modes")
4226 parser_getThermMode.add_argument('-z', '--zone', required=True, help='Thermal zone to work with')
4227 parser_getThermMode.set_defaults(func=getThermalMode)
4228 #set thermal control mode
4229 parser_setThermMode = thermMode_sub.add_parser("set", help="Set the thermal control mode")
4230 parser_setThermMode.add_argument('-z', '--zone', required=True, help='Thermal zone to work with')
4231 parser_setThermMode.add_argument('-m', '--mode', required=True, help='The supported thermal control mode')
4232 parser_setThermMode.set_defaults(func=setThermalMode)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004233
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004234 #sel command
4235 parser_sel = subparsers.add_parser("sel", help="Work with platform alerts")
Justin Thalere412dc22018-01-12 16:28:24 -06004236 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 -05004237 sel_subparser.required = True
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004238 #sel print
4239 sel_print = sel_subparser.add_parser("print", help="prints out a list of all sels in a condensed list")
4240 sel_print.add_argument('-d', '--devdebug', action='store_true', help=argparse.SUPPRESS)
4241 sel_print.add_argument('-v', '--verbose', action='store_true', help="Changes the output to being very verbose")
4242 sel_print.add_argument('-f', '--fileloc', help='Parse a file instead of the BMC output')
4243 sel_print.set_defaults(func=selPrint)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004244
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004245 #sel list
4246 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")
4247 sel_list.add_argument("selNum", nargs='?', type=int, help="The SEL entry to get details on")
4248 sel_list.set_defaults(func=selList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004249
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004250 sel_get = sel_subparser.add_parser("get", help="Gets the verbose details of a specified SEL entry")
4251 sel_get.add_argument('selNum', type=int, help="the number of the SEL entry to get")
4252 sel_get.set_defaults(func=selList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004253
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004254 sel_clear = sel_subparser.add_parser("clear", help="Clears all entries from the SEL")
4255 sel_clear.set_defaults(func=selClear)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004256
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004257 sel_setResolved = sel_subparser.add_parser("resolve", help="Sets the sel entry to resolved")
Justin Thalere412dc22018-01-12 16:28:24 -06004258 sel_setResolved.add_argument('-n', '--selNum', type=int, help="the number of the SEL entry to resolve")
4259 sel_ResolveAll_sub = sel_setResolved.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
4260 sel_ResolveAll = sel_ResolveAll_sub.add_parser('all', help='Resolve all SEL entries')
4261 sel_ResolveAll.set_defaults(func=selResolveAll)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004262 sel_setResolved.set_defaults(func=selSetResolved)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004263
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004264 parser_chassis = subparsers.add_parser("chassis", help="Work with chassis power and status")
Justin Thalere412dc22018-01-12 16:28:24 -06004265 chas_sub = parser_chassis.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004266
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004267 parser_chassis.add_argument('status', action='store_true', help='Returns the current status of the platform')
4268 parser_chassis.set_defaults(func=chassis)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004269
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004270 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 -06004271 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 -06004272 parser_chasPower.set_defaults(func=chassisPower)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004273
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004274 #control the chassis identify led
4275 parser_chasIdent = chas_sub.add_parser("identify", help="Control the chassis identify led")
4276 parser_chasIdent.add_argument('identcmd', choices=['on', 'off', 'status'], help='The control option for the led: on, off, blink, status')
4277 parser_chasIdent.set_defaults(func=chassisIdent)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004278
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004279 #collect service data
4280 parser_servData = subparsers.add_parser("collect_service_data", help="Collect all bmc data needed for service")
4281 parser_servData.add_argument('-d', '--devdebug', action='store_true', help=argparse.SUPPRESS)
4282 parser_servData.set_defaults(func=collectServiceData)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004283
Justin Thalere412dc22018-01-12 16:28:24 -06004284 #system quick health check
4285 parser_healthChk = subparsers.add_parser("health_check", help="Work with platform sensors")
4286 parser_healthChk.set_defaults(func=healthCheck)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004287
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004288 #work with bmc dumps
4289 parser_bmcdump = subparsers.add_parser("dump", help="Work with bmc dump files")
Justin Thalere412dc22018-01-12 16:28:24 -06004290 bmcDump_sub = parser_bmcdump.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Justin Thaler53bf2f12018-07-16 14:05:32 -05004291 bmcDump_sub.required = True
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004292 dump_Create = bmcDump_sub.add_parser('create', help="Create a bmc dump")
4293 dump_Create.set_defaults(func=bmcDumpCreate)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004294
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004295 dump_list = bmcDump_sub.add_parser('list', help="list all bmc dump files")
4296 dump_list.set_defaults(func=bmcDumpList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004297
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004298 parserdumpdelete = bmcDump_sub.add_parser('delete', help="Delete bmc dump files")
4299 parserdumpdelete.add_argument("-n", "--dumpNum", nargs='*', type=int, help="The Dump entry to delete")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004300 parserdumpdelete.set_defaults(func=bmcDumpDelete)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004301
Justin Thalere412dc22018-01-12 16:28:24 -06004302 bmcDumpDelsub = parserdumpdelete.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004303 deleteAllDumps = bmcDumpDelsub.add_parser('all', help='Delete all bmc dump files')
4304 deleteAllDumps.set_defaults(func=bmcDumpDeleteAll)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004305
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004306 parser_dumpretrieve = bmcDump_sub.add_parser('retrieve', help='Retrieve a dump file')
4307 parser_dumpretrieve.add_argument("dumpNum", type=int, help="The Dump entry to delete")
4308 parser_dumpretrieve.add_argument("-s", "--dumpSaveLoc", help="The location to save the bmc dump file")
4309 parser_dumpretrieve.set_defaults(func=bmcDumpRetrieve)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004310
Justin Thaler22b1bb52018-03-15 13:31:32 -05004311 #bmc command for reseting the bmc
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004312 parser_bmc = subparsers.add_parser('bmc', help="Work with the bmc")
Justin Thalere412dc22018-01-12 16:28:24 -06004313 bmc_sub = parser_bmc.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004314 parser_BMCReset = bmc_sub.add_parser('reset', help='Reset the bmc' )
4315 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 -06004316 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.")
4317 parser_bmc.set_defaults(func=bmc)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004318
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004319 #add alias to the bmc command
4320 parser_mc = subparsers.add_parser('mc', help="Work with the management controller")
Justin Thalere412dc22018-01-12 16:28:24 -06004321 mc_sub = parser_mc.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004322 parser_MCReset = mc_sub.add_parser('reset', help='Reset the bmc' )
4323 parser_MCReset.add_argument('type', choices=['warm','cold'], help="Reboot the BMC")
4324 #parser_MCReset.add_argument('cold', action='store_true', help="Reboot the BMC and CLEAR the configuration")
4325 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 -06004326 parser_MCReset.set_defaults(func=bmcReset)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004327 parser_mc.set_defaults(func=bmc)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004328
Justin Thalere412dc22018-01-12 16:28:24 -06004329 #gard clear
4330 parser_gc = subparsers.add_parser("gardclear", help="Used to clear gard records")
4331 parser_gc.set_defaults(func=gardClear)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004332
Justin Thalere412dc22018-01-12 16:28:24 -06004333 #firmware_flash
4334 parser_fw = subparsers.add_parser("firmware", help="Work with the system firmware")
4335 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 -05004336 fwflash_subproc.required = True
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004337
Justin Thalere412dc22018-01-12 16:28:24 -06004338 fwflash = fwflash_subproc.add_parser('flash', help="Flash the system firmware")
4339 fwflash.add_argument('type', choices=['bmc', 'pnor'], help="image type to flash")
4340 fwflash.add_argument('-f', '--fileloc', required=True, help="The absolute path to the firmware image")
4341 fwflash.set_defaults(func=fwFlash)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004342
Justin Thaler22b1bb52018-03-15 13:31:32 -05004343 fwActivate = fwflash_subproc.add_parser('activate', help="Activate existing image on the bmc")
Justin Thalere412dc22018-01-12 16:28:24 -06004344 fwActivate.add_argument('imageID', help="The image ID to activate from the firmware list. Ex: 63c95399")
4345 fwActivate.set_defaults(func=activateFWImage)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004346
Justin Thaler22b1bb52018-03-15 13:31:32 -05004347 fwActivateStatus = fwflash_subproc.add_parser('activation_status', help="Check Status of activations")
4348 fwActivateStatus.set_defaults(func=activateStatus)
4349
Justin Thaler3d71d402018-07-24 14:35:39 -05004350 fwList = fwflash_subproc.add_parser('list', help="List all of the installed firmware")
4351 fwList.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
4352 fwList.set_defaults(func=firmwareList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004353
Justin Thaler3d71d402018-07-24 14:35:39 -05004354 fwprint = fwflash_subproc.add_parser('print', help="List all of the installed firmware")
4355 fwprint.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
4356 fwprint.set_defaults(func=firmwareList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004357
Adriana Kobylak5af2fad2018-11-08 12:33:43 -06004358 fwDelete = fwflash_subproc.add_parser('delete', help="Delete an existing firmware version")
4359 fwDelete.add_argument('versionID', help="The version ID to delete from the firmware list. Ex: 63c95399")
4360 fwDelete.set_defaults(func=deleteFWVersion)
4361
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05004362 #logging
4363 parser_logging = subparsers.add_parser("logging", help="logging controls")
4364 logging_sub = parser_logging.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004365
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05004366 #turn rest api logging on/off
4367 parser_rest_logging = logging_sub.add_parser("rest_api", help="turn rest api logging on/off")
4368 parser_rest_logging.add_argument('rest_logging', choices=['on', 'off'], help='The control option for rest logging: on, off')
4369 parser_rest_logging.set_defaults(func=restLogging)
Deepak Kodihalli02d53282018-09-18 06:53:31 -05004370
4371 #remote logging
4372 parser_remote_logging = logging_sub.add_parser("remote_logging", help="Remote logging (rsyslog) commands")
4373 parser_remote_logging.add_argument('remote_logging', choices=['view', 'disable'], help='Remote logging (rsyslog) commands')
4374 parser_remote_logging.set_defaults(func=remoteLogging)
4375
4376 #configure remote logging
4377 parser_remote_logging_config = logging_sub.add_parser("remote_logging_config", help="Configure remote logging (rsyslog)")
4378 parser_remote_logging_config.add_argument("-a", "--address", required=True, help="Set IP address of rsyslog server")
4379 parser_remote_logging_config.add_argument("-p", "--port", required=True, type=int, help="Set Port of rsyslog server")
4380 parser_remote_logging_config.set_defaults(func=remoteLoggingConfig)
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05004381
4382 #certificate management
4383 parser_cert = subparsers.add_parser("certificate", help="Certificate management")
4384 certMgmt_subproc = parser_cert.add_subparsers(title='subcommands', description='valid certificate commands', help='sub-command help', dest='command')
4385
4386 certUpdate = certMgmt_subproc.add_parser('update', help="Update the certificate")
4387 certUpdate.add_argument('type', choices=['server', 'client', 'authority'], help="certificate type to update")
4388 certUpdate.add_argument('service', choices=['https', 'ldap'], help="Service to update")
4389 certUpdate.add_argument('-f', '--fileloc', required=True, help="The absolute path to the certificate file")
4390 certUpdate.set_defaults(func=certificateUpdate)
4391
4392 certDelete = certMgmt_subproc.add_parser('delete', help="Delete the certificate")
4393 certDelete.add_argument('type', choices=['server', 'client', 'authority'], help="certificate type to delete")
4394 certDelete.add_argument('service', choices=['https', 'ldap'], help="Service to delete the certificate")
4395 certDelete.set_defaults(func=certificateDelete)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004396
Marri Devender Raodfe81ad2019-07-01 05:38:09 -05004397 certReplace = certMgmt_subproc.add_parser('replace',
4398 help="Replace the certificate")
4399 certReplace.add_argument('type', choices=['server', 'client', 'authority'],
4400 help="certificate type to replace")
4401 certReplace.add_argument('service', choices=['https', 'ldap'],
4402 help="Service to replace the certificate")
4403 certReplace.add_argument('-f', '--fileloc', required=True,
4404 help="The absolute path to the certificate file")
4405 certReplace.set_defaults(func=certificateReplace)
4406
Marri Devender Rao34646402019-07-01 05:46:03 -05004407 certDisplay = certMgmt_subproc.add_parser('display',
4408 help="Print the certificate")
4409 certDisplay.add_argument('type', choices=['server', 'client', 'authority'],
4410 help="certificate type to display")
4411 certDisplay.set_defaults(func=certificateDisplay)
4412
Marri Devender Raoa208ff82019-07-01 05:51:27 -05004413 certList = certMgmt_subproc.add_parser('list',
4414 help="Certificate list")
4415 certList.set_defaults(func=certificateList)
4416
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05004417 certGenerateCSR = certMgmt_subproc.add_parser('generatecsr', help="Generate CSR")
4418 certGenerateCSR.add_argument('type', choices=['server', 'client', 'authority'],
4419 help="Generate CSR")
4420 certGenerateCSR.add_argument('city',
4421 help="The city or locality of the organization making the request")
4422 certGenerateCSR.add_argument('commonName',
4423 help="The fully qualified domain name of the component that is being secured.")
4424 certGenerateCSR.add_argument('country',
4425 help="The country of the organization making the request")
4426 certGenerateCSR.add_argument('organization',
4427 help="The name of the organization making the request.")
4428 certGenerateCSR.add_argument('organizationUnit',
4429 help="The name of the unit or division of the organization making the request.")
4430 certGenerateCSR.add_argument('state',
4431 help="The state, province, or region of the organization making the request.")
4432 certGenerateCSR.add_argument('keyPairAlgorithm', choices=['RSA', 'EC'],
4433 help="The type of key pair for use with signing algorithms.")
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05004434 certGenerateCSR.add_argument('keyCurveId',
4435 help="The curve ID to be used with the key, if needed based on the value of the 'KeyPairAlgorithm' parameter.")
4436 certGenerateCSR.add_argument('contactPerson',
4437 help="The name of the user making the request")
4438 certGenerateCSR.add_argument('email',
4439 help="The email address of the contact within the organization")
4440 certGenerateCSR.add_argument('alternativeNames',
4441 help="Additional hostnames of the component that is being secured")
4442 certGenerateCSR.add_argument('givenname',
4443 help="The given name of the user making the request")
4444 certGenerateCSR.add_argument('surname',
4445 help="The surname of the user making the request")
4446 certGenerateCSR.add_argument('unstructuredname',
4447 help="he unstructured name of the subject")
4448 certGenerateCSR.add_argument('initials',
4449 help="The initials of the user making the request")
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05004450 certGenerateCSR.set_defaults(func=certificateGenerateCSR)
4451
Matt Spinler7d426c22018-09-24 14:42:07 -05004452 # local users
4453 parser_users = subparsers.add_parser("local_users", help="Work with local users")
4454 parser_users.add_argument('local_users', choices=['disableall','enableall', 'queryenabled'], help="Disable, enable or query local user accounts")
4455 parser_users.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
4456 parser_users.set_defaults(func=localUsers)
4457
Ratan Gupta9166cd22018-10-01 18:09:40 +05304458 #LDAP
4459 parser_ldap = subparsers.add_parser("ldap", help="LDAP controls")
4460 ldap_sub = parser_ldap.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
4461
4462 #configure and enable LDAP
4463 parser_ldap_config = ldap_sub.add_parser("enable", help="Configure and enables the LDAP")
4464 parser_ldap_config.add_argument("-a", "--uri", required=True, help="Set LDAP server URI")
4465 parser_ldap_config.add_argument("-B", "--bindDN", required=True, help="Set the bind DN of the LDAP server")
4466 parser_ldap_config.add_argument("-b", "--baseDN", required=True, help="Set the base DN of the LDAP server")
4467 parser_ldap_config.add_argument("-p", "--bindPassword", required=True, help="Set the bind password of the LDAP server")
4468 parser_ldap_config.add_argument("-S", "--scope", choices=['sub','one', 'base'],
4469 help='Specifies the search scope:subtree, one level or base object.')
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004470 parser_ldap_config.add_argument("-t", "--serverType", required=True, choices=['ActiveDirectory','OpenLDAP'],
Ratan Gupta9166cd22018-10-01 18:09:40 +05304471 help='Specifies the configured server is ActiveDirectory(AD) or OpenLdap')
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004472 parser_ldap_config.add_argument("-g","--groupAttrName", required=False, default='', help="Group Attribute Name")
4473 parser_ldap_config.add_argument("-u","--userAttrName", required=False, default='', help="User Attribute Name")
4474 parser_ldap_config.set_defaults(func=enableLDAPConfig)
Ratan Gupta9166cd22018-10-01 18:09:40 +05304475
4476 # disable LDAP
4477 parser_disable_ldap = ldap_sub.add_parser("disable", help="disables the LDAP")
4478 parser_disable_ldap.set_defaults(func=disableLDAP)
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06004479 # view-config
4480 parser_ldap_config = \
4481 ldap_sub.add_parser("view-config", help="prints out a list of all \
4482 LDAPS's configured properties")
4483 parser_ldap_config.set_defaults(func=viewLDAPConfig)
Ratan Gupta9166cd22018-10-01 18:09:40 +05304484
Ratan Guptafeee6372018-10-17 23:25:51 +05304485 #create group privilege mapping
4486 parser_ldap_mapper = ldap_sub.add_parser("privilege-mapper", help="LDAP group privilege controls")
4487 parser_ldap_mapper_sub = parser_ldap_mapper.add_subparsers(title='subcommands', description='valid subcommands',
4488 help="sub-command help", dest='command')
4489
4490 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 -05004491 parser_ldap_mapper_create.add_argument("-t", "--serverType", choices=['ActiveDirectory','OpenLDAP'],
4492 help='Specifies the configured server is ActiveDirectory(AD) or OpenLdap')
Ratan Guptafeee6372018-10-17 23:25:51 +05304493 parser_ldap_mapper_create.add_argument("-g","--groupName",required=True,help="Group Name")
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004494 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 +05304495 parser_ldap_mapper_create.set_defaults(func=createPrivilegeMapping)
4496
4497 #list group privilege mapping
4498 parser_ldap_mapper_list = parser_ldap_mapper_sub.add_parser("list",help="List privilege mapping")
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004499 parser_ldap_mapper_list.add_argument("-t", "--serverType", choices=['ActiveDirectory','OpenLDAP'],
4500 help='Specifies the configured server is ActiveDirectory(AD) or OpenLdap')
Ratan Guptafeee6372018-10-17 23:25:51 +05304501 parser_ldap_mapper_list.set_defaults(func=listPrivilegeMapping)
4502
4503 #delete group privilege mapping
4504 parser_ldap_mapper_delete = parser_ldap_mapper_sub.add_parser("delete",help="Delete privilege mapping")
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004505 parser_ldap_mapper_delete.add_argument("-t", "--serverType", choices=['ActiveDirectory','OpenLDAP'],
4506 help='Specifies the configured server is ActiveDirectory(AD) or OpenLdap')
Ratan Guptafeee6372018-10-17 23:25:51 +05304507 parser_ldap_mapper_delete.add_argument("-g","--groupName",required=True,help="Group Name")
4508 parser_ldap_mapper_delete.set_defaults(func=deletePrivilegeMapping)
4509
Sivas SRR78835272018-11-27 05:27:19 -06004510 #deleteAll group privilege mapping
4511 parser_ldap_mapper_delete = parser_ldap_mapper_sub.add_parser("purge",help="Delete All privilege mapping")
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004512 parser_ldap_mapper_delete.add_argument("-t", "--serverType", choices=['ActiveDirectory','OpenLDAP'],
4513 help='Specifies the configured server is ActiveDirectory(AD) or OpenLdap')
Sivas SRR78835272018-11-27 05:27:19 -06004514 parser_ldap_mapper_delete.set_defaults(func=deleteAllPrivilegeMapping)
4515
Marri Devender Rao2c2a5162018-11-05 08:57:11 -06004516 # set local user password
4517 parser_set_password = subparsers.add_parser("set_password",
4518 help="Set password of local user")
4519 parser_set_password.add_argument( "-p", "--password", required=True,
4520 help="Password of local user")
4521 parser_set_password.set_defaults(func=setPassword)
4522
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004523 # network
4524 parser_nw = subparsers.add_parser("network", help="network controls")
4525 nw_sub = parser_nw.add_subparsers(title='subcommands',
4526 description='valid subcommands',
4527 help="sub-command help",
4528 dest='command')
4529
4530 # enable DHCP
4531 parser_enable_dhcp = nw_sub.add_parser("enableDHCP",
4532 help="enables the DHCP on given "
4533 "Interface")
4534 parser_enable_dhcp.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004535 help="Name of the ethernet interface(it can"
4536 "be obtained by the "
4537 "command:network view-config)"
4538 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004539 parser_enable_dhcp.set_defaults(func=enableDHCP)
4540
4541 # disable DHCP
4542 parser_disable_dhcp = nw_sub.add_parser("disableDHCP",
4543 help="disables the DHCP on given "
4544 "Interface")
4545 parser_disable_dhcp.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004546 help="Name of the ethernet interface(it can"
4547 "be obtained by the "
4548 "command:network view-config)"
4549 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004550 parser_disable_dhcp.set_defaults(func=disableDHCP)
4551
4552 # get HostName
4553 parser_gethostname = nw_sub.add_parser("getHostName",
4554 help="prints out HostName")
4555 parser_gethostname.set_defaults(func=getHostname)
4556
4557 # set HostName
4558 parser_sethostname = nw_sub.add_parser("setHostName", help="sets HostName")
4559 parser_sethostname.add_argument("-H", "--HostName", required=True,
4560 help="A HostName for the BMC")
4561 parser_sethostname.set_defaults(func=setHostname)
4562
4563 # get domainname
4564 parser_getdomainname = nw_sub.add_parser("getDomainName",
4565 help="prints out DomainName of "
4566 "given Interface")
4567 parser_getdomainname.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004568 help="Name of the ethernet interface(it "
4569 "can be obtained by the "
4570 "command:network view-config)"
4571 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004572 parser_getdomainname.set_defaults(func=getDomainName)
4573
4574 # set domainname
4575 parser_setdomainname = nw_sub.add_parser("setDomainName",
4576 help="sets DomainName of given "
4577 "Interface")
4578 parser_setdomainname.add_argument("-D", "--DomainName", required=True,
4579 help="Ex: DomainName=Domain1,Domain2,...")
4580 parser_setdomainname.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004581 help="Name of the ethernet interface(it "
4582 "can be obtained by the "
4583 "command:network view-config)"
4584 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004585 parser_setdomainname.set_defaults(func=setDomainName)
4586
4587 # get MACAddress
4588 parser_getmacaddress = nw_sub.add_parser("getMACAddress",
4589 help="prints out MACAddress the "
4590 "given Interface")
4591 parser_getmacaddress.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004592 help="Name of the ethernet interface(it "
4593 "can be obtained by the "
4594 "command:network view-config)"
4595 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004596 parser_getmacaddress.set_defaults(func=getMACAddress)
4597
4598 # set MACAddress
4599 parser_setmacaddress = nw_sub.add_parser("setMACAddress",
4600 help="sets MACAddress")
4601 parser_setmacaddress.add_argument("-MA", "--MACAddress", required=True,
4602 help="A MACAddress for the given "
4603 "Interface")
4604 parser_setmacaddress.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004605 help="Name of the ethernet interface(it can"
4606 "be obtained by the "
4607 "command:network view-config)"
4608 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004609 parser_setmacaddress.set_defaults(func=setMACAddress)
4610
4611 # get DefaultGW
4612 parser_getdefaultgw = nw_sub.add_parser("getDefaultGW",
4613 help="prints out DefaultGateway "
4614 "the BMC")
4615 parser_getdefaultgw.set_defaults(func=getDefaultGateway)
4616
4617 # set DefaultGW
4618 parser_setdefaultgw = nw_sub.add_parser("setDefaultGW",
4619 help="sets DefaultGW")
4620 parser_setdefaultgw.add_argument("-GW", "--DefaultGW", required=True,
4621 help="A DefaultGateway for the BMC")
4622 parser_setdefaultgw.set_defaults(func=setDefaultGateway)
4623
4624 # view network Config
4625 parser_ldap_config = nw_sub.add_parser("view-config", help="prints out a "
4626 "list of all network's configured "
4627 "properties")
4628 parser_ldap_config.set_defaults(func=viewNWConfig)
4629
4630 # get DNS
4631 parser_getDNS = nw_sub.add_parser("getDNS",
4632 help="prints out DNS servers on the "
4633 "given interface")
4634 parser_getDNS.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004635 help="Name of the ethernet interface(it can"
4636 "be obtained by the "
4637 "command:network view-config)"
4638 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004639 parser_getDNS.set_defaults(func=getDNS)
4640
4641 # set DNS
4642 parser_setDNS = nw_sub.add_parser("setDNS",
4643 help="sets DNS servers on the given "
4644 "interface")
4645 parser_setDNS.add_argument("-d", "--DNSServers", required=True,
4646 help="Ex: DNSSERVERS=DNS1,DNS2,...")
4647 parser_setDNS.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004648 help="Name of the ethernet interface(it can"
4649 "be obtained by the "
4650 "command:network view-config)"
4651 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004652 parser_setDNS.set_defaults(func=setDNS)
4653
4654 # get NTP
4655 parser_getNTP = nw_sub.add_parser("getNTP",
4656 help="prints out NTP servers on the "
4657 "given interface")
4658 parser_getNTP.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004659 help="Name of the ethernet interface(it can"
4660 "be obtained by the "
4661 "command:network view-config)"
4662 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004663 parser_getNTP.set_defaults(func=getNTP)
4664
4665 # set NTP
4666 parser_setNTP = nw_sub.add_parser("setNTP",
4667 help="sets NTP servers on the given "
4668 "interface")
4669 parser_setNTP.add_argument("-N", "--NTPServers", required=True,
4670 help="Ex: NTPSERVERS=NTP1,NTP2,...")
4671 parser_setNTP.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004672 help="Name of the ethernet interface(it can"
4673 "be obtained by the "
4674 "command:network view-config)"
4675 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004676 parser_setNTP.set_defaults(func=setNTP)
4677
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004678 # configure IP
4679 parser_ip_config = nw_sub.add_parser("addIP", help="Sets IP address to"
4680 "given interface")
4681 parser_ip_config.add_argument("-a", "--address", required=True,
4682 help="IP address of given interface")
4683 parser_ip_config.add_argument("-gw", "--gateway", required=False, default='',
4684 help="The gateway for given interface")
4685 parser_ip_config.add_argument("-l", "--prefixLength", required=True,
4686 help="The prefixLength of IP address")
Sunitha Harish0baf6372019-07-31 03:59:03 -05004687 parser_ip_config.add_argument("-p", "--type", required=True,
4688 choices=['ipv4', 'ipv6'],
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004689 help="The protocol type of the given"
4690 "IP address")
4691 parser_ip_config.add_argument("-I", "--Interface", required=True,
4692 help="Name of the ethernet interface(it can"
4693 "be obtained by the "
4694 "command:network view-config)"
4695 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
4696 parser_ip_config.set_defaults(func=addIP)
4697
4698 # getIP
4699 parser_getIP = nw_sub.add_parser("getIP", help="prints out IP address"
4700 "of given interface")
4701 parser_getIP.add_argument("-I", "--Interface", required=True,
4702 help="Name of the ethernet interface(it can"
4703 "be obtained by the command:network view-config)"
4704 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
4705 parser_getIP.set_defaults(func=getIP)
4706
4707 # rmIP
4708 parser_rmIP = nw_sub.add_parser("rmIP", help="deletes IP address"
4709 "of given interface")
4710 parser_rmIP.add_argument("-a", "--address", required=True,
4711 help="IP address to remove form given Interface")
4712 parser_rmIP.add_argument("-I", "--Interface", required=True,
4713 help="Name of the ethernet interface(it can"
4714 "be obtained by the command:network view-config)"
4715 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
4716 parser_rmIP.set_defaults(func=deleteIP)
4717
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004718 # add VLAN
4719 parser_create_vlan = nw_sub.add_parser("addVLAN", help="enables VLAN "
4720 "on given interface with given "
4721 "VLAN Identifier")
4722 parser_create_vlan.add_argument("-I", "--Interface", required=True,
4723 choices=['eth0', 'eth1'],
4724 help="Name of the ethernet interface")
4725 parser_create_vlan.add_argument("-n", "--Identifier", required=True,
4726 help="VLAN Identifier")
4727 parser_create_vlan.set_defaults(func=addVLAN)
4728
4729 # delete VLAN
4730 parser_delete_vlan = nw_sub.add_parser("deleteVLAN", help="disables VLAN "
4731 "on given interface with given "
4732 "VLAN Identifier")
4733 parser_delete_vlan.add_argument("-I", "--Interface", required=True,
4734 help="Name of the ethernet interface(it can"
4735 "be obtained by the "
4736 "command:network view-config)"
4737 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
4738 parser_delete_vlan.set_defaults(func=deleteVLAN)
4739
4740 # viewDHCPConfig
4741 parser_viewDHCPConfig = nw_sub.add_parser("viewDHCPConfig",
4742 help="Shows DHCP configured "
4743 "Properties")
4744 parser_viewDHCPConfig.set_defaults(func=viewDHCPConfig)
4745
4746 # configureDHCP
4747 parser_configDHCP = nw_sub.add_parser("configureDHCP",
4748 help="Configures/updates DHCP "
4749 "Properties")
4750 parser_configDHCP.add_argument("-d", "--DNSEnabled", type=str2bool,
4751 required=True, help="Sets DNSEnabled property")
4752 parser_configDHCP.add_argument("-n", "--HostNameEnabled", type=str2bool,
4753 required=True,
4754 help="Sets HostNameEnabled property")
4755 parser_configDHCP.add_argument("-t", "--NTPEnabled", type=str2bool,
4756 required=True,
4757 help="Sets NTPEnabled property")
4758 parser_configDHCP.add_argument("-s", "--SendHostNameEnabled", type=str2bool,
4759 required=True,
4760 help="Sets SendHostNameEnabled property")
4761 parser_configDHCP.set_defaults(func=configureDHCP)
4762
4763 # network factory reset
4764 parser_nw_reset = nw_sub.add_parser("nwReset",
4765 help="Resets networks setting to "
4766 "factory defaults. "
4767 "note:Reset settings will be applied "
4768 "after BMC reboot")
4769 parser_nw_reset.set_defaults(func=nwReset)
4770
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004771 return parser
4772
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004773def main(argv=None):
Justin Thalere412dc22018-01-12 16:28:24 -06004774 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004775 main function for running the command line utility as a sub application
4776 """
4777 global toolVersion
Matthew Barth0939e822019-09-27 15:47:50 -05004778 toolVersion = "1.17"
Sunitha Harishc99faba2019-07-19 06:55:22 -05004779 global isRedfishSupport
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004780
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004781 parser = createCommandParser()
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004782 args = parser.parse_args(argv)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004783
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004784 totTimeStart = int(round(time.time()*1000))
4785
4786 if(sys.version_info < (3,0)):
4787 urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
4788 if sys.version_info >= (3,0):
4789 requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)
Justin Thalere412dc22018-01-12 16:28:24 -06004790 if (args.version):
Justin Thaler22b1bb52018-03-15 13:31:32 -05004791 print("Version: "+ toolVersion)
Justin Thalere412dc22018-01-12 16:28:24 -06004792 sys.exit(0)
4793 if (hasattr(args, 'fileloc') and args.fileloc is not None and 'print' in args.command):
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004794 mysess = None
Justin Thalere412dc22018-01-12 16:28:24 -06004795 print(selPrint('N/A', args, mysess))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004796 else:
Justin Thalere412dc22018-01-12 16:28:24 -06004797 if(hasattr(args, 'host') and hasattr(args,'user')):
4798 if (args.askpw):
4799 pw = getpass.getpass()
4800 elif(args.PW is not None):
4801 pw = args.PW
Joseph Reynoldsa2d54c52019-06-11 22:02:57 -05004802 elif(args.PWenvvar):
4803 pw = os.environ['OPENBMCTOOL_PASSWORD']
Justin Thalere412dc22018-01-12 16:28:24 -06004804 else:
4805 print("You must specify a password")
4806 sys.exit()
4807 logintimeStart = int(round(time.time()*1000))
4808 mysess = login(args.host, args.user, pw, args.json)
Sunitha Harish336cda22019-07-23 02:02:52 -05004809 if(mysess == None):
4810 print("Login Failed!")
4811 sys.exit()
Justin Thalera9415b42018-05-25 19:40:13 -05004812 if(sys.version_info < (3,0)):
4813 if isinstance(mysess, basestring):
4814 print(mysess)
4815 sys.exit(1)
4816 elif sys.version_info >= (3,0):
4817 if isinstance(mysess, str):
4818 print(mysess)
4819 sys.exit(1)
Justin Thalere412dc22018-01-12 16:28:24 -06004820 logintimeStop = int(round(time.time()*1000))
Sunitha Harishc99faba2019-07-19 06:55:22 -05004821 isRedfishSupport = redfishSupportPresent(args.host,mysess)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004822 commandTimeStart = int(round(time.time()*1000))
Justin Thalere412dc22018-01-12 16:28:24 -06004823 output = args.func(args.host, args, mysess)
4824 commandTimeStop = int(round(time.time()*1000))
Justin Thaler761484a2019-03-26 19:20:23 -05004825 if isinstance(output, dict):
4826 print(json.dumps(output, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False))
4827 else:
4828 print(output)
Justin Thalere412dc22018-01-12 16:28:24 -06004829 if (mysess is not None):
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004830 logout(args.host, args.user, pw, mysess, args.json)
4831 if(args.procTime):
Justin Thalere412dc22018-01-12 16:28:24 -06004832 print("Total time: " + str(int(round(time.time()*1000))- totTimeStart))
4833 print("loginTime: " + str(logintimeStop - logintimeStart))
4834 print("command Time: " + str(commandTimeStop - commandTimeStart))
4835 else:
Joseph Reynoldsa2d54c52019-06-11 22:02:57 -05004836 print("usage:\n"
4837 " OPENBMCTOOL_PASSWORD=secret # if using -E\n"
4838 " openbmctool.py [-h] -H HOST -U USER {-A | -P PW | -E} [-j]\n" +
Justin Thalere412dc22018-01-12 16:28:24 -06004839 "\t[-t POLICYTABLELOC] [-V]\n" +
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05004840 "\t{fru,sensors,sel,chassis,collect_service_data, \
4841 health_check,dump,bmc,mc,gardclear,firmware,logging}\n" +
Justin Thalere412dc22018-01-12 16:28:24 -06004842 "\t...\n" +
4843 "openbmctool.py: error: the following arguments are required: -H/--host, -U/--user")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004844 sys.exit()
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004845
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004846if __name__ == '__main__':
Justin Thalere412dc22018-01-12 16:28:24 -06004847 """
4848 main function when called from the command line
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004849
4850 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004851 import sys
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004852
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004853 isTTY = sys.stdout.isatty()
4854 assert sys.version_info >= (2,7)
4855 main()