blob: 4541404eddcc8eea8e04b75b1b4c520cd9a8a77c [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:
Alvin Wang28bd09d2019-10-28 13:23:58 +08001425 dumpNum = dump.strip().split('/')[-1]
1426 if dumpNum.isdigit():
1427 dumpNums.append(int(dumpNum))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001428 d['dumpNum'] = dumpNums
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001429
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001430 return bmcDumpDelete(host, args, session)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001431
Justin Thalere412dc22018-01-12 16:28:24 -06001432
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001433def bmcDumpCreate(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001434 """
1435 Creates a bmc dump file
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001436
Justin Thalere412dc22018-01-12 16:28:24 -06001437 @param host: string, the hostname or IP address of the bmc
1438 @param args: contains additional arguments used by the collectServiceData sub command
1439 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001440 @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 -06001441 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001442 url = 'https://'+host+'/xyz/openbmc_project/dump/action/CreateDump'
1443 try:
Justin Thaler27197622019-01-23 14:42:11 -06001444 r = session.post(url, headers=jsonHeader, json = {"data": []}, verify=False, timeout=baseTimeout)
Matt Spinlereae05b02019-01-24 12:59:34 -06001445 if(r.status_code == 200 and not args.json):
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001446 return ('Dump successfully created')
Justin Thaler3a5771b2019-01-23 14:31:52 -06001447 elif(args.json):
1448 return r.json()
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001449 else:
1450 return ('Failed to create dump')
1451 except(requests.exceptions.Timeout):
1452 return connectionErrHandler(args.json, "Timeout", None)
1453 except(requests.exceptions.ConnectionError) as err:
1454 return connectionErrHandler(args.json, "ConnectionError", err)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001455
1456
Justin Thaler666cf342019-01-23 14:44:27 -06001457def csdDumpInitiate(host, args, session):
1458 """
1459 Starts the process of getting the current list of dumps then initiates the creation of one.
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001460
Justin Thaler666cf342019-01-23 14:44:27 -06001461 @param host: string, the hostname or IP address of the bmc
1462 @param args: contains additional arguments used by the collectServiceData sub command
1463 @param session: the active session to use
1464 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1465 """
1466 errorInfo = ""
1467 dumpcount = 0
1468 try:
1469 d = vars(args)
1470 d['json'] = True
1471 except Exception as e:
1472 errorInfo += "Failed to set the json flag to True \n Exception: {eInfo}\n".format(eInfo=e)
1473
1474 try:
1475 for i in range(3):
1476 dumpInfo = bmcDumpList(host, args, session)
1477 if 'data' in dumpInfo:
1478 dumpcount = len(dumpInfo['data'])
1479 break
1480 else:
1481 errorInfo+= "Dump List Message returned: " + json.dumps(dumpInfo,indent=0, separators=(',', ':')).replace('\n','') +"\n"
1482 except Exception as e:
1483 errorInfo+= "Failed to collect the list of dumps.\nException: {eInfo}\n".format(eInfo=e)
1484
1485 #Create a user initiated dump
1486 try:
1487 for i in range(3):
1488 dumpcreated = bmcDumpCreate(host, args, session)
1489 if 'message' in dumpcreated:
1490 if 'ok' in dumpcreated['message'].lower():
1491 break
1492 else:
1493 errorInfo+= "Dump create message returned: " + json.dumps(dumpInfo,indent=0, separators=(',', ':')).replace('\n','') +"\n"
1494 else:
1495 errorInfo+= "Dump create message returned: " + json.dumps(dumpInfo,indent=0, separators=(',', ':')).replace('\n','') +"\n"
1496 except Exception as e:
1497 errorInfo+= "Dump create exception encountered: {eInfo}\n".format(eInfo=e)
1498
1499 output = {}
1500 output['errors'] = errorInfo
1501 output['dumpcount'] = dumpcount
1502 return output
1503
1504def csdInventory(host, args,session, fileDir):
1505 """
1506 Collects the BMC inventory, retrying if necessary
1507
1508 @param host: string, the hostname or IP address of the bmc
1509 @param args: contains additional arguments used by the collectServiceData sub command
1510 @param session: the active session to use
1511 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1512 @param fileDir: string representation of the path to use for putting files created
1513 """
1514 errorInfo = "===========Inventory =============\n"
1515 output={}
1516 inventoryCollected = False
1517 try:
1518 for i in range(3):
1519 frulist = fruPrint(host, args, session)
1520 if 'Hardware' in frulist:
1521 inventoryCollected = True
1522 break
1523 else:
1524 errorInfo += json.dumps(frulist, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n'
1525 except Exception as e:
1526 errorInfo += "Inventory collection exception: {eInfo}\n".format(eInfo=e)
1527 if inventoryCollected:
1528 try:
1529 with open(fileDir +os.sep+'inventory.txt', 'w') as f:
1530 f.write(json.dumps(frulist, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n')
1531 print("Inventory collected and stored in " + fileDir + os.sep + "inventory.txt")
1532 output['fileLoc'] = fileDir+os.sep+'inventory.txt'
1533 except Exception as e:
1534 print("Failed to write inventory to file.")
1535 errorInfo += "Error writing inventory to the file. Exception: {eInfo}\n".format(eInfo=e)
1536
1537 output['errors'] = errorInfo
1538
1539 return output
1540
1541def csdSensors(host, args,session, fileDir):
1542 """
1543 Collects the BMC sensor readings, retrying if necessary
1544
1545 @param host: string, the hostname or IP address of the bmc
1546 @param args: contains additional arguments used by the collectServiceData sub command
1547 @param session: the active session to use
1548 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1549 @param fileDir: string representation of the path to use for putting files created
1550 """
1551 errorInfo = "===========Sensors =============\n"
1552 sensorsCollected = False
1553 output={}
1554 try:
1555 d = vars(args)
1556 d['json'] = False
1557 except Exception as e:
1558 errorInfo += "Failed to set the json flag to False \n Exception: {eInfo}\n".format(eInfo=e)
1559
1560 try:
1561 for i in range(3):
1562 sensorReadings = sensor(host, args, session)
1563 if 'OCC0' in sensorReadings:
1564 sensorsCollected = True
1565 break
1566 else:
1567 errorInfo += sensorReadings
1568 except Exception as e:
1569 errorInfo += "Sensor reading collection exception: {eInfo}\n".format(eInfo=e)
1570 if sensorsCollected:
1571 try:
1572 with open(fileDir +os.sep+'sensorReadings.txt', 'w') as f:
1573 f.write(sensorReadings)
1574 print("Sensor readings collected and stored in " + fileDir + os.sep+ "sensorReadings.txt")
1575 output['fileLoc'] = fileDir+os.sep+'sensorReadings.txt'
1576 except Exception as e:
1577 print("Failed to write sensor readings to file system.")
1578 errorInfo += "Error writing sensor readings to the file. Exception: {eInfo}\n".format(eInfo=e)
1579
1580 output['errors'] = errorInfo
1581 return output
1582
1583def csdLEDs(host,args, session, fileDir):
1584 """
1585 Collects the BMC LED status, retrying if necessary
1586
1587 @param host: string, the hostname or IP address of the bmc
1588 @param args: contains additional arguments used by the collectServiceData sub command
1589 @param session: the active session to use
1590 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1591 @param fileDir: string representation of the path to use for putting files created
1592 """
1593 errorInfo = "===========LEDs =============\n"
1594 ledsCollected = False
1595 output={}
1596 try:
1597 d = vars(args)
1598 d['json'] = True
1599 except Exception as e:
1600 errorInfo += "Failed to set the json flag to False \n Exception: {eInfo}\n".format(eInfo=e)
1601 try:
1602 url="https://"+host+"/xyz/openbmc_project/led/enumerate"
1603 httpHeader = {'Content-Type':'application/json'}
1604 for i in range(3):
1605 try:
1606 ledRes = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
1607 if ledRes.status_code == 200:
1608 ledsCollected = True
1609 leds = ledRes.json()['data']
1610 break
1611 else:
1612 errorInfo += ledRes.text
1613 except(requests.exceptions.Timeout):
1614 errorInfo+=json.dumps( connectionErrHandler(args.json, "Timeout", None), sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n'
1615 except(requests.exceptions.ConnectionError) as err:
1616 errorInfo += json.dumps(connectionErrHandler(args.json, "ConnectionError", err), sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n'
1617 except Exception as e:
1618 errorInfo += "LED status collection exception: {eInfo}\n".format(eInfo=e)
1619
1620 if ledsCollected:
1621 try:
1622 with open(fileDir +os.sep+'ledStatus.txt', 'w') as f:
1623 f.write(json.dumps(leds, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n')
1624 print("LED status collected and stored in " + fileDir + os.sep+ "ledStatus.txt")
1625 output['fileLoc'] = fileDir+os.sep+'ledStatus.txt'
1626 except Exception as e:
1627 print("Failed to write LED status to file system.")
1628 errorInfo += "Error writing LED status to the file. Exception: {eInfo}\n".format(eInfo=e)
1629
1630 output['errors'] = errorInfo
1631 return output
1632
1633def csdSelShortList(host, args, session, fileDir):
1634 """
1635 Collects the BMC log entries, retrying if necessary
1636
1637 @param host: string, the hostname or IP address of the bmc
1638 @param args: contains additional arguments used by the collectServiceData sub command
1639 @param session: the active session to use
1640 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1641 @param fileDir: string representation of the path to use for putting files created
1642 """
1643 errorInfo = "===========SEL Short List =============\n"
1644 selsCollected = False
1645 output={}
1646 try:
1647 d = vars(args)
1648 d['json'] = False
1649 except Exception as e:
1650 errorInfo += "Failed to set the json flag to False \n Exception: {eInfo}\n".format(eInfo=e)
1651
1652 try:
1653 for i in range(3):
1654 sels = selPrint(host,args,session)
1655 if '----Active Alerts----' in sels or 'No log entries found' in sels or '----Historical Alerts----' in sels:
1656 selsCollected = True
1657 break
1658 else:
1659 errorInfo += sels + '\n'
1660 except Exception as e:
1661 errorInfo += "SEL short list collection exception: {eInfo}\n".format(eInfo=e)
1662
1663 if selsCollected:
1664 try:
1665 with open(fileDir +os.sep+'SELshortlist.txt', 'w') as f:
1666 f.write(sels)
1667 print("SEL short list collected and stored in " + fileDir + os.sep+ "SELshortlist.txt")
1668 output['fileLoc'] = fileDir+os.sep+'SELshortlist.txt'
1669 except Exception as e:
1670 print("Failed to write SEL short list to file system.")
1671 errorInfo += "Error writing SEL short list to the file. Exception: {eInfo}\n".format(eInfo=e)
1672
1673 output['errors'] = errorInfo
1674 return output
1675
1676def csdParsedSels(host, args, session, fileDir):
1677 """
1678 Collects the BMC log entries, retrying if necessary
1679
1680 @param host: string, the hostname or IP address of the bmc
1681 @param args: contains additional arguments used by the collectServiceData sub command
1682 @param session: the active session to use
1683 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1684 @param fileDir: string representation of the path to use for putting files created
1685 """
1686 errorInfo = "===========SEL Parsed List =============\n"
1687 selsCollected = False
1688 output={}
1689 try:
1690 d = vars(args)
1691 d['json'] = True
1692 d['fullEsel'] = True
1693 except Exception as e:
1694 errorInfo += "Failed to set the json flag to True \n Exception: {eInfo}\n".format(eInfo=e)
1695
1696 try:
1697 for i in range(3):
1698 parsedfullsels = json.loads(selPrint(host,args,session))
1699 if 'numAlerts' in parsedfullsels:
1700 selsCollected = True
1701 break
1702 else:
1703 errorInfo += parsedfullsels + '\n'
1704 except Exception as e:
1705 errorInfo += "Parsed full SELs collection exception: {eInfo}\n".format(eInfo=e)
1706
1707 if selsCollected:
1708 try:
1709 sortedSELs = sortSELs(parsedfullsels)
1710 with open(fileDir +os.sep+'parsedSELs.txt', 'w') as f:
1711 for log in sortedSELs[0]:
1712 esel = ""
1713 parsedfullsels[sortedSELs[1][str(log)]]['timestamp'] = datetime.datetime.fromtimestamp(int(parsedfullsels[sortedSELs[1][str(log)]]['timestamp']/1000)).strftime("%Y-%m-%d %H:%M:%S")
1714 if ('raweSEL' in parsedfullsels[sortedSELs[1][str(log)]] and args.devdebug):
1715 esel = parsedfullsels[sortedSELs[1][str(log)]]['raweSEL']
1716 del parsedfullsels[sortedSELs[1][str(log)]]['raweSEL']
1717 f.write(json.dumps(parsedfullsels[sortedSELs[1][str(log)]],sort_keys=True, indent=4, separators=(',', ': ')))
1718 if(args.devdebug and esel != ""):
1719 f.write(parseESEL(args, esel))
1720 print("Parsed SELs collected and stored in " + fileDir + os.sep+ "parsedSELs.txt")
1721 output['fileLoc'] = fileDir+os.sep+'parsedSELs.txt'
1722 except Exception as e:
1723 print("Failed to write fully parsed SELs to file system.")
1724 errorInfo += "Error writing fully parsed SELs to the file. Exception: {eInfo}\n".format(eInfo=e)
1725
1726 output['errors'] = errorInfo
1727 return output
1728
1729def csdFullEnumeration(host, args, session, fileDir):
1730 """
1731 Collects a full enumeration of /xyz/openbmc_project/, retrying if necessary
1732
1733 @param host: string, the hostname or IP address of the bmc
1734 @param args: contains additional arguments used by the collectServiceData sub command
1735 @param session: the active session to use
1736 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1737 @param fileDir: string representation of the path to use for putting files created
1738 """
1739 errorInfo = "===========BMC Full Enumeration =============\n"
1740 bmcFullCollected = False
1741 output={}
1742 try:
1743 d = vars(args)
1744 d['json'] = True
1745 except Exception as e:
1746 errorInfo += "Failed to set the json flag to False \n Exception: {eInfo}\n".format(eInfo=e)
1747 try:
1748 print("Attempting to get a full BMC enumeration")
1749 url="https://"+host+"/xyz/openbmc_project/enumerate"
1750 httpHeader = {'Content-Type':'application/json'}
1751 for i in range(3):
1752 try:
1753 bmcRes = session.get(url, headers=jsonHeader, verify=False, timeout=180)
1754 if bmcRes.status_code == 200:
1755 bmcFullCollected = True
1756 fullEnumeration = bmcRes.json()
1757 break
1758 else:
1759 errorInfo += bmcRes.text
1760 except(requests.exceptions.Timeout):
1761 errorInfo+=json.dumps( connectionErrHandler(args.json, "Timeout", None), sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n'
1762 except(requests.exceptions.ConnectionError) as err:
1763 errorInfo += json.dumps(connectionErrHandler(args.json, "ConnectionError", err), sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n'
1764 except Exception as e:
1765 errorInfo += "RAW BMC data collection exception: {eInfo}\n".format(eInfo=e)
1766
1767 if bmcFullCollected:
1768 try:
1769 with open(fileDir +os.sep+'bmcFullRaw.txt', 'w') as f:
1770 f.write(json.dumps(fullEnumeration, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n')
1771 print("RAW BMC data collected and saved into " + fileDir + os.sep+ "bmcFullRaw.txt")
1772 output['fileLoc'] = fileDir+os.sep+'bmcFullRaw.txt'
1773 except Exception as e:
1774 print("Failed to write RAW BMC data to file system.")
1775 errorInfo += "Error writing RAW BMC data collection to the file. Exception: {eInfo}\n".format(eInfo=e)
1776
1777 output['errors'] = errorInfo
1778 return output
1779
1780def csdCollectAllDumps(host, args, session, fileDir):
1781 """
1782 Collects all of the bmc dump files and stores them in fileDir
1783
1784 @param host: string, the hostname or IP address of the bmc
1785 @param args: contains additional arguments used by the collectServiceData sub command
1786 @param session: the active session to use
1787 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1788 @param fileDir: string representation of the path to use for putting files created
1789 """
1790
1791 errorInfo = "===========BMC Dump Collection =============\n"
1792 dumpListCollected = False
1793 output={}
1794 dumpList = {}
1795 try:
1796 d = vars(args)
1797 d['json'] = True
1798 d['dumpSaveLoc'] = fileDir
1799 except Exception as e:
1800 errorInfo += "Failed to set the json flag to True, or failed to set the dumpSave Location \n Exception: {eInfo}\n".format(eInfo=e)
1801
1802 print('Collecting bmc dump files')
1803
1804 try:
1805 for i in range(3):
1806 dumpResp = bmcDumpList(host, args, session)
1807 if 'message' in dumpResp:
1808 if 'ok' in dumpResp['message'].lower():
1809 dumpList = dumpResp['data']
1810 dumpListCollected = True
1811 break
1812 else:
1813 errorInfo += "Status was not OK when retrieving the list of dumps available. \n Response: \n{resp}\n".format(resp=dumpResp)
1814 else:
1815 errorInfo += "Invalid response received from the BMC while retrieving the list of dumps available.\n {resp}\n".format(resp=dumpResp)
1816 except Exception as e:
1817 errorInfo += "BMC dump list exception: {eInfo}\n".format(eInfo=e)
1818
1819 if dumpListCollected:
1820 output['fileList'] = []
1821 for dump in dumpList:
1822 try:
1823 if '/xyz/openbmc_project/dump/internal/manager' not in dump:
1824 d['dumpNum'] = int(dump.strip().split('/')[-1])
1825 print('retrieving dump file ' + str(d['dumpNum']))
1826 filename = bmcDumpRetrieve(host, args, session).split('Saved as ')[-1]
1827 output['fileList'].append(filename)
1828 except Exception as e:
1829 print("Unable to collect dump: {dumpInfo}".format(dumpInfo=dump))
1830 errorInfo += "Exception collecting a bmc dump {dumpInfo}\n {eInfo}\n".format(dumpInfo=dump, eInfo=e)
1831 output['errors'] = errorInfo
1832 return output
Justin Thalere412dc22018-01-12 16:28:24 -06001833
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001834def collectServiceData(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001835 """
1836 Collects all data needed for service from the BMC
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001837
Justin Thalere412dc22018-01-12 16:28:24 -06001838 @param host: string, the hostname or IP address of the bmc
1839 @param args: contains additional arguments used by the collectServiceData sub command
1840 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001841 @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 -06001842 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001843
Justin Thaler22b1bb52018-03-15 13:31:32 -05001844 global toolVersion
Justin Thaler666cf342019-01-23 14:44:27 -06001845 filelist = []
1846 errorInfo = ""
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001847
Justin Thaler666cf342019-01-23 14:44:27 -06001848 #get current number of bmc dumps and create a new bmc dump
1849 dumpInitdata = csdDumpInitiate(host, args, session)
1850 dumpcount = dumpInitdata['dumpcount']
1851 errorInfo += dumpInitdata['errors']
1852 #create the directory to put files
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001853 try:
1854 args.silent = True
Justin Thalercf1deae2018-05-25 19:35:21 -05001855 myDir = tempfile.gettempdir()+os.sep + host + "--" + datetime.datetime.now().strftime("%Y-%m-%d_%H.%M.%S")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001856 os.makedirs(myDir)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001857
Justin Thaler666cf342019-01-23 14:44:27 -06001858 except Exception as e:
1859 print('Unable to create the temporary directory for data collection. Ensure sufficient privileges to create temporary directory. Aborting.')
1860 return("Python exception: {eInfo}".format(eInfo = e))
1861
1862 #Collect Inventory
1863 inventoryData = csdInventory(host, args, session, myDir)
1864 if 'fileLoc' in inventoryData:
1865 filelist.append(inventoryData['fileLoc'])
1866 errorInfo += inventoryData['errors']
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001867 #Read all the sensor and OCC status
Justin Thaler666cf342019-01-23 14:44:27 -06001868 sensorData = csdSensors(host,args,session,myDir)
1869 if 'fileLoc' in sensorData:
1870 filelist.append(sensorData['fileLoc'])
1871 errorInfo += sensorData['errors']
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001872 #Collect all of the LEDs status
Justin Thaler666cf342019-01-23 14:44:27 -06001873 ledStatus = csdLEDs(host, args, session, myDir)
1874 if 'fileLoc' in ledStatus:
1875 filelist.append(ledStatus['fileLoc'])
1876 errorInfo += ledStatus['errors']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001877
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001878 #Collect the bmc logs
Justin Thaler666cf342019-01-23 14:44:27 -06001879 selShort = csdSelShortList(host, args, session, myDir)
1880 if 'fileLoc' in selShort:
1881 filelist.append(selShort['fileLoc'])
1882 errorInfo += selShort['errors']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001883
Justin Thaler666cf342019-01-23 14:44:27 -06001884 parsedSELs = csdParsedSels(host, args, session, myDir)
1885 if 'fileLoc' in parsedSELs:
1886 filelist.append(parsedSELs['fileLoc'])
1887 errorInfo += parsedSELs['errors']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001888
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001889 #collect RAW bmc enumeration
Justin Thaler666cf342019-01-23 14:44:27 -06001890 bmcRaw = csdFullEnumeration(host, args, session, myDir)
1891 if 'fileLoc' in bmcRaw:
1892 filelist.append(bmcRaw['fileLoc'])
1893 errorInfo += bmcRaw['errors']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001894
Justin Thaler666cf342019-01-23 14:44:27 -06001895 #wait for new dump to finish being created
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001896 waitingForNewDump = True
1897 count = 0;
Justin Thaler666cf342019-01-23 14:44:27 -06001898 print("Waiting for new BMC dump to finish being created.")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001899 while(waitingForNewDump):
Justin Thaler666cf342019-01-23 14:44:27 -06001900 dumpList = bmcDumpList(host, args, session)['data']
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001901 if len(dumpList) > dumpcount:
1902 waitingForNewDump = False
1903 break;
1904 elif(count>30):
1905 print("Timed out waiting for bmc to make a new dump file. Dump space may be full.")
1906 break;
1907 else:
1908 time.sleep(2)
1909 count += 1
Justin Thaler666cf342019-01-23 14:44:27 -06001910
1911 #collect all of the dump files
1912 getBMCDumps = csdCollectAllDumps(host, args, session, myDir)
1913 if 'fileList' in getBMCDumps:
1914 filelist+= getBMCDumps['fileList']
1915 errorInfo += getBMCDumps['errors']
1916
1917 #write the runtime errors to a file
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001918 try:
Justin Thaler666cf342019-01-23 14:44:27 -06001919 with open(myDir +os.sep+'openbmctoolRuntimeErrors.txt', 'w') as f:
1920 f.write(errorInfo)
1921 print("OpenBMC tool runtime errors collected and stored in " + myDir + os.sep+ "openbmctoolRuntimeErrors.txt")
1922 filelist.append(myDir+os.sep+'openbmctoolRuntimeErrors.txt')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001923 except Exception as e:
Justin Thaler666cf342019-01-23 14:44:27 -06001924 print("Failed to write OpenBMC tool runtime errors to file system.")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001925
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001926 #create the zip file
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001927 try:
Justin Thalercf1deae2018-05-25 19:35:21 -05001928 filename = myDir.split(tempfile.gettempdir()+os.sep)[-1] + "_" + toolVersion + '_openbmc.zip'
Justin Thaler666cf342019-01-23 14:44:27 -06001929 zf = zipfile.ZipFile(myDir+os.sep + filename, 'w')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001930 for myfile in filelist:
1931 zf.write(myfile, os.path.basename(myfile))
1932 zf.close()
Justin Thaler666cf342019-01-23 14:44:27 -06001933 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 -06001934 except Exception as e:
1935 print("Failed to create zip file with collected information")
Justin Thaler666cf342019-01-23 14:44:27 -06001936 return "data collection finished"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001937
Justin Thalere412dc22018-01-12 16:28:24 -06001938
1939def healthCheck(host, args, session):
1940 """
1941 runs a health check on the platform
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001942
Justin Thalere412dc22018-01-12 16:28:24 -06001943 @param host: string, the hostname or IP address of the bmc
1944 @param args: contains additional arguments used by the bmc sub command
1945 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001946 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1947 """
Justin Thalere412dc22018-01-12 16:28:24 -06001948 #check fru status and get as json to easily work through
1949 d = vars(args)
1950 useJson = d['json']
1951 d['json'] = True
1952 d['verbose']= False
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001953
Justin Thalere412dc22018-01-12 16:28:24 -06001954 frus = json.loads(fruStatus(host, args, session))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001955
Justin Thalere412dc22018-01-12 16:28:24 -06001956 hwStatus= "OK"
1957 performanceStatus = "OK"
1958 for key in frus:
1959 if frus[key]["Functional"] == "No" and frus[key]["Present"] == "Yes":
1960 hwStatus= "Degraded"
Justin Thalerfb9c81c2018-07-16 11:14:37 -05001961 if("power_supply" in key or "powersupply" in key):
1962 gpuCount =0
1963 for comp in frus:
Justin Thalere412dc22018-01-12 16:28:24 -06001964 if "gv100card" in comp:
1965 gpuCount +=1
1966 if gpuCount > 4:
1967 hwStatus = "Critical"
1968 performanceStatus="Degraded"
1969 break;
1970 elif("fan" in key):
1971 hwStatus = "Degraded"
1972 else:
1973 performanceStatus = "Degraded"
1974 if useJson:
1975 output = {"Hardware Status": hwStatus, "Performance": performanceStatus}
1976 output = json.dumps(output, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False)
1977 else:
1978 output = ("Hardware Status: " + hwStatus +
1979 "\nPerformance: " +performanceStatus )
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001980
1981
Justin Thalere412dc22018-01-12 16:28:24 -06001982 #SW407886: Clear the duplicate entries
1983 #collect the dups
1984 d['devdebug'] = False
1985 sels = json.loads(selPrint(host, args, session))
1986 logNums2Clr = []
1987 oldestLogNum={"logNum": "bogus" ,"key" : ""}
1988 count = 0
1989 if sels['numAlerts'] > 0:
1990 for key in sels:
1991 if "numAlerts" in key:
1992 continue
1993 try:
1994 if "slave@00:00/00:00:00:06/sbefifo1-dev0/occ1-dev0" in sels[key]['Message']:
1995 count += 1
1996 if count > 1:
1997 #preserve first occurrence
1998 if sels[key]['timestamp'] < sels[oldestLogNum['key']]['timestamp']:
1999 oldestLogNum['key']=key
2000 oldestLogNum['logNum'] = sels[key]['logNum']
2001 else:
2002 oldestLogNum['key']=key
2003 oldestLogNum['logNum'] = sels[key]['logNum']
2004 logNums2Clr.append(sels[key]['logNum'])
2005 except KeyError:
2006 continue
2007 if(count >0):
2008 logNums2Clr.remove(oldestLogNum['logNum'])
2009 #delete the dups
2010 if count >1:
Justin Thalere412dc22018-01-12 16:28:24 -06002011 data = "{\"data\": [] }"
2012 for logNum in logNums2Clr:
2013 url = "https://"+ host+ "/xyz/openbmc_project/logging/entry/"+logNum+"/action/Delete"
2014 try:
Justin Thaler27197622019-01-23 14:42:11 -06002015 session.post(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002016 except(requests.exceptions.Timeout):
2017 deleteFailed = True
2018 except(requests.exceptions.ConnectionError) as err:
2019 deleteFailed = True
2020 #End of defect resolve code
2021 d['json'] = useJson
2022 return output
2023
2024
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002025
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002026def bmc(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06002027 """
2028 handles various bmc level commands, currently bmc rebooting
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002029
Justin Thalere412dc22018-01-12 16:28:24 -06002030 @param host: string, the hostname or IP address of the bmc
2031 @param args: contains additional arguments used by the bmc sub command
2032 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002033 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
2034 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002035 if(args.type is not None):
2036 return bmcReset(host, args, session)
Justin Thalere412dc22018-01-12 16:28:24 -06002037 if(args.info):
2038 return "Not implemented at this time"
2039
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002040
Justin Thalere412dc22018-01-12 16:28:24 -06002041
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002042def bmcReset(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06002043 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002044 controls resetting the bmc. warm reset reboots the bmc, cold reset removes the configuration and reboots.
2045
Justin Thalere412dc22018-01-12 16:28:24 -06002046 @param host: string, the hostname or IP address of the bmc
2047 @param args: contains additional arguments used by the bmcReset sub command
2048 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002049 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
2050 """
Justin Thaler22b1bb52018-03-15 13:31:32 -05002051 if checkFWactivation(host, args, session):
2052 return ("BMC reset control disabled during firmware activation")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002053 if(args.type == "warm"):
2054 print("\nAttempting to reboot the BMC...:")
2055 url="https://"+host+"/xyz/openbmc_project/state/bmc0/attr/RequestedBMCTransition"
Justin Thalere412dc22018-01-12 16:28:24 -06002056 data = '{"data":"xyz.openbmc_project.State.BMC.Transition.Reboot"}'
Justin Thaler27197622019-01-23 14:42:11 -06002057 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002058 return res.text
2059 elif(args.type =="cold"):
Justin Thalere412dc22018-01-12 16:28:24 -06002060 print("\nAttempting to reboot the BMC...:")
2061 url="https://"+host+"/xyz/openbmc_project/state/bmc0/attr/RequestedBMCTransition"
Justin Thalere412dc22018-01-12 16:28:24 -06002062 data = '{"data":"xyz.openbmc_project.State.BMC.Transition.Reboot"}'
Justin Thaler27197622019-01-23 14:42:11 -06002063 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002064 return res.text
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002065 else:
2066 return "invalid command"
Justin Thalere412dc22018-01-12 16:28:24 -06002067
2068def gardClear(host, args, session):
2069 """
2070 clears the gard records from the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002071
Justin Thalere412dc22018-01-12 16:28:24 -06002072 @param host: string, the hostname or IP address of the bmc
2073 @param args: contains additional arguments used by the gardClear sub command
2074 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002075 """
Justin Thalere412dc22018-01-12 16:28:24 -06002076 url="https://"+host+"/org/open_power/control/gard/action/Reset"
Justin Thalere412dc22018-01-12 16:28:24 -06002077 data = '{"data":[]}'
2078 try:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002079
Justin Thaler27197622019-01-23 14:42:11 -06002080 res = session.post(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002081 if res.status_code == 404:
2082 return "Command not supported by this firmware version"
2083 else:
2084 return res.text
2085 except(requests.exceptions.Timeout):
2086 return connectionErrHandler(args.json, "Timeout", None)
2087 except(requests.exceptions.ConnectionError) as err:
2088 return connectionErrHandler(args.json, "ConnectionError", err)
2089
2090def activateFWImage(host, args, session):
2091 """
2092 activates a firmware image on the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002093
Justin Thalere412dc22018-01-12 16:28:24 -06002094 @param host: string, the hostname or IP address of the bmc
2095 @param args: contains additional arguments used by the fwflash sub command
2096 @param session: the active session to use
2097 @param fwID: the unique ID of the fw image to activate
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002098 """
Justin Thalere412dc22018-01-12 16:28:24 -06002099 fwID = args.imageID
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002100
Justin Thalere412dc22018-01-12 16:28:24 -06002101 #determine the existing versions
Justin Thalere412dc22018-01-12 16:28:24 -06002102 url="https://"+host+"/xyz/openbmc_project/software/enumerate"
2103 try:
Justin Thaler27197622019-01-23 14:42:11 -06002104 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002105 except(requests.exceptions.Timeout):
2106 return connectionErrHandler(args.json, "Timeout", None)
2107 except(requests.exceptions.ConnectionError) as err:
2108 return connectionErrHandler(args.json, "ConnectionError", err)
2109 existingSoftware = json.loads(resp.text)['data']
2110 altVersionID = ''
2111 versionType = ''
2112 imageKey = '/xyz/openbmc_project/software/'+fwID
2113 if imageKey in existingSoftware:
2114 versionType = existingSoftware[imageKey]['Purpose']
2115 for key in existingSoftware:
2116 if imageKey == key:
2117 continue
2118 if 'Purpose' in existingSoftware[key]:
2119 if versionType == existingSoftware[key]['Purpose']:
2120 altVersionID = key.split('/')[-1]
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002121
2122
2123
2124
Justin Thalere412dc22018-01-12 16:28:24 -06002125 url="https://"+host+"/xyz/openbmc_project/software/"+ fwID + "/attr/Priority"
2126 url1="https://"+host+"/xyz/openbmc_project/software/"+ altVersionID + "/attr/Priority"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002127 data = "{\"data\": 0}"
Justin Thalere412dc22018-01-12 16:28:24 -06002128 data1 = "{\"data\": 1 }"
2129 try:
Justin Thaler27197622019-01-23 14:42:11 -06002130 resp = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
2131 resp1 = session.put(url1, headers=jsonHeader, data=data1, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002132 except(requests.exceptions.Timeout):
2133 return connectionErrHandler(args.json, "Timeout", None)
2134 except(requests.exceptions.ConnectionError) as err:
2135 return connectionErrHandler(args.json, "ConnectionError", err)
2136 if(not args.json):
2137 if resp.status_code == 200 and resp1.status_code == 200:
Justin Thaler22b1bb52018-03-15 13:31:32 -05002138 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 -06002139 else:
2140 return "Firmware activation failed."
2141 else:
2142 return resp.text + resp1.text
Justin Thaler22b1bb52018-03-15 13:31:32 -05002143
2144def activateStatus(host, args, session):
2145 if checkFWactivation(host, args, session):
2146 return("Firmware is currently being activated. Do not reboot the BMC or start the Host OS")
2147 else:
2148 return("No firmware activations are pending")
2149
2150def extractFWimage(path, imageType):
2151 """
2152 extracts the bmc image and returns information about the package
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002153
Justin Thaler22b1bb52018-03-15 13:31:32 -05002154 @param path: the path and file name of the firmware image
2155 @param imageType: The type of image the user is trying to flash. Host or BMC
2156 @return: the image id associated with the package. returns an empty string on error.
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002157 """
Justin Thaler22b1bb52018-03-15 13:31:32 -05002158 f = tempfile.TemporaryFile()
2159 tmpDir = tempfile.gettempdir()
2160 newImageID = ""
2161 if os.path.exists(path):
2162 try:
2163 imageFile = tarfile.open(path,'r')
2164 contents = imageFile.getmembers()
2165 for tf in contents:
2166 if 'MANIFEST' in tf.name:
2167 imageFile.extract(tf.name, path=tmpDir)
2168 with open(tempfile.gettempdir() +os.sep+ tf.name, 'r') as imageInfo:
2169 for line in imageInfo:
2170 if 'purpose' in line:
2171 purpose = line.split('=')[1]
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002172 if imageType not in purpose.split('.')[-1]:
Justin Thaler22b1bb52018-03-15 13:31:32 -05002173 print('The specified image is not for ' + imageType)
2174 print('Please try again with the image for ' + imageType)
2175 return ""
2176 if 'version' == line.split('=')[0]:
2177 version = line.split('=')[1].strip().encode('utf-8')
2178 m = hashlib.sha512()
2179 m.update(version)
2180 newImageID = m.hexdigest()[:8]
2181 break
2182 try:
2183 os.remove(tempfile.gettempdir() +os.sep+ tf.name)
2184 except OSError:
2185 pass
2186 return newImageID
2187 except tarfile.ExtractError as e:
2188 print('Unable to extract information from the firmware file.')
2189 print('Ensure you have write access to the directory: ' + tmpDir)
2190 return newImageID
2191 except tarfile.TarError as e:
2192 print('This is not a valid firmware file.')
2193 return newImageID
2194 print("This is not a valid firmware file.")
2195 return newImageID
2196 else:
2197 print('The filename and path provided are not valid.')
2198 return newImageID
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002199
Justin Thaler22b1bb52018-03-15 13:31:32 -05002200def getAllFWImageIDs(fwInvDict):
2201 """
2202 gets a list of all the firmware image IDs
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002203
Justin Thaler22b1bb52018-03-15 13:31:32 -05002204 @param fwInvDict: the dictionary to search for FW image IDs
2205 @return: list containing string representation of the found image ids
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002206 """
Justin Thaler22b1bb52018-03-15 13:31:32 -05002207 idList = []
2208 for key in fwInvDict:
2209 if 'Version' in fwInvDict[key]:
2210 idList.append(key.split('/')[-1])
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002211 return idList
2212
Justin Thalere412dc22018-01-12 16:28:24 -06002213def fwFlash(host, args, session):
2214 """
2215 updates the bmc firmware and pnor firmware
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002216
Justin Thalere412dc22018-01-12 16:28:24 -06002217 @param host: string, the hostname or IP address of the bmc
2218 @param args: contains additional arguments used by the fwflash sub command
2219 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002220 """
Justin Thaler22b1bb52018-03-15 13:31:32 -05002221 d = vars(args)
Justin Thalere412dc22018-01-12 16:28:24 -06002222 if(args.type == 'bmc'):
2223 purp = 'BMC'
2224 else:
2225 purp = 'Host'
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002226
2227 #check power state of the machine. No concurrent FW updates allowed
Justin Thaler22b1bb52018-03-15 13:31:32 -05002228 d['powcmd'] = 'status'
2229 powerstate = chassisPower(host, args, session)
2230 if 'Chassis Power State: On' in powerstate:
2231 return("Aborting firmware update. Host is powered on. Please turn off the host and try again.")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002232
Justin Thaler22b1bb52018-03-15 13:31:32 -05002233 #determine the existing images on the bmc
Justin Thalere412dc22018-01-12 16:28:24 -06002234 url="https://"+host+"/xyz/openbmc_project/software/enumerate"
2235 try:
Justin Thaler27197622019-01-23 14:42:11 -06002236 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002237 except(requests.exceptions.Timeout):
2238 return connectionErrHandler(args.json, "Timeout", None)
2239 except(requests.exceptions.ConnectionError) as err:
2240 return connectionErrHandler(args.json, "ConnectionError", err)
2241 oldsoftware = json.loads(resp.text)['data']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002242
Justin Thaler22b1bb52018-03-15 13:31:32 -05002243 #Extract the tar and get information from the manifest file
2244 newversionID = extractFWimage(args.fileloc, purp)
2245 if newversionID == "":
2246 return "Unable to verify FW image."
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002247
2248
Justin Thaler22b1bb52018-03-15 13:31:32 -05002249 #check if the new image is already on the bmc
2250 if newversionID not in getAllFWImageIDs(oldsoftware):
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002251
Justin Thaler22b1bb52018-03-15 13:31:32 -05002252 #upload the file
2253 httpHeader = {'Content-Type':'application/octet-stream'}
Matt Spinler220c3c42019-01-04 15:09:29 -06002254 httpHeader.update(xAuthHeader)
Justin Thaler22b1bb52018-03-15 13:31:32 -05002255 url="https://"+host+"/upload/image"
2256 data=open(args.fileloc,'rb').read()
2257 print("Uploading file to BMC")
Justin Thalere412dc22018-01-12 16:28:24 -06002258 try:
Justin Thaler22b1bb52018-03-15 13:31:32 -05002259 resp = session.post(url, headers=httpHeader, data=data, verify=False)
Justin Thalere412dc22018-01-12 16:28:24 -06002260 except(requests.exceptions.Timeout):
2261 return connectionErrHandler(args.json, "Timeout", None)
2262 except(requests.exceptions.ConnectionError) as err:
2263 return connectionErrHandler(args.json, "ConnectionError", err)
Justin Thaler22b1bb52018-03-15 13:31:32 -05002264 if resp.status_code != 200:
2265 return "Failed to upload the file to the bmc"
Justin Thalere412dc22018-01-12 16:28:24 -06002266 else:
Justin Thaler22b1bb52018-03-15 13:31:32 -05002267 print("Upload complete.")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002268
Justin Thaler22b1bb52018-03-15 13:31:32 -05002269 #verify bmc processed the image
2270 software ={}
2271 for i in range(0, 5):
Justin Thaler22b1bb52018-03-15 13:31:32 -05002272 url="https://"+host+"/xyz/openbmc_project/software/enumerate"
2273 try:
Justin Thaler27197622019-01-23 14:42:11 -06002274 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thaler22b1bb52018-03-15 13:31:32 -05002275 except(requests.exceptions.Timeout):
2276 return connectionErrHandler(args.json, "Timeout", None)
2277 except(requests.exceptions.ConnectionError) as err:
2278 return connectionErrHandler(args.json, "ConnectionError", err)
2279 software = json.loads(resp.text)['data']
2280 #check if bmc is done processing the new image
2281 if (newversionID in getAllFWImageIDs(software)):
Justin Thalere412dc22018-01-12 16:28:24 -06002282 break
Justin Thaler22b1bb52018-03-15 13:31:32 -05002283 else:
2284 time.sleep(15)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002285
Justin Thaler22b1bb52018-03-15 13:31:32 -05002286 #activate the new image
2287 print("Activating new image: "+newversionID)
2288 url="https://"+host+"/xyz/openbmc_project/software/"+ newversionID + "/attr/RequestedActivation"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002289 data = '{"data":"xyz.openbmc_project.Software.Activation.RequestedActivations.Active"}'
Justin Thaler22b1bb52018-03-15 13:31:32 -05002290 try:
Justin Thaler27197622019-01-23 14:42:11 -06002291 resp = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thaler22b1bb52018-03-15 13:31:32 -05002292 except(requests.exceptions.Timeout):
2293 return connectionErrHandler(args.json, "Timeout", None)
2294 except(requests.exceptions.ConnectionError) as err:
2295 return connectionErrHandler(args.json, "ConnectionError", err)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002296
Justin Thaler22b1bb52018-03-15 13:31:32 -05002297 #wait for the activation to complete, timeout after ~1 hour
2298 i=0
2299 while i < 360:
2300 url="https://"+host+"/xyz/openbmc_project/software/"+ newversionID
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002301 data = '{"data":"xyz.openbmc_project.Software.Activation.RequestedActivations.Active"}'
Justin Thaler22b1bb52018-03-15 13:31:32 -05002302 try:
Justin Thaler27197622019-01-23 14:42:11 -06002303 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thaler22b1bb52018-03-15 13:31:32 -05002304 except(requests.exceptions.Timeout):
2305 return connectionErrHandler(args.json, "Timeout", None)
2306 except(requests.exceptions.ConnectionError) as err:
2307 return connectionErrHandler(args.json, "ConnectionError", err)
2308 fwInfo = json.loads(resp.text)['data']
2309 if 'Activating' not in fwInfo['Activation'] and 'Activating' not in fwInfo['RequestedActivation']:
2310 print('')
2311 break
2312 else:
2313 sys.stdout.write('.')
2314 sys.stdout.flush()
2315 time.sleep(10) #check every 10 seconds
2316 return "Firmware flash and activation completed. Please reboot the bmc and then boot the host OS for the changes to take effect. "
2317 else:
2318 print("This image has been found on the bmc. Activating image: " + newversionID)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002319
Justin Thaler22b1bb52018-03-15 13:31:32 -05002320 d['imageID'] = newversionID
2321 return activateFWImage(host, args, session)
Justin Thalere412dc22018-01-12 16:28:24 -06002322
Justin Thaler3d71d402018-07-24 14:35:39 -05002323def getFWInventoryAttributes(rawFWInvItem, ID):
2324 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002325 gets and lists all of the firmware in the system.
2326
Justin Thaler3d71d402018-07-24 14:35:39 -05002327 @return: returns a dictionary containing the image attributes
2328 """
2329 reqActivation = rawFWInvItem["RequestedActivation"].split('.')[-1]
2330 pendingActivation = ""
2331 if reqActivation == "None":
2332 pendingActivation = "No"
2333 else:
2334 pendingActivation = "Yes"
2335 firmwareAttr = {ID: {
2336 "Purpose": rawFWInvItem["Purpose"].split('.')[-1],
2337 "Version": rawFWInvItem["Version"],
2338 "RequestedActivation": pendingActivation,
2339 "ID": ID}}
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002340
Justin Thaler3d71d402018-07-24 14:35:39 -05002341 if "ExtendedVersion" in rawFWInvItem:
2342 firmwareAttr[ID]['ExtendedVersion'] = rawFWInvItem['ExtendedVersion'].split(',')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002343 else:
Justin Thaler3d71d402018-07-24 14:35:39 -05002344 firmwareAttr[ID]['ExtendedVersion'] = ""
2345 return firmwareAttr
2346
2347def parseFWdata(firmwareDict):
2348 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002349 creates a dictionary with parsed firmware data
2350
Justin Thaler3d71d402018-07-24 14:35:39 -05002351 @return: returns a dictionary containing the image attributes
2352 """
2353 firmwareInfoDict = {"Functional": {}, "Activated":{}, "NeedsActivated":{}}
2354 for key in firmwareDict['data']:
2355 #check for valid endpoint
2356 if "Purpose" in firmwareDict['data'][key]:
2357 id = key.split('/')[-1]
2358 if firmwareDict['data'][key]['Activation'].split('.')[-1] == "Active":
2359 fwActivated = True
2360 else:
2361 fwActivated = False
Justin Thalercb68e062019-03-26 19:04:52 -05002362 if 'Priority' in firmwareDict['data'][key]:
2363 if firmwareDict['data'][key]['Priority'] == 0:
2364 firmwareInfoDict['Functional'].update(getFWInventoryAttributes(firmwareDict['data'][key], id))
2365 elif firmwareDict['data'][key]['Priority'] >= 0 and fwActivated:
2366 firmwareInfoDict['Activated'].update(getFWInventoryAttributes(firmwareDict['data'][key], id))
2367 else:
2368 firmwareInfoDict['NeedsActivated'].update(getFWInventoryAttributes(firmwareDict['data'][key], id))
Justin Thaler3d71d402018-07-24 14:35:39 -05002369 else:
Justin Thalercb68e062019-03-26 19:04:52 -05002370 firmwareInfoDict['NeedsActivated'].update(getFWInventoryAttributes(firmwareDict['data'][key], id))
Justin Thaler3d71d402018-07-24 14:35:39 -05002371 emptySections = []
2372 for key in firmwareInfoDict:
2373 if len(firmwareInfoDict[key])<=0:
2374 emptySections.append(key)
2375 for key in emptySections:
2376 del firmwareInfoDict[key]
2377 return firmwareInfoDict
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002378
Justin Thaler3d71d402018-07-24 14:35:39 -05002379def displayFWInvenory(firmwareInfoDict, args):
2380 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002381 gets and lists all of the firmware in the system.
2382
Justin Thaler3d71d402018-07-24 14:35:39 -05002383 @return: returns a string containing all of the firmware information
2384 """
2385 output = ""
2386 if not args.json:
2387 for key in firmwareInfoDict:
2388 for subkey in firmwareInfoDict[key]:
2389 firmwareInfoDict[key][subkey]['ExtendedVersion'] = str(firmwareInfoDict[key][subkey]['ExtendedVersion'])
2390 if not args.verbose:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002391 output = "---Running Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002392 colNames = ["Purpose", "Version", "ID"]
2393 keylist = ["Purpose", "Version", "ID"]
2394 output += tableDisplay(keylist, colNames, firmwareInfoDict["Functional"])
2395 if "Activated" in firmwareInfoDict:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002396 output += "\n---Available Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002397 output += tableDisplay(keylist, colNames, firmwareInfoDict["Activated"])
2398 if "NeedsActivated" in firmwareInfoDict:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002399 output += "\n---Needs Activated Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002400 output += tableDisplay(keylist, colNames, firmwareInfoDict["NeedsActivated"])
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002401
Justin Thaler3d71d402018-07-24 14:35:39 -05002402 else:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002403 output = "---Running Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002404 colNames = ["Purpose", "Version", "ID", "Pending Activation", "Extended Version"]
2405 keylist = ["Purpose", "Version", "ID", "RequestedActivation", "ExtendedVersion"]
2406 output += tableDisplay(keylist, colNames, firmwareInfoDict["Functional"])
2407 if "Activated" in firmwareInfoDict:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002408 output += "\n---Available Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002409 output += tableDisplay(keylist, colNames, firmwareInfoDict["Activated"])
2410 if "NeedsActivated" in firmwareInfoDict:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002411 output += "\n---Needs Activated Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002412 output += tableDisplay(keylist, colNames, firmwareInfoDict["NeedsActivated"])
2413 return output
2414 else:
2415 return str(json.dumps(firmwareInfoDict, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False))
2416
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002417def firmwareList(host, args, session):
Justin Thaler3d71d402018-07-24 14:35:39 -05002418 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002419 gets and lists all of the firmware in the system.
2420
Justin Thaler3d71d402018-07-24 14:35:39 -05002421 @return: returns a string containing all of the firmware information
2422 """
Justin Thaler3d71d402018-07-24 14:35:39 -05002423 url="https://{hostname}/xyz/openbmc_project/software/enumerate".format(hostname=host)
2424 try:
Justin Thaler27197622019-01-23 14:42:11 -06002425 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thaler3d71d402018-07-24 14:35:39 -05002426 except(requests.exceptions.Timeout):
2427 return(connectionErrHandler(args.json, "Timeout", None))
2428 firmwareDict = json.loads(res.text)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002429
Justin Thaler3d71d402018-07-24 14:35:39 -05002430 #sort the received information
2431 firmwareInfoDict = parseFWdata(firmwareDict)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002432
Justin Thaler3d71d402018-07-24 14:35:39 -05002433 #display the information
2434 return displayFWInvenory(firmwareInfoDict, args)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002435
2436
Adriana Kobylak5af2fad2018-11-08 12:33:43 -06002437def deleteFWVersion(host, args, session):
2438 """
2439 deletes a firmware version on the BMC
2440
2441 @param host: string, the hostname or IP address of the BMC
2442 @param args: contains additional arguments used by the fwflash sub command
2443 @param session: the active session to use
2444 @param fwID: the unique ID of the fw version to delete
2445 """
2446 fwID = args.versionID
2447
2448 print("Deleting version: "+fwID)
2449 url="https://"+host+"/xyz/openbmc_project/software/"+ fwID + "/action/Delete"
Adriana Kobylak5af2fad2018-11-08 12:33:43 -06002450 data = "{\"data\": [] }"
2451
2452 try:
Justin Thaler27197622019-01-23 14:42:11 -06002453 res = session.post(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Adriana Kobylak5af2fad2018-11-08 12:33:43 -06002454 except(requests.exceptions.Timeout):
2455 return(connectionErrHandler(args.json, "Timeout", None))
2456 if res.status_code == 200:
2457 return ('The firmware version has been deleted')
2458 else:
2459 return ('Unable to delete the specified firmware version')
2460
2461
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05002462def restLogging(host, args, session):
2463 """
2464 Called by the logging function. Turns REST API logging on/off.
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002465
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05002466 @param host: string, the hostname or IP address of the bmc
2467 @param args: contains additional arguments used by the logging sub command
2468 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002469 @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 -05002470 """
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05002471 url="https://"+host+"/xyz/openbmc_project/logging/rest_api_logs/attr/Enabled"
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05002472
2473 if(args.rest_logging == 'on'):
2474 data = '{"data": 1}'
2475 elif(args.rest_logging == 'off'):
2476 data = '{"data": 0}'
2477 else:
2478 return "Invalid logging rest_api command"
2479
2480 try:
Justin Thaler27197622019-01-23 14:42:11 -06002481 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05002482 except(requests.exceptions.Timeout):
2483 return(connectionErrHandler(args.json, "Timeout", None))
2484 return res.text
2485
2486
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002487def remoteLogging(host, args, session):
2488 """
2489 Called by the logging function. View config information for/disable remote logging (rsyslog).
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002490
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002491 @param host: string, the hostname or IP address of the bmc
2492 @param args: contains additional arguments used by the logging sub command
2493 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002494 @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 -05002495 """
2496
2497 url="https://"+host+"/xyz/openbmc_project/logging/config/remote"
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002498
2499 try:
2500 if(args.remote_logging == 'view'):
Justin Thaler27197622019-01-23 14:42:11 -06002501 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002502 elif(args.remote_logging == 'disable'):
Justin Thaler27197622019-01-23 14:42:11 -06002503 res = session.put(url + '/attr/Port', headers=jsonHeader, json = {"data": 0}, verify=False, timeout=baseTimeout)
2504 res = session.put(url + '/attr/Address', headers=jsonHeader, json = {"data": ""}, verify=False, timeout=baseTimeout)
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002505 else:
2506 return "Invalid logging remote_logging command"
2507 except(requests.exceptions.Timeout):
2508 return(connectionErrHandler(args.json, "Timeout", None))
2509 return res.text
2510
2511
2512def remoteLoggingConfig(host, args, session):
2513 """
2514 Called by the logging function. Configures remote logging (rsyslog).
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002515
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002516 @param host: string, the hostname or IP address of the bmc
2517 @param args: contains additional arguments used by the logging sub command
2518 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002519 @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 -05002520 """
2521
2522 url="https://"+host+"/xyz/openbmc_project/logging/config/remote"
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002523
2524 try:
Justin Thaler27197622019-01-23 14:42:11 -06002525 res = session.put(url + '/attr/Port', headers=jsonHeader, json = {"data": args.port}, verify=False, timeout=baseTimeout)
2526 res = session.put(url + '/attr/Address', headers=jsonHeader, json = {"data": args.address}, verify=False, timeout=baseTimeout)
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002527 except(requests.exceptions.Timeout):
2528 return(connectionErrHandler(args.json, "Timeout", None))
2529 return res.text
2530
Marri Devender Rao82590dc2019-06-06 04:54:22 -05002531def redfishSupportPresent(host, session):
2532 url = "https://" + host + "/redfish/v1"
2533 try:
2534 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
2535 except(requests.exceptions.Timeout):
2536 return False
2537 except(requests.exceptions.ConnectionError) as err:
2538 return False
2539 if resp.status_code != 200:
2540 return False
2541 else:
2542 return True
Ratan Gupta9166cd22018-10-01 18:09:40 +05302543
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002544def certificateUpdate(host, args, session):
2545 """
2546 Called by certificate management function. update server/client/authority certificates
2547 Example:
2548 certificate update server https -f cert.pem
2549 certificate update authority ldap -f Root-CA.pem
2550 certificate update client ldap -f cert.pem
2551 @param host: string, the hostname or IP address of the bmc
2552 @param args: contains additional arguments used by the certificate update sub command
2553 @param session: the active session to use
2554 """
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002555 httpHeader = {'Content-Type': 'application/octet-stream'}
Matt Spinler220c3c42019-01-04 15:09:29 -06002556 httpHeader.update(xAuthHeader)
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002557 data = open(args.fileloc, 'rb').read()
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002558 try:
Marri Devender Rao82590dc2019-06-06 04:54:22 -05002559 if redfishSupportPresent(host, session):
Marri Devender Rao62db08a2019-08-22 03:16:02 -05002560 if(args.type.lower() == 'server' and args.service.lower() != "https"):
2561 return "Invalid service type"
2562 if(args.type.lower() == 'client' and args.service.lower() != "ldap"):
2563 return "Invalid service type"
2564 if(args.type.lower() == 'authority' and args.service.lower() != "ldap"):
2565 return "Invalid service type"
Marri Devender Rao82590dc2019-06-06 04:54:22 -05002566 url = "";
2567 if(args.type.lower() == 'server'):
2568 url = "https://" + host + \
2569 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"
2570 elif(args.type.lower() == 'client'):
2571 url = "https://" + host + \
2572 "/redfish/v1/AccountService/LDAP/Certificates"
2573 elif(args.type.lower() == 'authority'):
2574 url = "https://" + host + \
2575 "/redfish/v1/Managers/bmc/Truststore/Certificates"
2576 else:
2577 return "Unsupported certificate type"
2578 resp = session.post(url, headers=httpHeader, data=data,
2579 verify=False)
2580 else:
2581 url = "https://" + host + "/xyz/openbmc_project/certs/" + \
2582 args.type.lower() + "/" + args.service.lower()
2583 resp = session.put(url, headers=httpHeader, data=data, verify=False)
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002584 except(requests.exceptions.Timeout):
2585 return(connectionErrHandler(args.json, "Timeout", None))
2586 except(requests.exceptions.ConnectionError) as err:
2587 return connectionErrHandler(args.json, "ConnectionError", err)
2588 if resp.status_code != 200:
2589 print(resp.text)
2590 return "Failed to update the certificate"
2591 else:
Marri Devender Rao82590dc2019-06-06 04:54:22 -05002592 print("Update complete.")
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002593
2594def certificateDelete(host, args, session):
2595 """
2596 Called by certificate management function to delete certificate
2597 Example:
2598 certificate delete server https
2599 certificate delete authority ldap
2600 certificate delete client ldap
2601 @param host: string, the hostname or IP address of the bmc
2602 @param args: contains additional arguments used by the certificate delete sub command
2603 @param session: the active session to use
2604 """
Marri Devender Rao77e78682019-07-17 03:18:35 -05002605 if redfishSupportPresent(host, session):
2606 return "Not supported, please use certificate replace instead";
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002607 httpHeader = {'Content-Type': 'multipart/form-data'}
Matt Spinler220c3c42019-01-04 15:09:29 -06002608 httpHeader.update(xAuthHeader)
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002609 url = "https://" + host + "/xyz/openbmc_project/certs/" + args.type.lower() + "/" + args.service.lower()
2610 print("Deleting certificate url=" + url)
2611 try:
2612 resp = session.delete(url, headers=httpHeader)
2613 except(requests.exceptions.Timeout):
2614 return(connectionErrHandler(args.json, "Timeout", None))
2615 except(requests.exceptions.ConnectionError) as err:
2616 return connectionErrHandler(args.json, "ConnectionError", err)
2617 if resp.status_code != 200:
2618 print(resp.text)
2619 return "Failed to delete the certificate"
2620 else:
Marri Devender Rao77e78682019-07-17 03:18:35 -05002621 print("Delete complete.")
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002622
Marri Devender Raodfe81ad2019-07-01 05:38:09 -05002623def certificateReplace(host, args, session):
2624 """
2625 Called by certificate management function. replace server/client/
2626 authority certificates
2627 Example:
2628 certificate replace server https -f cert.pem
2629 certificate replace authority ldap -f Root-CA.pem
2630 certificate replace client ldap -f cert.pem
2631 @param host: string, the hostname or IP address of the bmc
2632 @param args: contains additional arguments used by the certificate
2633 replace sub command
2634 @param session: the active session to use
2635 """
2636 cert = open(args.fileloc, 'rb').read()
2637 try:
2638 if redfishSupportPresent(host, session):
2639 httpHeader = {'Content-Type': 'application/json'}
2640 httpHeader.update(xAuthHeader)
2641 url = "";
Marri Devender Rao62db08a2019-08-22 03:16:02 -05002642 if(args.type.lower() == 'server' and args.service.lower() != "https"):
2643 return "Invalid service type"
2644 if(args.type.lower() == 'client' and args.service.lower() != "ldap"):
2645 return "Invalid service type"
2646 if(args.type.lower() == 'authority' and args.service.lower() != "ldap"):
2647 return "Invalid service type"
Marri Devender Raodfe81ad2019-07-01 05:38:09 -05002648 if(args.type.lower() == 'server'):
2649 url = "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/1"
2650 elif(args.type.lower() == 'client'):
2651 url = "/redfish/v1/AccountService/LDAP/Certificates/1"
2652 elif(args.type.lower() == 'authority'):
2653 url = "/redfish/v1/Managers/bmc/Truststore/Certificates/1"
2654 replaceUrl = "https://" + host + \
2655 "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate"
2656 data ={"CertificateUri":{"@odata.id":url}, "CertificateType":"PEM",
2657 "CertificateString":cert}
2658 resp = session.post(replaceUrl, headers=httpHeader, json=data, verify=False)
2659 else:
2660 httpHeader = {'Content-Type': 'application/octet-stream'}
2661 httpHeader.update(xAuthHeader)
2662 url = "https://" + host + "/xyz/openbmc_project/certs/" + \
2663 args.type.lower() + "/" + args.service.lower()
2664 resp = session.delete(url, headers=httpHeader)
2665 resp = session.put(url, headers=httpHeader, data=cert, verify=False)
2666 except(requests.exceptions.Timeout):
2667 return(connectionErrHandler(args.json, "Timeout", None))
2668 except(requests.exceptions.ConnectionError) as err:
2669 return connectionErrHandler(args.json, "ConnectionError", err)
2670 if resp.status_code != 200:
2671 print(resp.text)
2672 return "Failed to replace the certificate"
2673 else:
2674 print("Replace complete.")
2675 return resp.text
2676
Marri Devender Rao34646402019-07-01 05:46:03 -05002677def certificateDisplay(host, args, session):
2678 """
2679 Called by certificate management function. display server/client/
2680 authority certificates
2681 Example:
2682 certificate display server
2683 certificate display authority
2684 certificate display client
2685 @param host: string, the hostname or IP address of the bmc
2686 @param args: contains additional arguments used by the certificate
2687 display sub command
2688 @param session: the active session to use
2689 """
2690 if not redfishSupportPresent(host, session):
2691 return "Not supported";
2692
2693 httpHeader = {'Content-Type': 'application/octet-stream'}
2694 httpHeader.update(xAuthHeader)
2695 if(args.type.lower() == 'server'):
2696 url = "https://" + host + \
2697 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/1"
2698 elif(args.type.lower() == 'client'):
2699 url = "https://" + host + \
2700 "/redfish/v1/AccountService/LDAP/Certificates/1"
2701 elif(args.type.lower() == 'authority'):
2702 url = "https://" + host + \
2703 "/redfish/v1/Managers/bmc/Truststore/Certificates/1"
2704 try:
2705 resp = session.get(url, headers=httpHeader, verify=False)
2706 except(requests.exceptions.Timeout):
2707 return(connectionErrHandler(args.json, "Timeout", None))
2708 except(requests.exceptions.ConnectionError) as err:
2709 return connectionErrHandler(args.json, "ConnectionError", err)
2710 if resp.status_code != 200:
2711 print(resp.text)
2712 return "Failed to display the certificate"
2713 else:
2714 print("Display complete.")
2715 return resp.text
2716
Marri Devender Raoa208ff82019-07-01 05:51:27 -05002717def certificateList(host, args, session):
2718 """
2719 Called by certificate management function.
2720 Example:
2721 certificate list
2722 @param host: string, the hostname or IP address of the bmc
2723 @param args: contains additional arguments used by the certificate
2724 list sub command
2725 @param session: the active session to use
2726 """
2727 if not redfishSupportPresent(host, session):
2728 return "Not supported";
2729
2730 httpHeader = {'Content-Type': 'application/octet-stream'}
2731 httpHeader.update(xAuthHeader)
2732 url = "https://" + host + \
2733 "/redfish/v1/CertificateService/CertificateLocations/"
2734 try:
2735 resp = session.get(url, headers=httpHeader, verify=False)
2736 except(requests.exceptions.Timeout):
2737 return(connectionErrHandler(args.json, "Timeout", None))
2738 except(requests.exceptions.ConnectionError) as err:
2739 return connectionErrHandler(args.json, "ConnectionError", err)
2740 if resp.status_code != 200:
2741 print(resp.text)
2742 return "Failed to list certificates"
2743 else:
2744 print("List certificates complete.")
2745 return resp.text
2746
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05002747def certificateGenerateCSR(host, args, session):
2748 """
2749 Called by certificate management function. Generate CSR for server/
2750 client certificates
2751 Example:
Marri Devender Raodf0e1a42019-09-09 08:18:27 -05002752 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
2753 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 -05002754 @param host: string, the hostname or IP address of the bmc
2755 @param args: contains additional arguments used by the certificate replace sub command
2756 @param session: the active session to use
2757 """
2758 if not redfishSupportPresent(host, session):
2759 return "Not supported";
2760
2761 httpHeader = {'Content-Type': 'application/octet-stream'}
2762 httpHeader.update(xAuthHeader)
2763 url = "";
2764 if(args.type.lower() == 'server'):
2765 url = "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/"
Marri Devender Rao88064f02019-08-19 09:00:30 -05002766 usage_list = ["ServerAuthentication"]
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05002767 elif(args.type.lower() == 'client'):
2768 url = "/redfish/v1/AccountService/LDAP/Certificates/"
Marri Devender Rao88064f02019-08-19 09:00:30 -05002769 usage_list = ["ClientAuthentication"]
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05002770 elif(args.type.lower() == 'authority'):
2771 url = "/redfish/v1/Managers/bmc/Truststore/Certificates/"
2772 print("Generating CSR url=" + url)
2773 generateCSRUrl = "https://" + host + \
2774 "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR"
2775 try:
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05002776 alt_name_list = args.alternativeNames.split(",")
2777 data ={"CertificateCollection":{"@odata.id":url},
2778 "CommonName":args.commonName, "City":args.city,
2779 "Country":args.country, "Organization":args.organization,
2780 "OrganizationalUnit":args.organizationUnit, "State":args.state,
Marri Devender Raodf0e1a42019-09-09 08:18:27 -05002781 "KeyPairAlgorithm":args.keyPairAlgorithm, "KeyCurveId":args.keyCurveId,
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05002782 "AlternativeNames":alt_name_list, "ContactPerson":args.contactPerson,
2783 "Email":args.email, "GivenName":args.givenname, "Initials":args.initials,
2784 "KeyUsage":usage_list, "Surname":args.surname,
2785 "UnstructuredName":args.unstructuredname}
2786 resp = session.post(generateCSRUrl, headers=httpHeader,
2787 json=data, verify=False)
2788 except(requests.exceptions.Timeout):
2789 return(connectionErrHandler(args.json, "Timeout", None))
2790 except(requests.exceptions.ConnectionError) as err:
2791 return connectionErrHandler(args.json, "ConnectionError", err)
2792 if resp.status_code != 200:
2793 print(resp.text)
2794 return "Failed to generate CSR"
2795 else:
2796 print("GenerateCSR complete.")
2797 return resp.text
2798
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05002799def enableLDAPConfig(host, args, session):
Ratan Gupta9166cd22018-10-01 18:09:40 +05302800 """
2801 Called by the ldap function. Configures LDAP.
2802
2803 @param host: string, the hostname or IP address of the bmc
2804 @param args: contains additional arguments used by the ldap subcommand
2805 @param session: the active session to use
2806 @param args.json: boolean, if this flag is set to true, the output will
2807 be provided in json format for programmatic consumption
2808 """
2809
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05002810 if(isRedfishSupport):
2811 return enableLDAP(host, args, session)
2812 else:
2813 return enableLegacyLDAP(host, args, session)
2814
2815def enableLegacyLDAP(host, args, session):
2816 """
2817 Called by the ldap function. Configures LDAP on Lagecy systems.
2818
2819 @param host: string, the hostname or IP address of the bmc
2820 @param args: contains additional arguments used by the ldap subcommand
2821 @param session: the active session to use
2822 @param args.json: boolean, if this flag is set to true, the output will
2823 be provided in json format for programmatic consumption
2824 """
2825
Ratan Gupta9166cd22018-10-01 18:09:40 +05302826 url='https://'+host+'/xyz/openbmc_project/user/ldap/action/CreateConfig'
Ratan Gupta9166cd22018-10-01 18:09:40 +05302827 scope = {
2828 'sub' : 'xyz.openbmc_project.User.Ldap.Create.SearchScope.sub',
2829 'one' : 'xyz.openbmc_project.User.Ldap.Create.SearchScope.one',
2830 'base': 'xyz.openbmc_project.User.Ldap.Create.SearchScope.base'
2831 }
2832
2833 serverType = {
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05002834 'ActiveDirectory' : 'xyz.openbmc_project.User.Ldap.Create.Type.ActiveDirectory',
2835 'OpenLDAP' : 'xyz.openbmc_project.User.Ldap.Create.Type.OpenLdap'
Ratan Gupta9166cd22018-10-01 18:09:40 +05302836 }
2837
2838 data = {"data": [args.uri, args.bindDN, args.baseDN, args.bindPassword, scope[args.scope], serverType[args.serverType]]}
2839
2840 try:
Justin Thaler27197622019-01-23 14:42:11 -06002841 res = session.post(url, headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
Ratan Gupta9166cd22018-10-01 18:09:40 +05302842 except(requests.exceptions.Timeout):
2843 return(connectionErrHandler(args.json, "Timeout", None))
2844 except(requests.exceptions.ConnectionError) as err:
2845 return connectionErrHandler(args.json, "ConnectionError", err)
2846
2847 return res.text
2848
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05002849def enableLDAP(host, args, session):
2850 """
2851 Called by the ldap function. Configures LDAP for systems with latest user-manager design changes
2852
2853 @param host: string, the hostname or IP address of the bmc
2854 @param args: contains additional arguments used by the ldap subcommand
2855 @param session: the active session to use
2856 @param args.json: boolean, if this flag is set to true, the output will
2857 be provided in json format for programmatic consumption
2858 """
2859
2860 scope = {
2861 'sub' : 'xyz.openbmc_project.User.Ldap.Config.SearchScope.sub',
2862 'one' : 'xyz.openbmc_project.User.Ldap.Config.SearchScope.one',
2863 'base': 'xyz.openbmc_project.User.Ldap.Config.SearchScope.base'
2864 }
2865
2866 serverType = {
2867 'ActiveDirectory' : 'xyz.openbmc_project.User.Ldap.Config.Type.ActiveDirectory',
2868 'OpenLDAP' : 'xyz.openbmc_project.User.Ldap.Config.Type.OpenLdap'
2869 }
2870
2871 url = "https://"+host+"/xyz/openbmc_project/user/ldap/"
2872
2873 serverTypeEnabled = getLDAPTypeEnabled(host,session)
2874 serverTypeToBeEnabled = args.serverType
2875
2876 #If the given LDAP type is already enabled, then return
2877 if (serverTypeToBeEnabled == serverTypeEnabled):
2878 return("Server type " + serverTypeToBeEnabled + " is already enabled...")
2879
2880 try:
2881
2882 # Copy the role map from the currently enabled LDAP server type
2883 # to the newly enabled server type
2884 # Disable the currently enabled LDAP server type. Unless
2885 # it is disabled, we cannot enable a new LDAP server type
2886 if (serverTypeEnabled is not None):
2887
2888 if (serverTypeToBeEnabled != serverTypeEnabled):
2889 res = syncRoleMap(host,args,session,serverTypeEnabled,serverTypeToBeEnabled)
2890
2891 data = "{\"data\": 0 }"
2892 res = session.put(url + serverTypeMap[serverTypeEnabled] + '/attr/Enabled', headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
2893
2894 data = {"data": args.baseDN}
2895 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/LDAPBaseDN', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
2896 if (res.status_code != requests.codes.ok):
2897 print("Updates to the property LDAPBaseDN failed...")
2898 return(res.text)
2899
2900 data = {"data": args.bindDN}
2901 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/LDAPBindDN', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
2902 if (res.status_code != requests.codes.ok):
2903 print("Updates to the property LDAPBindDN failed...")
2904 return(res.text)
2905
2906 data = {"data": args.bindPassword}
2907 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/LDAPBindDNPassword', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
2908 if (res.status_code != requests.codes.ok):
2909 print("Updates to the property LDAPBindDNPassword failed...")
2910 return(res.text)
2911
2912 data = {"data": scope[args.scope]}
2913 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/LDAPSearchScope', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
2914 if (res.status_code != requests.codes.ok):
2915 print("Updates to the property LDAPSearchScope failed...")
2916 return(res.text)
2917
2918 data = {"data": args.uri}
2919 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/LDAPServerURI', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
2920 if (res.status_code != requests.codes.ok):
2921 print("Updates to the property LDAPServerURI failed...")
2922 return(res.text)
2923
2924 data = {"data": args.groupAttrName}
2925 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/GroupNameAttribute', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
2926 if (res.status_code != requests.codes.ok):
2927 print("Updates to the property GroupNameAttribute failed...")
2928 return(res.text)
2929
2930 data = {"data": args.userAttrName}
2931 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/UserNameAttribute', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
2932 if (res.status_code != requests.codes.ok):
2933 print("Updates to the property UserNameAttribute failed...")
2934 return(res.text)
2935
2936 #After updating the properties, enable the new server type
2937 data = "{\"data\": 1 }"
2938 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/Enabled', headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
2939
2940 except(requests.exceptions.Timeout):
2941 return(connectionErrHandler(args.json, "Timeout", None))
2942 except(requests.exceptions.ConnectionError) as err:
2943 return connectionErrHandler(args.json, "ConnectionError", err)
2944 return res.text
Ratan Gupta9166cd22018-10-01 18:09:40 +05302945
2946def disableLDAP(host, args, session):
2947 """
2948 Called by the ldap function. Deletes the LDAP Configuration.
2949
2950 @param host: string, the hostname or IP address of the bmc
2951 @param args: contains additional arguments used by the ldap subcommand
2952 @param session: the active session to use
2953 @param args.json: boolean, if this flag is set to true, the output
2954 will be provided in json format for programmatic consumption
2955 """
2956
Ratan Gupta9166cd22018-10-01 18:09:40 +05302957 try:
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05002958 if (isRedfishSupport) :
2959
2960 url = "https://"+host+"/xyz/openbmc_project/user/ldap/"
2961
2962 serverTypeEnabled = getLDAPTypeEnabled(host,session)
2963
2964 if (serverTypeEnabled is not None):
2965 #To keep the role map in sync,
2966 #If the server type being disabled has role map, then
2967 # - copy the role map to the other server type(s)
2968 for serverType in serverTypeMap.keys():
2969 if (serverType != serverTypeEnabled):
2970 res = syncRoleMap(host,args,session,serverTypeEnabled,serverType)
2971
2972 #Disable the currently enabled LDAP server type
2973 data = "{\"data\": 0 }"
2974 res = session.put(url + serverTypeMap[serverTypeEnabled] + '/attr/Enabled', headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
2975
2976 else:
2977 return("LDAP server has not been enabled...")
2978
2979 else :
2980 url='https://'+host+'/xyz/openbmc_project/user/ldap/config/action/delete'
2981 data = {"data": []}
2982 res = session.post(url, headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
2983
Ratan Gupta9166cd22018-10-01 18:09:40 +05302984 except(requests.exceptions.Timeout):
2985 return(connectionErrHandler(args.json, "Timeout", None))
2986 except(requests.exceptions.ConnectionError) as err:
2987 return connectionErrHandler(args.json, "ConnectionError", err)
2988
2989 return res.text
2990
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06002991def enableDHCP(host, args, session):
2992
2993 """
2994 Called by the network function. Enables DHCP.
2995
2996 @param host: string, the hostname or IP address of the bmc
2997 @param args: contains additional arguments used by the ldap subcommand
2998 args.json: boolean, if this flag is set to true, the output
2999 will be provided in json format for programmatic consumption
3000 @param session: the active session to use
3001 """
3002
3003 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3004 "/attr/DHCPEnabled"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003005 data = "{\"data\": 1 }"
3006 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003007 res = session.put(url, headers=jsonHeader, data=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003008 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003009
3010 except(requests.exceptions.Timeout):
3011 return(connectionErrHandler(args.json, "Timeout", None))
3012 except(requests.exceptions.ConnectionError) as err:
3013 return connectionErrHandler(args.json, "ConnectionError", err)
3014 if res.status_code == 403:
3015 return "The specified Interface"+"("+args.Interface+")"+\
3016 " doesn't exist"
3017
3018 return res.text
3019
3020
3021def disableDHCP(host, args, session):
3022 """
3023 Called by the network function. Disables DHCP.
3024
3025 @param host: string, the hostname or IP address of the bmc
3026 @param args: contains additional arguments used by the ldap subcommand
3027 args.json: boolean, if this flag is set to true, the output
3028 will be provided in json format for programmatic consumption
3029 @param session: the active session to use
3030 """
3031
3032 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3033 "/attr/DHCPEnabled"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003034 data = "{\"data\": 0 }"
3035 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003036 res = session.put(url, headers=jsonHeader, data=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003037 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003038 except(requests.exceptions.Timeout):
3039 return(connectionErrHandler(args.json, "Timeout", None))
3040 except(requests.exceptions.ConnectionError) as err:
3041 return connectionErrHandler(args.json, "ConnectionError", err)
3042 if res.status_code == 403:
3043 return "The specified Interface"+"("+args.Interface+")"+\
3044 " doesn't exist"
3045 return res.text
3046
3047
3048def getHostname(host, args, session):
3049
3050 """
3051 Called by the network function. Prints out the Hostname.
3052
3053 @param host: string, the hostname or IP address of the bmc
3054 @param args: contains additional arguments used by the ldap subcommand
3055 args.json: boolean, if this flag is set to true, the output
3056 will be provided in json format for programmatic consumption
3057 @param session: the active session to use
3058 """
3059
3060 url = "https://"+host+"/xyz/openbmc_project/network/config/attr/HostName"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003061
3062 try:
Justin Thaler27197622019-01-23 14:42:11 -06003063 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003064 except(requests.exceptions.Timeout):
3065 return(connectionErrHandler(args.json, "Timeout", None))
3066 except(requests.exceptions.ConnectionError) as err:
3067 return connectionErrHandler(args.json, "ConnectionError", err)
3068
3069 return res.text
3070
3071
3072def setHostname(host, args, session):
3073 """
3074 Called by the network function. Sets the Hostname.
3075
3076 @param host: string, the hostname or IP address of the bmc
3077 @param args: contains additional arguments used by the ldap subcommand
3078 args.json: boolean, if this flag is set to true, the output
3079 will be provided in json format for programmatic consumption
3080 @param session: the active session to use
3081 """
3082
3083 url = "https://"+host+"/xyz/openbmc_project/network/config/attr/HostName"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003084
3085 data = {"data": args.HostName}
3086
3087 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003088 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003089 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003090 except(requests.exceptions.Timeout):
3091 return(connectionErrHandler(args.json, "Timeout", None))
3092 except(requests.exceptions.ConnectionError) as err:
3093 return connectionErrHandler(args.json, "ConnectionError", err)
3094
3095 return res.text
3096
3097
3098def getDomainName(host, args, session):
3099
3100 """
3101 Called by the network function. Prints out the DomainName.
3102
3103 @param host: string, the hostname or IP address of the bmc
3104 @param args: contains additional arguments used by the ldap subcommand
3105 args.json: boolean, if this flag is set to true, the output
3106 will be provided in json format for programmatic consumption
3107 @param session: the active session to use
3108 """
3109
3110 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3111 "/attr/DomainName"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003112
3113 try:
Justin Thaler27197622019-01-23 14:42:11 -06003114 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003115 except(requests.exceptions.Timeout):
3116 return(connectionErrHandler(args.json, "Timeout", None))
3117 except(requests.exceptions.ConnectionError) as err:
3118 return connectionErrHandler(args.json, "ConnectionError", err)
3119 if res.status_code == 404:
Sunitha Harishf9bb2fa2019-09-19 01:48:00 -05003120 return "The DomainName is not configured on Interface"+"("+args.Interface+")"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003121
3122 return res.text
3123
3124
3125def setDomainName(host, args, session):
3126 """
3127 Called by the network function. Sets the DomainName.
3128
3129 @param host: string, the hostname or IP address of the bmc
3130 @param args: contains additional arguments used by the ldap subcommand
3131 args.json: boolean, if this flag is set to true, the output
3132 will be provided in json format for programmatic consumption
3133 @param session: the active session to use
3134 """
3135
3136 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3137 "/attr/DomainName"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003138
3139 data = {"data": args.DomainName.split(",")}
3140
3141 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003142 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003143 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003144 except(requests.exceptions.Timeout):
3145 return(connectionErrHandler(args.json, "Timeout", None))
3146 except(requests.exceptions.ConnectionError) as err:
3147 return connectionErrHandler(args.json, "ConnectionError", err)
3148 if res.status_code == 403:
3149 return "The specified Interface"+"("+args.Interface+")"+\
3150 " doesn't exist"
3151
3152 return res.text
3153
3154
3155def getMACAddress(host, args, session):
3156
3157 """
3158 Called by the network function. Prints out the MACAddress.
3159
3160 @param host: string, the hostname or IP address of the bmc
3161 @param args: contains additional arguments used by the ldap subcommand
3162 args.json: boolean, if this flag is set to true, the output
3163 will be provided in json format for programmatic consumption
3164 @param session: the active session to use
3165 """
3166
3167 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3168 "/attr/MACAddress"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003169
3170 try:
Justin Thaler27197622019-01-23 14:42:11 -06003171 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003172 except(requests.exceptions.Timeout):
3173 return(connectionErrHandler(args.json, "Timeout", None))
3174 except(requests.exceptions.ConnectionError) as err:
3175 return connectionErrHandler(args.json, "ConnectionError", err)
3176 if res.status_code == 404:
3177 return "The specified Interface"+"("+args.Interface+")"+\
3178 " doesn't exist"
3179
3180 return res.text
3181
3182
3183def setMACAddress(host, args, session):
3184 """
3185 Called by the network function. Sets the MACAddress.
3186
3187 @param host: string, the hostname or IP address of the bmc
3188 @param args: contains additional arguments used by the ldap subcommand
3189 args.json: boolean, if this flag is set to true, the output
3190 will be provided in json format for programmatic consumption
3191 @param session: the active session to use
3192 """
3193
3194 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3195 "/attr/MACAddress"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003196
3197 data = {"data": args.MACAddress}
3198
3199 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003200 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003201 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003202 except(requests.exceptions.Timeout):
3203 return(connectionErrHandler(args.json, "Timeout", None))
3204 except(requests.exceptions.ConnectionError) as err:
3205 return connectionErrHandler(args.json, "ConnectionError", err)
3206 if res.status_code == 403:
3207 return "The specified Interface"+"("+args.Interface+")"+\
3208 " doesn't exist"
3209
3210 return res.text
3211
3212
3213def getDefaultGateway(host, args, session):
3214
3215 """
3216 Called by the network function. Prints out the DefaultGateway.
3217
3218 @param host: string, the hostname or IP address of the bmc
3219 @param args: contains additional arguments used by the ldap subcommand
3220 args.json: boolean, if this flag is set to true, the output
3221 will be provided in json format for programmatic consumption
3222 @param session: the active session to use
3223 """
3224
3225 url = "https://"+host+"/xyz/openbmc_project/network/config/attr/DefaultGateway"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003226
3227 try:
Justin Thaler27197622019-01-23 14:42:11 -06003228 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003229 except(requests.exceptions.Timeout):
3230 return(connectionErrHandler(args.json, "Timeout", None))
3231 except(requests.exceptions.ConnectionError) as err:
3232 return connectionErrHandler(args.json, "ConnectionError", err)
3233 if res.status_code == 404:
3234 return "Failed to get Default Gateway info!!"
3235
3236 return res.text
3237
3238
3239def setDefaultGateway(host, args, session):
3240 """
3241 Called by the network function. Sets the DefaultGateway.
3242
3243 @param host: string, the hostname or IP address of the bmc
3244 @param args: contains additional arguments used by the ldap subcommand
3245 args.json: boolean, if this flag is set to true, the output
3246 will be provided in json format for programmatic consumption
3247 @param session: the active session to use
3248 """
3249
3250 url = "https://"+host+"/xyz/openbmc_project/network/config/attr/DefaultGateway"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003251
3252 data = {"data": args.DefaultGW}
3253
3254 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003255 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003256 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003257 except(requests.exceptions.Timeout):
3258 return(connectionErrHandler(args.json, "Timeout", None))
3259 except(requests.exceptions.ConnectionError) as err:
3260 return connectionErrHandler(args.json, "ConnectionError", err)
3261 if res.status_code == 403:
3262 return "Failed to set Default Gateway!!"
3263
3264 return res.text
3265
3266
3267def viewNWConfig(host, args, session):
3268 """
3269 Called by the ldap function. Prints out network configured properties
3270
3271 @param host: string, the hostname or IP address of the bmc
3272 @param args: contains additional arguments used by the ldap subcommand
3273 args.json: boolean, if this flag is set to true, the output
3274 will be provided in json format for programmatic consumption
3275 @param session: the active session to use
3276 @return returns LDAP's configured properties.
3277 """
3278 url = "https://"+host+"/xyz/openbmc_project/network/enumerate"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003279 try:
Justin Thaler27197622019-01-23 14:42:11 -06003280 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003281 except(requests.exceptions.Timeout):
3282 return(connectionErrHandler(args.json, "Timeout", None))
3283 except(requests.exceptions.ConnectionError) as err:
3284 return connectionErrHandler(args.json, "ConnectionError", err)
3285 except(requests.exceptions.RequestException) as err:
3286 return connectionErrHandler(args.json, "RequestException", err)
3287 if res.status_code == 404:
3288 return "LDAP server config has not been created"
3289 return res.text
3290
3291
3292def getDNS(host, args, session):
3293
3294 """
3295 Called by the network function. Prints out DNS servers on the interface
3296
3297 @param host: string, the hostname or IP address of the bmc
3298 @param args: contains additional arguments used by the ldap subcommand
3299 args.json: boolean, if this flag is set to true, the output
3300 will be provided in json format for programmatic consumption
3301 @param session: the active session to use
3302 """
3303
3304 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
3305 + "/attr/Nameservers"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003306
3307 try:
Justin Thaler27197622019-01-23 14:42:11 -06003308 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003309 except(requests.exceptions.Timeout):
3310 return(connectionErrHandler(args.json, "Timeout", None))
3311 except(requests.exceptions.ConnectionError) as err:
3312 return connectionErrHandler(args.json, "ConnectionError", err)
3313 if res.status_code == 404:
Sunitha Harishf9bb2fa2019-09-19 01:48:00 -05003314 return "The NameServer is not configured on Interface"+"("+args.Interface+")"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003315
3316 return res.text
3317
3318
3319def setDNS(host, args, session):
3320 """
3321 Called by the network function. Sets DNS servers on the interface.
3322
3323 @param host: string, the hostname or IP address of the bmc
3324 @param args: contains additional arguments used by the ldap subcommand
3325 args.json: boolean, if this flag is set to true, the output
3326 will be provided in json format for programmatic consumption
3327 @param session: the active session to use
3328 """
3329
3330 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
3331 + "/attr/Nameservers"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003332
3333 data = {"data": args.DNSServers.split(",")}
3334
3335 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003336 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003337 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003338 except(requests.exceptions.Timeout):
3339 return(connectionErrHandler(args.json, "Timeout", None))
3340 except(requests.exceptions.ConnectionError) as err:
3341 return connectionErrHandler(args.json, "ConnectionError", err)
3342 if res.status_code == 403:
3343 return "The specified Interface"+"("+args.Interface+")" +\
3344 " doesn't exist"
3345
3346 return res.text
3347
3348
3349def getNTP(host, args, session):
3350
3351 """
3352 Called by the network function. Prints out NTP servers on the interface
3353
3354 @param host: string, the hostname or IP address of the bmc
3355 @param args: contains additional arguments used by the ldap subcommand
3356 args.json: boolean, if this flag is set to true, the output
3357 will be provided in json format for programmatic consumption
3358 @param session: the active session to use
3359 """
3360
3361 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
3362 + "/attr/NTPServers"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003363 try:
Justin Thaler27197622019-01-23 14:42:11 -06003364 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003365 except(requests.exceptions.Timeout):
3366 return(connectionErrHandler(args.json, "Timeout", None))
3367 except(requests.exceptions.ConnectionError) as err:
3368 return connectionErrHandler(args.json, "ConnectionError", err)
3369 if res.status_code == 404:
Sunitha Harishf9bb2fa2019-09-19 01:48:00 -05003370 return "The NTPServer is not configured on Interface"+"("+args.Interface+")"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003371
3372 return res.text
3373
3374
3375def setNTP(host, args, session):
3376 """
3377 Called by the network function. Sets NTP servers on the interface.
3378
3379 @param host: string, the hostname or IP address of the bmc
3380 @param args: contains additional arguments used by the ldap subcommand
3381 args.json: boolean, if this flag is set to true, the output
3382 will be provided in json format for programmatic consumption
3383 @param session: the active session to use
3384 """
3385
3386 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
3387 + "/attr/NTPServers"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003388
3389 data = {"data": args.NTPServers.split(",")}
3390
3391 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003392 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003393 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003394 except(requests.exceptions.Timeout):
3395 return(connectionErrHandler(args.json, "Timeout", None))
3396 except(requests.exceptions.ConnectionError) as err:
3397 return connectionErrHandler(args.json, "ConnectionError", err)
3398 if res.status_code == 403:
3399 return "The specified Interface"+"("+args.Interface+")" +\
3400 " doesn't exist"
3401
3402 return res.text
3403
3404
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003405def addIP(host, args, session):
3406 """
3407 Called by the network function. Configures IP address on given interface
3408
3409 @param host: string, the hostname or IP address of the bmc
3410 @param args: contains additional arguments used by the ldap subcommand
3411 args.json: boolean, if this flag is set to true, the output
3412 will be provided in json format for programmatic consumption
3413 @param session: the active session to use
3414 """
3415
3416 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
3417 + "/action/IP"
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003418 protocol = {
3419 'ipv4': 'xyz.openbmc_project.Network.IP.Protocol.IPv4',
3420 'ipv6': 'xyz.openbmc_project.Network.IP.Protocol.IPv6'
3421 }
3422
3423 data = {"data": [protocol[args.type], args.address, int(args.prefixLength),
3424 args.gateway]}
3425
3426 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003427 res = session.post(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003428 timeout=baseTimeout)
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003429 except(requests.exceptions.Timeout):
3430 return(connectionErrHandler(args.json, "Timeout", None))
3431 except(requests.exceptions.ConnectionError) as err:
3432 return connectionErrHandler(args.json, "ConnectionError", err)
3433 if res.status_code == 404:
3434 return "The specified Interface" + "(" + args.Interface + ")" +\
3435 " doesn't exist"
3436
3437 return res.text
3438
3439
3440def getIP(host, args, session):
3441 """
3442 Called by the network function. Prints out IP address of given interface
3443
3444 @param host: string, the hostname or IP address of the bmc
3445 @param args: contains additional arguments used by the ldap subcommand
3446 args.json: boolean, if this flag is set to true, the output
3447 will be provided in json format for programmatic consumption
3448 @param session: the active session to use
3449 """
3450
3451 url = "https://" + host+"/xyz/openbmc_project/network/" + args.Interface +\
3452 "/enumerate"
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003453 try:
Justin Thaler27197622019-01-23 14:42:11 -06003454 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003455 except(requests.exceptions.Timeout):
3456 return(connectionErrHandler(args.json, "Timeout", None))
3457 except(requests.exceptions.ConnectionError) as err:
3458 return connectionErrHandler(args.json, "ConnectionError", err)
3459 if res.status_code == 404:
3460 return "The specified Interface" + "(" + args.Interface + ")" +\
3461 " doesn't exist"
3462
3463 return res.text
3464
3465
3466def deleteIP(host, args, session):
3467 """
3468 Called by the network function. Deletes the IP address from given Interface
3469
3470 @param host: string, the hostname or IP address of the bmc
3471 @param args: contains additional arguments used by the ldap subcommand
3472 @param session: the active session to use
3473 @param args.json: boolean, if this flag is set to true, the output
3474 will be provided in json format for programmatic consumption
3475 """
3476
3477 url = "https://"+host+"/xyz/openbmc_project/network/" + args.Interface+\
3478 "/enumerate"
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003479 data = {"data": []}
3480 try:
Justin Thaler27197622019-01-23 14:42:11 -06003481 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003482 except(requests.exceptions.Timeout):
3483 return(connectionErrHandler(args.json, "Timeout", None))
3484 except(requests.exceptions.ConnectionError) as err:
3485 return connectionErrHandler(args.json, "ConnectionError", err)
3486 if res.status_code == 404:
3487 return "The specified Interface" + "(" + args.Interface + ")" +\
3488 " doesn't exist"
3489 objDict = json.loads(res.text)
3490 if not objDict['data']:
3491 return "No object found for given address on given Interface"
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003492 for obj in objDict['data']:
Sunitha Harish0baf6372019-07-31 03:59:03 -05003493 try:
3494 if args.address in objDict['data'][obj]['Address']:
3495 url = "https://"+host+obj+"/action/Delete"
3496 try:
3497 res = session.post(url, headers=jsonHeader, json=data,
3498 verify=False, timeout=baseTimeout)
3499 except(requests.exceptions.Timeout):
3500 return(connectionErrHandler(args.json, "Timeout", None))
3501 except(requests.exceptions.ConnectionError) as err:
3502 return connectionErrHandler(args.json, "ConnectionError", err)
3503 return res.text
3504 else:
3505 continue
3506 except KeyError:
Sunitha Harishf9bb2fa2019-09-19 01:48:00 -05003507 continue
3508 return "No object found for address " + args.address + \
3509 " on Interface(" + args.Interface + ")"
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003510
3511
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003512def addVLAN(host, args, session):
3513 """
3514 Called by the network function. Creates VLAN on given interface.
3515
3516 @param host: string, the hostname or IP address of the bmc
3517 @param args: contains additional arguments used by the ldap subcommand
3518 args.json: boolean, if this flag is set to true, the output
3519 will be provided in json format for programmatic consumption
3520 @param session: the active session to use
3521 """
3522
3523 url = "https://" + host+"/xyz/openbmc_project/network/action/VLAN"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003524
Sunitha Harish0baf6372019-07-31 03:59:03 -05003525 data = {"data": [args.Interface,int(args.Identifier)]}
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003526 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003527 res = session.post(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003528 timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003529 except(requests.exceptions.Timeout):
3530 return(connectionErrHandler(args.json, "Timeout", None))
3531 except(requests.exceptions.ConnectionError) as err:
3532 return connectionErrHandler(args.json, "ConnectionError", err)
3533 if res.status_code == 400:
Sunitha Harish0baf6372019-07-31 03:59:03 -05003534 return "Adding VLAN to interface" + "(" + args.Interface + ")" +\
3535 " failed"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003536
3537 return res.text
3538
3539
3540def deleteVLAN(host, args, session):
3541 """
3542 Called by the network function. Creates VLAN on given interface.
3543
3544 @param host: string, the hostname or IP address of the bmc
3545 @param args: contains additional arguments used by the ldap subcommand
3546 args.json: boolean, if this flag is set to true, the output
3547 will be provided in json format for programmatic consumption
3548 @param session: the active session to use
3549 """
3550
Sunitha Harish577a5032019-08-08 06:27:40 -05003551 url = "https://" + host+"/xyz/openbmc_project/network/"+args.Interface+"/action/Delete"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003552 data = {"data": []}
3553
3554 try:
Justin Thaler27197622019-01-23 14:42:11 -06003555 res = session.post(url, headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003556 except(requests.exceptions.Timeout):
3557 return(connectionErrHandler(args.json, "Timeout", None))
3558 except(requests.exceptions.ConnectionError) as err:
3559 return connectionErrHandler(args.json, "ConnectionError", err)
3560 if res.status_code == 404:
Sunitha Harish577a5032019-08-08 06:27:40 -05003561 return "The specified VLAN"+"("+args.Interface+")" +" doesn't exist"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003562
3563 return res.text
3564
3565
3566def viewDHCPConfig(host, args, session):
3567 """
3568 Called by the network function. Shows DHCP configured Properties.
3569
3570 @param host: string, the hostname or IP address of the bmc
3571 @param args: contains additional arguments used by the ldap subcommand
3572 args.json: boolean, if this flag is set to true, the output
3573 will be provided in json format for programmatic consumption
3574 @param session: the active session to use
3575 """
3576
3577 url="https://"+host+"/xyz/openbmc_project/network/config/dhcp"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003578
3579 try:
Justin Thaler27197622019-01-23 14:42:11 -06003580 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003581 except(requests.exceptions.Timeout):
3582 return(connectionErrHandler(args.json, "Timeout", None))
3583 except(requests.exceptions.ConnectionError) as err:
3584 return connectionErrHandler(args.json, "ConnectionError", err)
3585
3586 return res.text
3587
3588
3589def configureDHCP(host, args, session):
3590 """
3591 Called by the network function. Configures/updates DHCP Properties.
3592
3593 @param host: string, the hostname or IP address of the bmc
3594 @param args: contains additional arguments used by the ldap subcommand
3595 args.json: boolean, if this flag is set to true, the output
3596 will be provided in json format for programmatic consumption
3597 @param session: the active session to use
3598 """
3599
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003600
3601 try:
3602 url="https://"+host+"/xyz/openbmc_project/network/config/dhcp"
3603 if(args.DNSEnabled == True):
3604 data = '{"data": 1}'
3605 else:
3606 data = '{"data": 0}'
Matt Spinler220c3c42019-01-04 15:09:29 -06003607 res = session.put(url + '/attr/DNSEnabled', headers=jsonHeader,
Justin Thaler27197622019-01-23 14:42:11 -06003608 data=data, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003609 if(args.HostNameEnabled == True):
3610 data = '{"data": 1}'
3611 else:
3612 data = '{"data": 0}'
Matt Spinler220c3c42019-01-04 15:09:29 -06003613 res = session.put(url + '/attr/HostNameEnabled', headers=jsonHeader,
Justin Thaler27197622019-01-23 14:42:11 -06003614 data=data, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003615 if(args.NTPEnabled == True):
3616 data = '{"data": 1}'
3617 else:
3618 data = '{"data": 0}'
Matt Spinler220c3c42019-01-04 15:09:29 -06003619 res = session.put(url + '/attr/NTPEnabled', headers=jsonHeader,
Justin Thaler27197622019-01-23 14:42:11 -06003620 data=data, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003621 if(args.SendHostNameEnabled == True):
3622 data = '{"data": 1}'
3623 else:
3624 data = '{"data": 0}'
Matt Spinler220c3c42019-01-04 15:09:29 -06003625 res = session.put(url + '/attr/SendHostNameEnabled', headers=jsonHeader,
Justin Thaler27197622019-01-23 14:42:11 -06003626 data=data, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003627 except(requests.exceptions.Timeout):
3628 return(connectionErrHandler(args.json, "Timeout", None))
3629 except(requests.exceptions.ConnectionError) as err:
3630 return connectionErrHandler(args.json, "ConnectionError", err)
3631
3632 return res.text
3633
3634
3635def nwReset(host, args, session):
3636
3637 """
3638 Called by the network function. Resets networks setting to factory defaults.
3639
3640 @param host: string, the hostname or IP address of the bmc
3641 @param args: contains additional arguments used by the ldap subcommand
3642 args.json: boolean, if this flag is set to true, the output
3643 will be provided in json format for programmatic consumption
3644 @param session: the active session to use
3645 """
3646
3647 url = "https://"+host+"/xyz/openbmc_project/network/action/Reset"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003648 data = '{"data":[] }'
3649 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003650 res = session.post(url, headers=jsonHeader, data=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003651 timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003652
3653 except(requests.exceptions.Timeout):
3654 return(connectionErrHandler(args.json, "Timeout", None))
3655 except(requests.exceptions.ConnectionError) as err:
3656 return connectionErrHandler(args.json, "ConnectionError", err)
3657
3658 return res.text
3659
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003660def getLDAPTypeEnabled(host,session):
3661
3662 """
3663 Called by LDAP related functions to find the LDAP server type that has been enabled.
3664 Returns None if LDAP has not been configured.
3665
3666 @param host: string, the hostname or IP address of the bmc
3667 @param session: the active session to use
3668 """
3669
3670 enabled = False
3671 url = 'https://'+host+'/xyz/openbmc_project/user/ldap/'
3672 for key,value in serverTypeMap.items():
3673 data = {"data": []}
3674 try:
3675 res = session.get(url + value + '/attr/Enabled', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
3676 except(requests.exceptions.Timeout):
3677 print(connectionErrHandler(args.json, "Timeout", None))
3678 return
3679 except(requests.exceptions.ConnectionError) as err:
3680 print(connectionErrHandler(args.json, "ConnectionError", err))
3681 return
3682
3683 enabled = res.json()['data']
3684 if (enabled):
3685 return key
3686
3687def syncRoleMap(host,args,session,fromServerType,toServerType):
3688
3689 """
3690 Called by LDAP related functions to sync the role maps
3691 Returns False if LDAP has not been configured.
3692
3693 @param host: string, the hostname or IP address of the bmc
3694 @param session: the active session to use
3695 @param fromServerType : Server type whose role map has to be copied
3696 @param toServerType : Server type to which role map has to be copied
3697 """
3698
3699 url = "https://"+host+"/xyz/openbmc_project/user/ldap/"
3700
3701 try:
3702 #Note: If the fromServerType has no role map, then
3703 #the toServerType will not have any role map.
3704
3705 #delete the privilege mapping from the toServerType and
3706 #then copy the privilege mapping from fromServerType to
3707 #toServerType.
3708 args.serverType = toServerType
3709 res = deleteAllPrivilegeMapping(host, args, session)
3710
3711 data = {"data": []}
3712 res = session.get(url + serverTypeMap[fromServerType] + '/role_map/enumerate', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
3713 #Previously enabled server type has no role map
3714 if (res.status_code != requests.codes.ok):
3715
3716 #fromServerType has no role map; So, no need to copy
3717 #role map to toServerType.
3718 return
3719
3720 objDict = json.loads(res.text)
3721 dataDict = objDict['data']
3722 for key,value in dataDict.items():
3723 data = {"data": [value["GroupName"], value["Privilege"]]}
3724 res = session.post(url + serverTypeMap[toServerType] + '/action/Create', headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
3725
3726 except(requests.exceptions.Timeout):
3727 return(connectionErrHandler(args.json, "Timeout", None))
3728 except(requests.exceptions.ConnectionError) as err:
3729 return connectionErrHandler(args.json, "ConnectionError", err)
3730 return res.text
3731
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003732
Ratan Guptafeee6372018-10-17 23:25:51 +05303733def createPrivilegeMapping(host, args, session):
3734 """
3735 Called by the ldap function. Creates the group and the privilege mapping.
3736
3737 @param host: string, the hostname or IP address of the bmc
3738 @param args: contains additional arguments used by the ldap subcommand
3739 @param session: the active session to use
3740 @param args.json: boolean, if this flag is set to true, the output
3741 will be provided in json format for programmatic consumption
3742 """
3743
Ratan Guptafeee6372018-10-17 23:25:51 +05303744 try:
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003745 if (isRedfishSupport):
3746 url = 'https://'+host+'/xyz/openbmc_project/user/ldap/'
3747
3748 #To maintain the interface compatibility between op930 and op940, the server type has been made
3749 #optional. If the server type is not specified, then create the role-mapper for the currently
3750 #enabled server type.
3751 serverType = args.serverType
3752 if (serverType is None):
3753 serverType = getLDAPTypeEnabled(host,session)
3754 if (serverType is None):
3755 return("LDAP server has not been enabled. Please specify LDAP serverType to proceed further...")
3756
3757 data = {"data": [args.groupName,args.privilege]}
3758 res = session.post(url + serverTypeMap[serverType] + '/action/Create', headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
3759
3760 else:
3761 url = 'https://'+host+'/xyz/openbmc_project/user/ldap/action/Create'
3762 data = {"data": [args.groupName,args.privilege]}
3763 res = session.post(url, headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
3764
Ratan Guptafeee6372018-10-17 23:25:51 +05303765 except(requests.exceptions.Timeout):
3766 return(connectionErrHandler(args.json, "Timeout", None))
3767 except(requests.exceptions.ConnectionError) as err:
3768 return connectionErrHandler(args.json, "ConnectionError", err)
3769 return res.text
3770
3771def listPrivilegeMapping(host, args, session):
3772 """
3773 Called by the ldap function. Lists the group and the privilege mapping.
3774
3775 @param host: string, the hostname or IP address of the bmc
3776 @param args: contains additional arguments used by the ldap subcommand
3777 @param session: the active session to use
3778 @param args.json: boolean, if this flag is set to true, the output
3779 will be provided in json format for programmatic consumption
3780 """
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003781
3782 if (isRedfishSupport):
3783 serverType = args.serverType
3784 if (serverType is None):
3785 serverType = getLDAPTypeEnabled(host,session)
3786 if (serverType is None):
3787 return("LDAP has not been enabled. Please specify LDAP serverType to proceed further...")
3788
3789 url = 'https://'+host+'/xyz/openbmc_project/user/ldap/'+serverTypeMap[serverType]+'/role_map/enumerate'
3790
3791 else:
3792 url = 'https://'+host+'/xyz/openbmc_project/user/ldap/enumerate'
3793
Ratan Guptafeee6372018-10-17 23:25:51 +05303794 data = {"data": []}
3795
3796 try:
Justin Thaler27197622019-01-23 14:42:11 -06003797 res = session.get(url, headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
Ratan Guptafeee6372018-10-17 23:25:51 +05303798 except(requests.exceptions.Timeout):
3799 return(connectionErrHandler(args.json, "Timeout", None))
3800 except(requests.exceptions.ConnectionError) as err:
3801 return connectionErrHandler(args.json, "ConnectionError", err)
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003802
Ratan Guptafeee6372018-10-17 23:25:51 +05303803 return res.text
3804
3805def deletePrivilegeMapping(host, args, session):
3806 """
3807 Called by the ldap function. Deletes the mapping associated with the group.
3808
3809 @param host: string, the hostname or IP address of the bmc
3810 @param args: contains additional arguments used by the ldap subcommand
3811 @param session: the active session to use
3812 @param args.json: boolean, if this flag is set to true, the output
3813 will be provided in json format for programmatic consumption
3814 """
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003815
3816 ldapNameSpaceObjects = listPrivilegeMapping(host, args, session)
Ratan Guptafeee6372018-10-17 23:25:51 +05303817 ldapNameSpaceObjects = json.loads(ldapNameSpaceObjects)["data"]
3818 path = ''
Ratan Guptafeee6372018-10-17 23:25:51 +05303819 data = {"data": []}
3820
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003821 if (isRedfishSupport):
3822 if (args.serverType is None):
3823 serverType = getLDAPTypeEnabled(host,session)
3824 if (serverType is None):
3825 return("LDAP has not been enabled. Please specify LDAP serverType to proceed further...")
3826 # search for the object having the mapping for the given group
3827 for key,value in ldapNameSpaceObjects.items():
3828 if value['GroupName'] == args.groupName:
3829 path = key
3830 break
3831
3832 if path == '':
3833 return "No privilege mapping found for this group."
3834
3835 # delete the object
3836 url = 'https://'+host+path+'/action/Delete'
3837
3838 else:
3839 # not interested in the config objet
3840 ldapNameSpaceObjects.pop('/xyz/openbmc_project/user/ldap/config', None)
3841
3842 # search for the object having the mapping for the given group
3843 for key,value in ldapNameSpaceObjects.items():
3844 if value['GroupName'] == args.groupName:
3845 path = key
3846 break
3847
3848 if path == '':
3849 return "No privilege mapping found for this group."
3850
3851 # delete the object
3852 url = 'https://'+host+path+'/action/delete'
3853
Ratan Guptafeee6372018-10-17 23:25:51 +05303854 try:
Justin Thaler27197622019-01-23 14:42:11 -06003855 res = session.post(url, headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
Ratan Guptafeee6372018-10-17 23:25:51 +05303856 except(requests.exceptions.Timeout):
3857 return(connectionErrHandler(args.json, "Timeout", None))
3858 except(requests.exceptions.ConnectionError) as err:
3859 return connectionErrHandler(args.json, "ConnectionError", err)
3860 return res.text
Ratan Gupta9166cd22018-10-01 18:09:40 +05303861
Sivas SRR78835272018-11-27 05:27:19 -06003862def deleteAllPrivilegeMapping(host, args, session):
3863 """
3864 Called by the ldap function. Deletes all the privilege mapping and group defined.
3865 @param host: string, the hostname or IP address of the bmc
3866 @param args: contains additional arguments used by the ldap subcommand
3867 @param session: the active session to use
3868 @param args.json: boolean, if this flag is set to true, the output
3869 will be provided in json format for programmatic consumption
3870 """
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003871
Sivas SRR78835272018-11-27 05:27:19 -06003872 ldapNameSpaceObjects = listPrivilegeMapping(host, args, session)
3873 ldapNameSpaceObjects = json.loads(ldapNameSpaceObjects)["data"]
3874 path = ''
Sivas SRR78835272018-11-27 05:27:19 -06003875 data = {"data": []}
3876
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003877 if (isRedfishSupport):
3878 if (args.serverType is None):
3879 serverType = getLDAPTypeEnabled(host,session)
3880 if (serverType is None):
3881 return("LDAP has not been enabled. Please specify LDAP serverType to proceed further...")
3882
3883 else:
3884 # Remove the config object.
3885 ldapNameSpaceObjects.pop('/xyz/openbmc_project/user/ldap/config', None)
3886
Sivas SRR78835272018-11-27 05:27:19 -06003887 try:
3888 # search for GroupName property and delete if it is available.
3889 for path in ldapNameSpaceObjects.keys():
3890 # delete the object
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003891 url = 'https://'+host+path+'/action/Delete'
Justin Thaler27197622019-01-23 14:42:11 -06003892 res = session.post(url, headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003893
Sivas SRR78835272018-11-27 05:27:19 -06003894 except(requests.exceptions.Timeout):
3895 return(connectionErrHandler(args.json, "Timeout", None))
3896 except(requests.exceptions.ConnectionError) as err:
3897 return connectionErrHandler(args.json, "ConnectionError", err)
3898 return res.text
3899
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06003900def viewLDAPConfig(host, args, session):
3901 """
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003902 Called by the ldap function. Prints out active LDAP configuration properties
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06003903
3904 @param host: string, the hostname or IP address of the bmc
3905 @param args: contains additional arguments used by the ldap subcommand
3906 args.json: boolean, if this flag is set to true, the output
3907 will be provided in json format for programmatic consumption
3908 @param session: the active session to use
3909 @return returns LDAP's configured properties.
3910 """
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003911
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06003912 try:
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003913 if (isRedfishSupport):
3914
3915 url = "https://"+host+"/xyz/openbmc_project/user/ldap/"
3916
3917 serverTypeEnabled = getLDAPTypeEnabled(host,session)
3918
3919 if (serverTypeEnabled is not None):
3920 data = {"data": []}
3921 res = session.get(url + serverTypeMap[serverTypeEnabled], headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
3922 else:
3923 return("LDAP server has not been enabled...")
3924
3925 else :
3926 url = "https://"+host+"/xyz/openbmc_project/user/ldap/config"
3927 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
3928
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06003929 except(requests.exceptions.Timeout):
3930 return(connectionErrHandler(args.json, "Timeout", None))
3931 except(requests.exceptions.ConnectionError) as err:
3932 return connectionErrHandler(args.json, "ConnectionError", err)
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06003933 if res.status_code == 404:
3934 return "LDAP server config has not been created"
3935 return res.text
3936
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003937def str2bool(v):
3938 if v.lower() in ('yes', 'true', 't', 'y', '1'):
3939 return True
3940 elif v.lower() in ('no', 'false', 'f', 'n', '0'):
3941 return False
3942 else:
3943 raise argparse.ArgumentTypeError('Boolean value expected.')
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06003944
Matt Spinler7d426c22018-09-24 14:42:07 -05003945def localUsers(host, args, session):
3946 """
3947 Enables and disables local BMC users.
3948
3949 @param host: string, the hostname or IP address of the bmc
3950 @param args: contains additional arguments used by the logging sub command
3951 @param session: the active session to use
3952 """
3953
Matt Spinler7d426c22018-09-24 14:42:07 -05003954 url="https://{hostname}/xyz/openbmc_project/user/enumerate".format(hostname=host)
3955 try:
Justin Thaler27197622019-01-23 14:42:11 -06003956 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Matt Spinler7d426c22018-09-24 14:42:07 -05003957 except(requests.exceptions.Timeout):
3958 return(connectionErrHandler(args.json, "Timeout", None))
3959 usersDict = json.loads(res.text)
3960
3961 if not usersDict['data']:
3962 return "No users found"
3963
3964 output = ""
3965 for user in usersDict['data']:
Matt Spinler015adc22018-10-23 14:30:19 -05003966
3967 # Skip LDAP and another non-local users
3968 if 'UserEnabled' not in usersDict['data'][user]:
3969 continue
3970
Matt Spinler7d426c22018-09-24 14:42:07 -05003971 name = user.split('/')[-1]
3972 url = "https://{hostname}{user}/attr/UserEnabled".format(hostname=host, user=user)
3973
3974 if args.local_users == "queryenabled":
3975 try:
Justin Thaler27197622019-01-23 14:42:11 -06003976 res = session.get(url, headers=jsonHeader,verify=False, timeout=baseTimeout)
Matt Spinler7d426c22018-09-24 14:42:07 -05003977 except(requests.exceptions.Timeout):
3978 return(connectionErrHandler(args.json, "Timeout", None))
3979
3980 result = json.loads(res.text)
3981 output += ("User: {name} Enabled: {result}\n").format(name=name, result=result['data'])
3982
3983 elif args.local_users in ["enableall", "disableall"]:
3984 action = ""
3985 if args.local_users == "enableall":
3986 data = '{"data": true}'
3987 action = "Enabling"
3988 else:
3989 data = '{"data": false}'
3990 action = "Disabling"
3991
3992 output += "{action} {name}\n".format(action=action, name=name)
3993
3994 try:
Justin Thaler27197622019-01-23 14:42:11 -06003995 resp = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Matt Spinler7d426c22018-09-24 14:42:07 -05003996 except(requests.exceptions.Timeout):
3997 return connectionErrHandler(args.json, "Timeout", None)
3998 except(requests.exceptions.ConnectionError) as err:
3999 return connectionErrHandler(args.json, "ConnectionError", err)
4000 else:
4001 return "Invalid local users argument"
4002
4003 return output
4004
Marri Devender Rao2c2a5162018-11-05 08:57:11 -06004005def setPassword(host, args, session):
4006 """
4007 Set local user password
4008 @param host: string, the hostname or IP address of the bmc
4009 @param args: contains additional arguments used by the logging sub
4010 command
4011 @param session: the active session to use
4012 @param args.json: boolean, if this flag is set to true, the output
4013 will be provided in json format for programmatic consumption
4014 @return: Session object
4015 """
Marri Devender Rao2c2a5162018-11-05 08:57:11 -06004016 try:
Sunitha Harishc99faba2019-07-19 06:55:22 -05004017 if(isRedfishSupport):
4018 url = "https://" + host + "/redfish/v1/AccountService/Accounts/"+ \
4019 args.user
4020 data = {"Password":args.password}
4021 res = session.patch(url, headers=jsonHeader, json=data,
4022 verify=False, timeout=baseTimeout)
4023 else:
4024 url = "https://" + host + "/xyz/openbmc_project/user/" + args.user + \
4025 "/action/SetPassword"
4026 res = session.post(url, headers=jsonHeader,
Marri Devender Rao2c2a5162018-11-05 08:57:11 -06004027 json={"data": [args.password]}, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06004028 timeout=baseTimeout)
Marri Devender Rao2c2a5162018-11-05 08:57:11 -06004029 except(requests.exceptions.Timeout):
4030 return(connectionErrHandler(args.json, "Timeout", None))
4031 except(requests.exceptions.ConnectionError) as err:
4032 return connectionErrHandler(args.json, "ConnectionError", err)
4033 except(requests.exceptions.RequestException) as err:
4034 return connectionErrHandler(args.json, "RequestException", err)
Sunitha Harishc99faba2019-07-19 06:55:22 -05004035 return res.status_code
Matthew Barth368e83c2019-02-01 13:48:25 -06004036
4037def getThermalZones(host, args, session):
4038 """
4039 Get the available thermal control zones
4040 @param host: string, the hostname or IP address of the bmc
4041 @param args: contains additional arguments used to get the thermal
4042 control zones
4043 @param session: the active session to use
4044 @return: Session object
4045 """
4046 url = "https://" + host + "/xyz/openbmc_project/control/thermal/enumerate"
4047
4048 try:
4049 res = session.get(url, headers=jsonHeader, verify=False, timeout=30)
4050 except(requests.exceptions.Timeout):
4051 return(connectionErrHandler(args.json, "Timeout", None))
4052 except(requests.exceptions.ConnectionError) as err:
4053 return connectionErrHandler(args.json, "ConnectionError", err)
4054 except(requests.exceptions.RequestException) as err:
4055 return connectionErrHandler(args.json, "RequestException", err)
4056
4057 if (res.status_code == 404):
Matthew Barth0939e822019-09-27 15:47:50 -05004058 return "No thermal control zones found"
Matthew Barth368e83c2019-02-01 13:48:25 -06004059
4060 zonesDict = json.loads(res.text)
4061 if not zonesDict['data']:
4062 return "No thermal control zones found"
4063 for zone in zonesDict['data']:
4064 z = ",".join(str(zone.split('/')[-1]) for zone in zonesDict['data'])
4065
4066 return "Zones: [ " + z + " ]"
4067
4068
4069def getThermalMode(host, args, session):
4070 """
4071 Get thermal control mode
4072 @param host: string, the hostname or IP address of the bmc
4073 @param args: contains additional arguments used to get the thermal
4074 control mode
4075 @param session: the active session to use
4076 @param args.zone: the zone to get the mode on
4077 @return: Session object
4078 """
4079 url = "https://" + host + "/xyz/openbmc_project/control/thermal/" + \
4080 args.zone
4081
4082 try:
4083 res = session.get(url, headers=jsonHeader, verify=False, timeout=30)
4084 except(requests.exceptions.Timeout):
4085 return(connectionErrHandler(args.json, "Timeout", None))
4086 except(requests.exceptions.ConnectionError) as err:
4087 return connectionErrHandler(args.json, "ConnectionError", err)
4088 except(requests.exceptions.RequestException) as err:
4089 return connectionErrHandler(args.json, "RequestException", err)
4090
4091 if (res.status_code == 404):
Matthew Barth0939e822019-09-27 15:47:50 -05004092 return "Thermal control zone(" + args.zone + ") not found"
Matthew Barth368e83c2019-02-01 13:48:25 -06004093
4094 propsDict = json.loads(res.text)
4095 if not propsDict['data']:
4096 return "No thermal control properties found on zone(" + args.zone + ")"
4097 curMode = "Current"
4098 supModes = "Supported"
4099 result = "\n"
4100 for prop in propsDict['data']:
4101 if (prop.casefold() == curMode.casefold()):
4102 result += curMode + " Mode: " + propsDict['data'][curMode] + "\n"
4103 if (prop.casefold() == supModes.casefold()):
4104 s = ", ".join(str(sup) for sup in propsDict['data'][supModes])
4105 result += supModes + " Modes: [ " + s + " ]\n"
4106
4107 return result
4108
4109def setThermalMode(host, args, session):
4110 """
4111 Set thermal control mode
4112 @param host: string, the hostname or IP address of the bmc
4113 @param args: contains additional arguments used for setting the thermal
4114 control mode
4115 @param session: the active session to use
4116 @param args.zone: the zone to set the mode on
4117 @param args.mode: the mode to enable
4118 @return: Session object
4119 """
4120 url = "https://" + host + "/xyz/openbmc_project/control/thermal/" + \
4121 args.zone + "/attr/Current"
4122
4123 # Check args.mode against supported modes using `getThermalMode` output
4124 modes = getThermalMode(host, args, session)
4125 modes = os.linesep.join([m for m in modes.splitlines() if m])
4126 modes = modes.replace("\n", ";").strip()
4127 modesDict = dict(m.split(': ') for m in modes.split(';'))
4128 sModes = ''.join(s for s in modesDict['Supported Modes'] if s not in '[ ]')
4129 if args.mode.casefold() not in \
4130 (m.casefold() for m in sModes.split(',')) or not args.mode:
4131 result = ("Unsupported mode('" + args.mode + "') given, " +
4132 "select a supported mode: \n" +
4133 getThermalMode(host, args, session))
4134 return result
4135
4136 data = '{"data":"' + args.mode + '"}'
4137 try:
4138 res = session.get(url, headers=jsonHeader, verify=False, timeout=30)
4139 except(requests.exceptions.Timeout):
4140 return(connectionErrHandler(args.json, "Timeout", None))
4141 except(requests.exceptions.ConnectionError) as err:
4142 return connectionErrHandler(args.json, "ConnectionError", err)
4143 except(requests.exceptions.RequestException) as err:
4144 return connectionErrHandler(args.json, "RequestException", err)
4145
4146 if (data and res.status_code != 404):
4147 try:
4148 res = session.put(url, headers=jsonHeader,
4149 data=data, verify=False,
4150 timeout=30)
4151 except(requests.exceptions.Timeout):
4152 return(connectionErrHandler(args.json, "Timeout", None))
4153 except(requests.exceptions.ConnectionError) as err:
4154 return connectionErrHandler(args.json, "ConnectionError", err)
4155 except(requests.exceptions.RequestException) as err:
4156 return connectionErrHandler(args.json, "RequestException", err)
4157
4158 if res.status_code == 403:
4159 return "The specified thermal control zone(" + args.zone + ")" + \
4160 " does not exist"
4161
4162 return res.text
4163 else:
4164 return "Setting thermal control mode(" + args.mode + ")" + \
Matthew Barth0939e822019-09-27 15:47:50 -05004165 " not supported or operation not available"
Matthew Barth368e83c2019-02-01 13:48:25 -06004166
4167
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004168def createCommandParser():
Justin Thalere412dc22018-01-12 16:28:24 -06004169 """
4170 creates the parser for the command line along with help for each command and subcommand
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004171
Justin Thalere412dc22018-01-12 16:28:24 -06004172 @return: returns the parser for the command line
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004173 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004174 parser = argparse.ArgumentParser(description='Process arguments')
Justin Thalere412dc22018-01-12 16:28:24 -06004175 parser.add_argument("-H", "--host", help='A hostname or IP for the BMC')
4176 parser.add_argument("-U", "--user", help='The username to login with')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004177 group = parser.add_mutually_exclusive_group()
4178 group.add_argument("-A", "--askpw", action='store_true', help='prompt for password')
4179 group.add_argument("-P", "--PW", help='Provide the password in-line')
Joseph Reynoldsa2d54c52019-06-11 22:02:57 -05004180 group.add_argument("-E", "--PWenvvar", action='store_true', help='Get password from envvar OPENBMCTOOL_PASSWORD')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004181 parser.add_argument('-j', '--json', action='store_true', help='output json data only')
4182 parser.add_argument('-t', '--policyTableLoc', help='The location of the policy table to parse alerts')
4183 parser.add_argument('-c', '--CerFormat', action='store_true', help=argparse.SUPPRESS)
4184 parser.add_argument('-T', '--procTime', action='store_true', help= argparse.SUPPRESS)
Justin Thalere412dc22018-01-12 16:28:24 -06004185 parser.add_argument('-V', '--version', action='store_true', help='Display the version number of the openbmctool')
4186 subparsers = parser.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004187
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004188 #fru command
4189 parser_inv = subparsers.add_parser("fru", help='Work with platform inventory')
Justin Thalere412dc22018-01-12 16:28:24 -06004190 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 -05004191 inv_subparser.required = True
4192 #fru print
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004193 inv_print = inv_subparser.add_parser("print", help="prints out a list of all FRUs")
4194 inv_print.set_defaults(func=fruPrint)
4195 #fru list [0....n]
4196 inv_list = inv_subparser.add_parser("list", help="print out details on selected FRUs. Specifying no items will list the entire inventory")
4197 inv_list.add_argument('items', nargs='?', help="print out details on selected FRUs. Specifying no items will list the entire inventory")
4198 inv_list.set_defaults(func=fruList)
4199 #fru status
4200 inv_status = inv_subparser.add_parser("status", help="prints out the status of all FRUs")
Justin Thalere412dc22018-01-12 16:28:24 -06004201 inv_status.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004202 inv_status.set_defaults(func=fruStatus)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004203
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004204 #sensors command
4205 parser_sens = subparsers.add_parser("sensors", help="Work with platform sensors")
Justin Thalere412dc22018-01-12 16:28:24 -06004206 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 -05004207 sens_subparser.required = True
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004208 #sensor print
4209 sens_print= sens_subparser.add_parser('print', help="prints out a list of all Sensors.")
4210 sens_print.set_defaults(func=sensor)
4211 #sensor list[0...n]
4212 sens_list=sens_subparser.add_parser("list", help="Lists all Sensors in the platform. Specify a sensor for full details. ")
4213 sens_list.add_argument("sensNum", nargs='?', help="The Sensor number to get full details on" )
4214 sens_list.set_defaults(func=sensor)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004215
Matthew Barth368e83c2019-02-01 13:48:25 -06004216 #thermal control commands
4217 parser_therm = subparsers.add_parser("thermal", help="Work with thermal control parameters")
4218 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')
4219 #thermal control zones
4220 parser_thermZones = therm_subparser.add_parser("zones", help="Get a list of available thermal control zones")
4221 parser_thermZones.set_defaults(func=getThermalZones)
4222 #thermal control modes
4223 parser_thermMode = therm_subparser.add_parser("modes", help="Work with thermal control modes")
4224 thermMode_sub = parser_thermMode.add_subparsers(title='subactions', description='Work with thermal control modes', help="Work with thermal control modes")
4225 #get thermal control mode
4226 parser_getThermMode = thermMode_sub.add_parser("get", help="Get current and supported thermal control modes")
4227 parser_getThermMode.add_argument('-z', '--zone', required=True, help='Thermal zone to work with')
4228 parser_getThermMode.set_defaults(func=getThermalMode)
4229 #set thermal control mode
4230 parser_setThermMode = thermMode_sub.add_parser("set", help="Set the thermal control mode")
4231 parser_setThermMode.add_argument('-z', '--zone', required=True, help='Thermal zone to work with')
4232 parser_setThermMode.add_argument('-m', '--mode', required=True, help='The supported thermal control mode')
4233 parser_setThermMode.set_defaults(func=setThermalMode)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004234
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004235 #sel command
4236 parser_sel = subparsers.add_parser("sel", help="Work with platform alerts")
Justin Thalere412dc22018-01-12 16:28:24 -06004237 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 -05004238 sel_subparser.required = True
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004239 #sel print
4240 sel_print = sel_subparser.add_parser("print", help="prints out a list of all sels in a condensed list")
4241 sel_print.add_argument('-d', '--devdebug', action='store_true', help=argparse.SUPPRESS)
4242 sel_print.add_argument('-v', '--verbose', action='store_true', help="Changes the output to being very verbose")
4243 sel_print.add_argument('-f', '--fileloc', help='Parse a file instead of the BMC output')
4244 sel_print.set_defaults(func=selPrint)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004245
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004246 #sel list
4247 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")
4248 sel_list.add_argument("selNum", nargs='?', type=int, help="The SEL entry to get details on")
4249 sel_list.set_defaults(func=selList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004250
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004251 sel_get = sel_subparser.add_parser("get", help="Gets the verbose details of a specified SEL entry")
4252 sel_get.add_argument('selNum', type=int, help="the number of the SEL entry to get")
4253 sel_get.set_defaults(func=selList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004254
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004255 sel_clear = sel_subparser.add_parser("clear", help="Clears all entries from the SEL")
4256 sel_clear.set_defaults(func=selClear)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004257
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004258 sel_setResolved = sel_subparser.add_parser("resolve", help="Sets the sel entry to resolved")
Justin Thalere412dc22018-01-12 16:28:24 -06004259 sel_setResolved.add_argument('-n', '--selNum', type=int, help="the number of the SEL entry to resolve")
4260 sel_ResolveAll_sub = sel_setResolved.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
4261 sel_ResolveAll = sel_ResolveAll_sub.add_parser('all', help='Resolve all SEL entries')
4262 sel_ResolveAll.set_defaults(func=selResolveAll)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004263 sel_setResolved.set_defaults(func=selSetResolved)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004264
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004265 parser_chassis = subparsers.add_parser("chassis", help="Work with chassis power and status")
Justin Thalere412dc22018-01-12 16:28:24 -06004266 chas_sub = parser_chassis.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004267
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004268 parser_chassis.add_argument('status', action='store_true', help='Returns the current status of the platform')
4269 parser_chassis.set_defaults(func=chassis)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004270
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004271 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 -06004272 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 -06004273 parser_chasPower.set_defaults(func=chassisPower)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004274
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004275 #control the chassis identify led
4276 parser_chasIdent = chas_sub.add_parser("identify", help="Control the chassis identify led")
4277 parser_chasIdent.add_argument('identcmd', choices=['on', 'off', 'status'], help='The control option for the led: on, off, blink, status')
4278 parser_chasIdent.set_defaults(func=chassisIdent)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004279
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004280 #collect service data
4281 parser_servData = subparsers.add_parser("collect_service_data", help="Collect all bmc data needed for service")
4282 parser_servData.add_argument('-d', '--devdebug', action='store_true', help=argparse.SUPPRESS)
4283 parser_servData.set_defaults(func=collectServiceData)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004284
Justin Thalere412dc22018-01-12 16:28:24 -06004285 #system quick health check
4286 parser_healthChk = subparsers.add_parser("health_check", help="Work with platform sensors")
4287 parser_healthChk.set_defaults(func=healthCheck)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004288
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004289 #work with bmc dumps
4290 parser_bmcdump = subparsers.add_parser("dump", help="Work with bmc dump files")
Justin Thalere412dc22018-01-12 16:28:24 -06004291 bmcDump_sub = parser_bmcdump.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Justin Thaler53bf2f12018-07-16 14:05:32 -05004292 bmcDump_sub.required = True
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004293 dump_Create = bmcDump_sub.add_parser('create', help="Create a bmc dump")
4294 dump_Create.set_defaults(func=bmcDumpCreate)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004295
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004296 dump_list = bmcDump_sub.add_parser('list', help="list all bmc dump files")
4297 dump_list.set_defaults(func=bmcDumpList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004298
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004299 parserdumpdelete = bmcDump_sub.add_parser('delete', help="Delete bmc dump files")
4300 parserdumpdelete.add_argument("-n", "--dumpNum", nargs='*', type=int, help="The Dump entry to delete")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004301 parserdumpdelete.set_defaults(func=bmcDumpDelete)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004302
Justin Thalere412dc22018-01-12 16:28:24 -06004303 bmcDumpDelsub = parserdumpdelete.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004304 deleteAllDumps = bmcDumpDelsub.add_parser('all', help='Delete all bmc dump files')
4305 deleteAllDumps.set_defaults(func=bmcDumpDeleteAll)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004306
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004307 parser_dumpretrieve = bmcDump_sub.add_parser('retrieve', help='Retrieve a dump file')
4308 parser_dumpretrieve.add_argument("dumpNum", type=int, help="The Dump entry to delete")
4309 parser_dumpretrieve.add_argument("-s", "--dumpSaveLoc", help="The location to save the bmc dump file")
4310 parser_dumpretrieve.set_defaults(func=bmcDumpRetrieve)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004311
Justin Thaler22b1bb52018-03-15 13:31:32 -05004312 #bmc command for reseting the bmc
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004313 parser_bmc = subparsers.add_parser('bmc', help="Work with the bmc")
Justin Thalere412dc22018-01-12 16:28:24 -06004314 bmc_sub = parser_bmc.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004315 parser_BMCReset = bmc_sub.add_parser('reset', help='Reset the bmc' )
4316 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 -06004317 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.")
4318 parser_bmc.set_defaults(func=bmc)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004319
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004320 #add alias to the bmc command
4321 parser_mc = subparsers.add_parser('mc', help="Work with the management controller")
Justin Thalere412dc22018-01-12 16:28:24 -06004322 mc_sub = parser_mc.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004323 parser_MCReset = mc_sub.add_parser('reset', help='Reset the bmc' )
4324 parser_MCReset.add_argument('type', choices=['warm','cold'], help="Reboot the BMC")
4325 #parser_MCReset.add_argument('cold', action='store_true', help="Reboot the BMC and CLEAR the configuration")
4326 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 -06004327 parser_MCReset.set_defaults(func=bmcReset)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004328 parser_mc.set_defaults(func=bmc)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004329
Justin Thalere412dc22018-01-12 16:28:24 -06004330 #gard clear
4331 parser_gc = subparsers.add_parser("gardclear", help="Used to clear gard records")
4332 parser_gc.set_defaults(func=gardClear)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004333
Justin Thalere412dc22018-01-12 16:28:24 -06004334 #firmware_flash
4335 parser_fw = subparsers.add_parser("firmware", help="Work with the system firmware")
4336 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 -05004337 fwflash_subproc.required = True
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004338
Justin Thalere412dc22018-01-12 16:28:24 -06004339 fwflash = fwflash_subproc.add_parser('flash', help="Flash the system firmware")
4340 fwflash.add_argument('type', choices=['bmc', 'pnor'], help="image type to flash")
4341 fwflash.add_argument('-f', '--fileloc', required=True, help="The absolute path to the firmware image")
4342 fwflash.set_defaults(func=fwFlash)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004343
Justin Thaler22b1bb52018-03-15 13:31:32 -05004344 fwActivate = fwflash_subproc.add_parser('activate', help="Activate existing image on the bmc")
Justin Thalere412dc22018-01-12 16:28:24 -06004345 fwActivate.add_argument('imageID', help="The image ID to activate from the firmware list. Ex: 63c95399")
4346 fwActivate.set_defaults(func=activateFWImage)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004347
Justin Thaler22b1bb52018-03-15 13:31:32 -05004348 fwActivateStatus = fwflash_subproc.add_parser('activation_status', help="Check Status of activations")
4349 fwActivateStatus.set_defaults(func=activateStatus)
4350
Justin Thaler3d71d402018-07-24 14:35:39 -05004351 fwList = fwflash_subproc.add_parser('list', help="List all of the installed firmware")
4352 fwList.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
4353 fwList.set_defaults(func=firmwareList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004354
Justin Thaler3d71d402018-07-24 14:35:39 -05004355 fwprint = fwflash_subproc.add_parser('print', help="List all of the installed firmware")
4356 fwprint.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
4357 fwprint.set_defaults(func=firmwareList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004358
Adriana Kobylak5af2fad2018-11-08 12:33:43 -06004359 fwDelete = fwflash_subproc.add_parser('delete', help="Delete an existing firmware version")
4360 fwDelete.add_argument('versionID', help="The version ID to delete from the firmware list. Ex: 63c95399")
4361 fwDelete.set_defaults(func=deleteFWVersion)
4362
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05004363 #logging
4364 parser_logging = subparsers.add_parser("logging", help="logging controls")
4365 logging_sub = parser_logging.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004366
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05004367 #turn rest api logging on/off
4368 parser_rest_logging = logging_sub.add_parser("rest_api", help="turn rest api logging on/off")
4369 parser_rest_logging.add_argument('rest_logging', choices=['on', 'off'], help='The control option for rest logging: on, off')
4370 parser_rest_logging.set_defaults(func=restLogging)
Deepak Kodihalli02d53282018-09-18 06:53:31 -05004371
4372 #remote logging
4373 parser_remote_logging = logging_sub.add_parser("remote_logging", help="Remote logging (rsyslog) commands")
4374 parser_remote_logging.add_argument('remote_logging', choices=['view', 'disable'], help='Remote logging (rsyslog) commands')
4375 parser_remote_logging.set_defaults(func=remoteLogging)
4376
4377 #configure remote logging
4378 parser_remote_logging_config = logging_sub.add_parser("remote_logging_config", help="Configure remote logging (rsyslog)")
4379 parser_remote_logging_config.add_argument("-a", "--address", required=True, help="Set IP address of rsyslog server")
4380 parser_remote_logging_config.add_argument("-p", "--port", required=True, type=int, help="Set Port of rsyslog server")
4381 parser_remote_logging_config.set_defaults(func=remoteLoggingConfig)
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05004382
4383 #certificate management
4384 parser_cert = subparsers.add_parser("certificate", help="Certificate management")
4385 certMgmt_subproc = parser_cert.add_subparsers(title='subcommands', description='valid certificate commands', help='sub-command help', dest='command')
4386
4387 certUpdate = certMgmt_subproc.add_parser('update', help="Update the certificate")
4388 certUpdate.add_argument('type', choices=['server', 'client', 'authority'], help="certificate type to update")
4389 certUpdate.add_argument('service', choices=['https', 'ldap'], help="Service to update")
4390 certUpdate.add_argument('-f', '--fileloc', required=True, help="The absolute path to the certificate file")
4391 certUpdate.set_defaults(func=certificateUpdate)
4392
4393 certDelete = certMgmt_subproc.add_parser('delete', help="Delete the certificate")
4394 certDelete.add_argument('type', choices=['server', 'client', 'authority'], help="certificate type to delete")
4395 certDelete.add_argument('service', choices=['https', 'ldap'], help="Service to delete the certificate")
4396 certDelete.set_defaults(func=certificateDelete)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004397
Marri Devender Raodfe81ad2019-07-01 05:38:09 -05004398 certReplace = certMgmt_subproc.add_parser('replace',
4399 help="Replace the certificate")
4400 certReplace.add_argument('type', choices=['server', 'client', 'authority'],
4401 help="certificate type to replace")
4402 certReplace.add_argument('service', choices=['https', 'ldap'],
4403 help="Service to replace the certificate")
4404 certReplace.add_argument('-f', '--fileloc', required=True,
4405 help="The absolute path to the certificate file")
4406 certReplace.set_defaults(func=certificateReplace)
4407
Marri Devender Rao34646402019-07-01 05:46:03 -05004408 certDisplay = certMgmt_subproc.add_parser('display',
4409 help="Print the certificate")
4410 certDisplay.add_argument('type', choices=['server', 'client', 'authority'],
4411 help="certificate type to display")
4412 certDisplay.set_defaults(func=certificateDisplay)
4413
Marri Devender Raoa208ff82019-07-01 05:51:27 -05004414 certList = certMgmt_subproc.add_parser('list',
4415 help="Certificate list")
4416 certList.set_defaults(func=certificateList)
4417
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05004418 certGenerateCSR = certMgmt_subproc.add_parser('generatecsr', help="Generate CSR")
4419 certGenerateCSR.add_argument('type', choices=['server', 'client', 'authority'],
4420 help="Generate CSR")
4421 certGenerateCSR.add_argument('city',
4422 help="The city or locality of the organization making the request")
4423 certGenerateCSR.add_argument('commonName',
4424 help="The fully qualified domain name of the component that is being secured.")
4425 certGenerateCSR.add_argument('country',
4426 help="The country of the organization making the request")
4427 certGenerateCSR.add_argument('organization',
4428 help="The name of the organization making the request.")
4429 certGenerateCSR.add_argument('organizationUnit',
4430 help="The name of the unit or division of the organization making the request.")
4431 certGenerateCSR.add_argument('state',
4432 help="The state, province, or region of the organization making the request.")
4433 certGenerateCSR.add_argument('keyPairAlgorithm', choices=['RSA', 'EC'],
4434 help="The type of key pair for use with signing algorithms.")
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05004435 certGenerateCSR.add_argument('keyCurveId',
4436 help="The curve ID to be used with the key, if needed based on the value of the 'KeyPairAlgorithm' parameter.")
4437 certGenerateCSR.add_argument('contactPerson',
4438 help="The name of the user making the request")
4439 certGenerateCSR.add_argument('email',
4440 help="The email address of the contact within the organization")
4441 certGenerateCSR.add_argument('alternativeNames',
4442 help="Additional hostnames of the component that is being secured")
4443 certGenerateCSR.add_argument('givenname',
4444 help="The given name of the user making the request")
4445 certGenerateCSR.add_argument('surname',
4446 help="The surname of the user making the request")
4447 certGenerateCSR.add_argument('unstructuredname',
4448 help="he unstructured name of the subject")
4449 certGenerateCSR.add_argument('initials',
4450 help="The initials of the user making the request")
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05004451 certGenerateCSR.set_defaults(func=certificateGenerateCSR)
4452
Matt Spinler7d426c22018-09-24 14:42:07 -05004453 # local users
4454 parser_users = subparsers.add_parser("local_users", help="Work with local users")
4455 parser_users.add_argument('local_users', choices=['disableall','enableall', 'queryenabled'], help="Disable, enable or query local user accounts")
4456 parser_users.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
4457 parser_users.set_defaults(func=localUsers)
4458
Ratan Gupta9166cd22018-10-01 18:09:40 +05304459 #LDAP
4460 parser_ldap = subparsers.add_parser("ldap", help="LDAP controls")
4461 ldap_sub = parser_ldap.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
4462
4463 #configure and enable LDAP
4464 parser_ldap_config = ldap_sub.add_parser("enable", help="Configure and enables the LDAP")
4465 parser_ldap_config.add_argument("-a", "--uri", required=True, help="Set LDAP server URI")
4466 parser_ldap_config.add_argument("-B", "--bindDN", required=True, help="Set the bind DN of the LDAP server")
4467 parser_ldap_config.add_argument("-b", "--baseDN", required=True, help="Set the base DN of the LDAP server")
4468 parser_ldap_config.add_argument("-p", "--bindPassword", required=True, help="Set the bind password of the LDAP server")
4469 parser_ldap_config.add_argument("-S", "--scope", choices=['sub','one', 'base'],
4470 help='Specifies the search scope:subtree, one level or base object.')
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004471 parser_ldap_config.add_argument("-t", "--serverType", required=True, choices=['ActiveDirectory','OpenLDAP'],
Ratan Gupta9166cd22018-10-01 18:09:40 +05304472 help='Specifies the configured server is ActiveDirectory(AD) or OpenLdap')
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004473 parser_ldap_config.add_argument("-g","--groupAttrName", required=False, default='', help="Group Attribute Name")
4474 parser_ldap_config.add_argument("-u","--userAttrName", required=False, default='', help="User Attribute Name")
4475 parser_ldap_config.set_defaults(func=enableLDAPConfig)
Ratan Gupta9166cd22018-10-01 18:09:40 +05304476
4477 # disable LDAP
4478 parser_disable_ldap = ldap_sub.add_parser("disable", help="disables the LDAP")
4479 parser_disable_ldap.set_defaults(func=disableLDAP)
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06004480 # view-config
4481 parser_ldap_config = \
4482 ldap_sub.add_parser("view-config", help="prints out a list of all \
4483 LDAPS's configured properties")
4484 parser_ldap_config.set_defaults(func=viewLDAPConfig)
Ratan Gupta9166cd22018-10-01 18:09:40 +05304485
Ratan Guptafeee6372018-10-17 23:25:51 +05304486 #create group privilege mapping
4487 parser_ldap_mapper = ldap_sub.add_parser("privilege-mapper", help="LDAP group privilege controls")
4488 parser_ldap_mapper_sub = parser_ldap_mapper.add_subparsers(title='subcommands', description='valid subcommands',
4489 help="sub-command help", dest='command')
4490
4491 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 -05004492 parser_ldap_mapper_create.add_argument("-t", "--serverType", choices=['ActiveDirectory','OpenLDAP'],
4493 help='Specifies the configured server is ActiveDirectory(AD) or OpenLdap')
Ratan Guptafeee6372018-10-17 23:25:51 +05304494 parser_ldap_mapper_create.add_argument("-g","--groupName",required=True,help="Group Name")
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004495 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 +05304496 parser_ldap_mapper_create.set_defaults(func=createPrivilegeMapping)
4497
4498 #list group privilege mapping
4499 parser_ldap_mapper_list = parser_ldap_mapper_sub.add_parser("list",help="List privilege mapping")
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004500 parser_ldap_mapper_list.add_argument("-t", "--serverType", choices=['ActiveDirectory','OpenLDAP'],
4501 help='Specifies the configured server is ActiveDirectory(AD) or OpenLdap')
Ratan Guptafeee6372018-10-17 23:25:51 +05304502 parser_ldap_mapper_list.set_defaults(func=listPrivilegeMapping)
4503
4504 #delete group privilege mapping
4505 parser_ldap_mapper_delete = parser_ldap_mapper_sub.add_parser("delete",help="Delete privilege mapping")
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004506 parser_ldap_mapper_delete.add_argument("-t", "--serverType", choices=['ActiveDirectory','OpenLDAP'],
4507 help='Specifies the configured server is ActiveDirectory(AD) or OpenLdap')
Ratan Guptafeee6372018-10-17 23:25:51 +05304508 parser_ldap_mapper_delete.add_argument("-g","--groupName",required=True,help="Group Name")
4509 parser_ldap_mapper_delete.set_defaults(func=deletePrivilegeMapping)
4510
Sivas SRR78835272018-11-27 05:27:19 -06004511 #deleteAll group privilege mapping
4512 parser_ldap_mapper_delete = parser_ldap_mapper_sub.add_parser("purge",help="Delete All privilege mapping")
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004513 parser_ldap_mapper_delete.add_argument("-t", "--serverType", choices=['ActiveDirectory','OpenLDAP'],
4514 help='Specifies the configured server is ActiveDirectory(AD) or OpenLdap')
Sivas SRR78835272018-11-27 05:27:19 -06004515 parser_ldap_mapper_delete.set_defaults(func=deleteAllPrivilegeMapping)
4516
Marri Devender Rao2c2a5162018-11-05 08:57:11 -06004517 # set local user password
4518 parser_set_password = subparsers.add_parser("set_password",
4519 help="Set password of local user")
4520 parser_set_password.add_argument( "-p", "--password", required=True,
4521 help="Password of local user")
4522 parser_set_password.set_defaults(func=setPassword)
4523
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004524 # network
4525 parser_nw = subparsers.add_parser("network", help="network controls")
4526 nw_sub = parser_nw.add_subparsers(title='subcommands',
4527 description='valid subcommands',
4528 help="sub-command help",
4529 dest='command')
4530
4531 # enable DHCP
4532 parser_enable_dhcp = nw_sub.add_parser("enableDHCP",
4533 help="enables the DHCP on given "
4534 "Interface")
4535 parser_enable_dhcp.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004536 help="Name of the ethernet interface(it can"
4537 "be obtained by the "
4538 "command:network view-config)"
4539 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004540 parser_enable_dhcp.set_defaults(func=enableDHCP)
4541
4542 # disable DHCP
4543 parser_disable_dhcp = nw_sub.add_parser("disableDHCP",
4544 help="disables the DHCP on given "
4545 "Interface")
4546 parser_disable_dhcp.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004547 help="Name of the ethernet interface(it can"
4548 "be obtained by the "
4549 "command:network view-config)"
4550 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004551 parser_disable_dhcp.set_defaults(func=disableDHCP)
4552
4553 # get HostName
4554 parser_gethostname = nw_sub.add_parser("getHostName",
4555 help="prints out HostName")
4556 parser_gethostname.set_defaults(func=getHostname)
4557
4558 # set HostName
4559 parser_sethostname = nw_sub.add_parser("setHostName", help="sets HostName")
4560 parser_sethostname.add_argument("-H", "--HostName", required=True,
4561 help="A HostName for the BMC")
4562 parser_sethostname.set_defaults(func=setHostname)
4563
4564 # get domainname
4565 parser_getdomainname = nw_sub.add_parser("getDomainName",
4566 help="prints out DomainName of "
4567 "given Interface")
4568 parser_getdomainname.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004569 help="Name of the ethernet interface(it "
4570 "can be obtained by the "
4571 "command:network view-config)"
4572 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004573 parser_getdomainname.set_defaults(func=getDomainName)
4574
4575 # set domainname
4576 parser_setdomainname = nw_sub.add_parser("setDomainName",
4577 help="sets DomainName of given "
4578 "Interface")
4579 parser_setdomainname.add_argument("-D", "--DomainName", required=True,
4580 help="Ex: DomainName=Domain1,Domain2,...")
4581 parser_setdomainname.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004582 help="Name of the ethernet interface(it "
4583 "can be obtained by the "
4584 "command:network view-config)"
4585 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004586 parser_setdomainname.set_defaults(func=setDomainName)
4587
4588 # get MACAddress
4589 parser_getmacaddress = nw_sub.add_parser("getMACAddress",
4590 help="prints out MACAddress the "
4591 "given Interface")
4592 parser_getmacaddress.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004593 help="Name of the ethernet interface(it "
4594 "can be obtained by the "
4595 "command:network view-config)"
4596 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004597 parser_getmacaddress.set_defaults(func=getMACAddress)
4598
4599 # set MACAddress
4600 parser_setmacaddress = nw_sub.add_parser("setMACAddress",
4601 help="sets MACAddress")
4602 parser_setmacaddress.add_argument("-MA", "--MACAddress", required=True,
4603 help="A MACAddress for the given "
4604 "Interface")
4605 parser_setmacaddress.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004606 help="Name of the ethernet interface(it can"
4607 "be obtained by the "
4608 "command:network view-config)"
4609 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004610 parser_setmacaddress.set_defaults(func=setMACAddress)
4611
4612 # get DefaultGW
4613 parser_getdefaultgw = nw_sub.add_parser("getDefaultGW",
4614 help="prints out DefaultGateway "
4615 "the BMC")
4616 parser_getdefaultgw.set_defaults(func=getDefaultGateway)
4617
4618 # set DefaultGW
4619 parser_setdefaultgw = nw_sub.add_parser("setDefaultGW",
4620 help="sets DefaultGW")
4621 parser_setdefaultgw.add_argument("-GW", "--DefaultGW", required=True,
4622 help="A DefaultGateway for the BMC")
4623 parser_setdefaultgw.set_defaults(func=setDefaultGateway)
4624
4625 # view network Config
4626 parser_ldap_config = nw_sub.add_parser("view-config", help="prints out a "
4627 "list of all network's configured "
4628 "properties")
4629 parser_ldap_config.set_defaults(func=viewNWConfig)
4630
4631 # get DNS
4632 parser_getDNS = nw_sub.add_parser("getDNS",
4633 help="prints out DNS servers on the "
4634 "given interface")
4635 parser_getDNS.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004636 help="Name of the ethernet interface(it can"
4637 "be obtained by the "
4638 "command:network view-config)"
4639 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004640 parser_getDNS.set_defaults(func=getDNS)
4641
4642 # set DNS
4643 parser_setDNS = nw_sub.add_parser("setDNS",
4644 help="sets DNS servers on the given "
4645 "interface")
4646 parser_setDNS.add_argument("-d", "--DNSServers", required=True,
4647 help="Ex: DNSSERVERS=DNS1,DNS2,...")
4648 parser_setDNS.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004649 help="Name of the ethernet interface(it can"
4650 "be obtained by the "
4651 "command:network view-config)"
4652 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004653 parser_setDNS.set_defaults(func=setDNS)
4654
4655 # get NTP
4656 parser_getNTP = nw_sub.add_parser("getNTP",
4657 help="prints out NTP servers on the "
4658 "given interface")
4659 parser_getNTP.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004660 help="Name of the ethernet interface(it can"
4661 "be obtained by the "
4662 "command:network view-config)"
4663 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004664 parser_getNTP.set_defaults(func=getNTP)
4665
4666 # set NTP
4667 parser_setNTP = nw_sub.add_parser("setNTP",
4668 help="sets NTP servers on the given "
4669 "interface")
4670 parser_setNTP.add_argument("-N", "--NTPServers", required=True,
4671 help="Ex: NTPSERVERS=NTP1,NTP2,...")
4672 parser_setNTP.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004673 help="Name of the ethernet interface(it can"
4674 "be obtained by the "
4675 "command:network view-config)"
4676 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004677 parser_setNTP.set_defaults(func=setNTP)
4678
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004679 # configure IP
4680 parser_ip_config = nw_sub.add_parser("addIP", help="Sets IP address to"
4681 "given interface")
4682 parser_ip_config.add_argument("-a", "--address", required=True,
4683 help="IP address of given interface")
4684 parser_ip_config.add_argument("-gw", "--gateway", required=False, default='',
4685 help="The gateway for given interface")
4686 parser_ip_config.add_argument("-l", "--prefixLength", required=True,
4687 help="The prefixLength of IP address")
Sunitha Harish0baf6372019-07-31 03:59:03 -05004688 parser_ip_config.add_argument("-p", "--type", required=True,
4689 choices=['ipv4', 'ipv6'],
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004690 help="The protocol type of the given"
4691 "IP address")
4692 parser_ip_config.add_argument("-I", "--Interface", required=True,
4693 help="Name of the ethernet interface(it can"
4694 "be obtained by the "
4695 "command:network view-config)"
4696 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
4697 parser_ip_config.set_defaults(func=addIP)
4698
4699 # getIP
4700 parser_getIP = nw_sub.add_parser("getIP", help="prints out IP address"
4701 "of given interface")
4702 parser_getIP.add_argument("-I", "--Interface", required=True,
4703 help="Name of the ethernet interface(it can"
4704 "be obtained by the command:network view-config)"
4705 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
4706 parser_getIP.set_defaults(func=getIP)
4707
4708 # rmIP
4709 parser_rmIP = nw_sub.add_parser("rmIP", help="deletes IP address"
4710 "of given interface")
4711 parser_rmIP.add_argument("-a", "--address", required=True,
4712 help="IP address to remove form given Interface")
4713 parser_rmIP.add_argument("-I", "--Interface", required=True,
4714 help="Name of the ethernet interface(it can"
4715 "be obtained by the command:network view-config)"
4716 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
4717 parser_rmIP.set_defaults(func=deleteIP)
4718
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004719 # add VLAN
4720 parser_create_vlan = nw_sub.add_parser("addVLAN", help="enables VLAN "
4721 "on given interface with given "
4722 "VLAN Identifier")
4723 parser_create_vlan.add_argument("-I", "--Interface", required=True,
4724 choices=['eth0', 'eth1'],
4725 help="Name of the ethernet interface")
4726 parser_create_vlan.add_argument("-n", "--Identifier", required=True,
4727 help="VLAN Identifier")
4728 parser_create_vlan.set_defaults(func=addVLAN)
4729
4730 # delete VLAN
4731 parser_delete_vlan = nw_sub.add_parser("deleteVLAN", help="disables VLAN "
4732 "on given interface with given "
4733 "VLAN Identifier")
4734 parser_delete_vlan.add_argument("-I", "--Interface", required=True,
4735 help="Name of the ethernet interface(it can"
4736 "be obtained by the "
4737 "command:network view-config)"
4738 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
4739 parser_delete_vlan.set_defaults(func=deleteVLAN)
4740
4741 # viewDHCPConfig
4742 parser_viewDHCPConfig = nw_sub.add_parser("viewDHCPConfig",
4743 help="Shows DHCP configured "
4744 "Properties")
4745 parser_viewDHCPConfig.set_defaults(func=viewDHCPConfig)
4746
4747 # configureDHCP
4748 parser_configDHCP = nw_sub.add_parser("configureDHCP",
4749 help="Configures/updates DHCP "
4750 "Properties")
4751 parser_configDHCP.add_argument("-d", "--DNSEnabled", type=str2bool,
4752 required=True, help="Sets DNSEnabled property")
4753 parser_configDHCP.add_argument("-n", "--HostNameEnabled", type=str2bool,
4754 required=True,
4755 help="Sets HostNameEnabled property")
4756 parser_configDHCP.add_argument("-t", "--NTPEnabled", type=str2bool,
4757 required=True,
4758 help="Sets NTPEnabled property")
4759 parser_configDHCP.add_argument("-s", "--SendHostNameEnabled", type=str2bool,
4760 required=True,
4761 help="Sets SendHostNameEnabled property")
4762 parser_configDHCP.set_defaults(func=configureDHCP)
4763
4764 # network factory reset
4765 parser_nw_reset = nw_sub.add_parser("nwReset",
4766 help="Resets networks setting to "
4767 "factory defaults. "
4768 "note:Reset settings will be applied "
4769 "after BMC reboot")
4770 parser_nw_reset.set_defaults(func=nwReset)
4771
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004772 return parser
4773
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004774def main(argv=None):
Justin Thalere412dc22018-01-12 16:28:24 -06004775 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004776 main function for running the command line utility as a sub application
4777 """
4778 global toolVersion
Matthew Barth0939e822019-09-27 15:47:50 -05004779 toolVersion = "1.17"
Sunitha Harishc99faba2019-07-19 06:55:22 -05004780 global isRedfishSupport
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004781
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004782 parser = createCommandParser()
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004783 args = parser.parse_args(argv)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004784
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004785 totTimeStart = int(round(time.time()*1000))
4786
4787 if(sys.version_info < (3,0)):
4788 urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
4789 if sys.version_info >= (3,0):
4790 requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)
Justin Thalere412dc22018-01-12 16:28:24 -06004791 if (args.version):
Justin Thaler22b1bb52018-03-15 13:31:32 -05004792 print("Version: "+ toolVersion)
Justin Thalere412dc22018-01-12 16:28:24 -06004793 sys.exit(0)
4794 if (hasattr(args, 'fileloc') and args.fileloc is not None and 'print' in args.command):
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004795 mysess = None
Justin Thalere412dc22018-01-12 16:28:24 -06004796 print(selPrint('N/A', args, mysess))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004797 else:
Justin Thalere412dc22018-01-12 16:28:24 -06004798 if(hasattr(args, 'host') and hasattr(args,'user')):
4799 if (args.askpw):
4800 pw = getpass.getpass()
4801 elif(args.PW is not None):
4802 pw = args.PW
Joseph Reynoldsa2d54c52019-06-11 22:02:57 -05004803 elif(args.PWenvvar):
4804 pw = os.environ['OPENBMCTOOL_PASSWORD']
Justin Thalere412dc22018-01-12 16:28:24 -06004805 else:
4806 print("You must specify a password")
4807 sys.exit()
4808 logintimeStart = int(round(time.time()*1000))
4809 mysess = login(args.host, args.user, pw, args.json)
Sunitha Harish336cda22019-07-23 02:02:52 -05004810 if(mysess == None):
4811 print("Login Failed!")
4812 sys.exit()
Justin Thalera9415b42018-05-25 19:40:13 -05004813 if(sys.version_info < (3,0)):
4814 if isinstance(mysess, basestring):
4815 print(mysess)
4816 sys.exit(1)
4817 elif sys.version_info >= (3,0):
4818 if isinstance(mysess, str):
4819 print(mysess)
4820 sys.exit(1)
Justin Thalere412dc22018-01-12 16:28:24 -06004821 logintimeStop = int(round(time.time()*1000))
Sunitha Harishc99faba2019-07-19 06:55:22 -05004822 isRedfishSupport = redfishSupportPresent(args.host,mysess)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004823 commandTimeStart = int(round(time.time()*1000))
Justin Thalere412dc22018-01-12 16:28:24 -06004824 output = args.func(args.host, args, mysess)
4825 commandTimeStop = int(round(time.time()*1000))
Justin Thaler761484a2019-03-26 19:20:23 -05004826 if isinstance(output, dict):
4827 print(json.dumps(output, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False))
4828 else:
4829 print(output)
Justin Thalere412dc22018-01-12 16:28:24 -06004830 if (mysess is not None):
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004831 logout(args.host, args.user, pw, mysess, args.json)
4832 if(args.procTime):
Justin Thalere412dc22018-01-12 16:28:24 -06004833 print("Total time: " + str(int(round(time.time()*1000))- totTimeStart))
4834 print("loginTime: " + str(logintimeStop - logintimeStart))
4835 print("command Time: " + str(commandTimeStop - commandTimeStart))
4836 else:
Joseph Reynoldsa2d54c52019-06-11 22:02:57 -05004837 print("usage:\n"
4838 " OPENBMCTOOL_PASSWORD=secret # if using -E\n"
4839 " openbmctool.py [-h] -H HOST -U USER {-A | -P PW | -E} [-j]\n" +
Justin Thalere412dc22018-01-12 16:28:24 -06004840 "\t[-t POLICYTABLELOC] [-V]\n" +
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05004841 "\t{fru,sensors,sel,chassis,collect_service_data, \
4842 health_check,dump,bmc,mc,gardclear,firmware,logging}\n" +
Justin Thalere412dc22018-01-12 16:28:24 -06004843 "\t...\n" +
4844 "openbmctool.py: error: the following arguments are required: -H/--host, -U/--user")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004845 sys.exit()
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004846
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004847if __name__ == '__main__':
Justin Thalere412dc22018-01-12 16:28:24 -06004848 """
4849 main function when called from the command line
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004850
4851 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004852 import sys
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004853
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004854 isTTY = sys.stdout.isatty()
4855 assert sys.version_info >= (2,7)
4856 main()