blob: 2d3fb3d67408e8a2865b4a3fe4e0a9466f65ae5a [file] [log] [blame]
Justin Thalerb8807ce2018-05-25 19:16:20 -05001#!/usr/bin/python3
Justin Thalere412dc22018-01-12 16:28:24 -06002"""
Joseph Reynoldsa2d54c52019-06-11 22:02:57 -05003 Copyright 2017,2019 IBM Corporation
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004
Justin Thalere412dc22018-01-12 16:28:24 -06005 Licensed under the Apache License, Version 2.0 (the "License");
6 you may not use this file except in compliance with the License.
7 You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16"""
Justin Thalerf9aee3e2017-12-05 12:11:09 -060017import argparse
18import requests
19import getpass
20import json
21import os
22import urllib3
23import time, datetime
Justin Thalerf9aee3e2017-12-05 12:11:09 -060024import binascii
25import subprocess
26import platform
27import zipfile
Justin Thaler22b1bb52018-03-15 13:31:32 -050028import tarfile
29import tempfile
30import hashlib
Justin Thalera6b5df72018-07-16 11:10:07 -050031import re
Justin Thaler24d4efa2018-11-08 22:48:10 -060032import uuid
Justin Thalerf9aee3e2017-12-05 12:11:09 -060033
Matt Spinler220c3c42019-01-04 15:09:29 -060034jsonHeader = {'Content-Type' : 'application/json'}
35xAuthHeader = {}
Justin Thaler27197622019-01-23 14:42:11 -060036baseTimeout = 60
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -050037serverTypeMap = {
38 'ActiveDirectory' : 'active_directory',
39 'OpenLDAP' : 'openldap'
40 }
Matt Spinler220c3c42019-01-04 15:09:29 -060041
Justin Thalerf9aee3e2017-12-05 12:11:09 -060042def hilight(textToColor, color, bold):
Justin Thalere412dc22018-01-12 16:28:24 -060043 """
44 Used to add highlights to various text for displaying in a terminal
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -060045
Justin Thalere412dc22018-01-12 16:28:24 -060046 @param textToColor: string, the text to be colored
47 @param color: string, used to color the text red or green
48 @param bold: boolean, used to bold the textToColor
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -060049 @return: Buffered reader containing the modified string.
50 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -060051 if(sys.platform.__contains__("win")):
52 if(color == "red"):
53 os.system('color 04')
54 elif(color == "green"):
55 os.system('color 02')
56 else:
57 os.system('color') #reset to default
58 return textToColor
59 else:
60 attr = []
61 if(color == "red"):
62 attr.append('31')
63 elif(color == "green"):
64 attr.append('32')
65 else:
66 attr.append('0')
67 if bold:
68 attr.append('1')
69 else:
70 attr.append('0')
71 return '\x1b[%sm%s\x1b[0m' % (';'.join(attr),textToColor)
72
Justin Thalerf9aee3e2017-12-05 12:11:09 -060073def connectionErrHandler(jsonFormat, errorStr, err):
Justin Thalere412dc22018-01-12 16:28:24 -060074 """
75 Error handler various connection errors to bmcs
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -060076
77 @param jsonFormat: boolean, used to output in json format with an error code.
Justin Thalere412dc22018-01-12 16:28:24 -060078 @param errorStr: string, used to color the text red or green
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -060079 @param err: string, the text from the exception
80 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -060081 if errorStr == "Timeout":
82 if not jsonFormat:
83 return("FQPSPIN0000M: Connection timed out. Ensure you have network connectivity to the bmc")
84 else:
Justin Thaler115bca72018-05-25 19:29:08 -050085 conerror = {}
86 conerror['CommonEventID'] = 'FQPSPIN0000M'
87 conerror['sensor']="N/A"
88 conerror['state']="N/A"
89 conerror['additionalDetails'] = "N/A"
90 conerror['Message']="Connection timed out. Ensure you have network connectivity to the BMC"
91 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."
92 conerror['Serviceable']="Yes"
93 conerror['CallHomeCandidate']= "No"
94 conerror['Severity'] = "Critical"
95 conerror['EventType'] = "Communication Failure/Timeout"
96 conerror['VMMigrationFlag'] = "Yes"
97 conerror["AffectedSubsystem"] = "Interconnect (Networking)"
98 conerror["timestamp"] = str(int(time.time()))
99 conerror["UserAction"] = "Verify network connectivity between the two systems and the bmc is functional."
100 eventdict = {}
101 eventdict['event0'] = conerror
102 eventdict['numAlerts'] = '1'
Justin Thaler115bca72018-05-25 19:29:08 -0500103 errorMessageStr = errorMessageStr = json.dumps(eventdict, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600104 return(errorMessageStr)
105 elif errorStr == "ConnectionError":
106 if not jsonFormat:
107 return("FQPSPIN0001M: " + str(err))
108 else:
Justin Thaler115bca72018-05-25 19:29:08 -0500109 conerror = {}
110 conerror['CommonEventID'] = 'FQPSPIN0001M'
111 conerror['sensor']="N/A"
112 conerror['state']="N/A"
113 conerror['additionalDetails'] = str(err)
114 conerror['Message']="Connection Error. View additional details for more information"
115 conerror['LengthyDescription'] = "A connection error to the specified BMC occurred and additional details are provided. Review these details to resolve the issue."
116 conerror['Serviceable']="Yes"
117 conerror['CallHomeCandidate']= "No"
118 conerror['Severity'] = "Critical"
119 conerror['EventType'] = "Communication Failure/Timeout"
120 conerror['VMMigrationFlag'] = "Yes"
121 conerror["AffectedSubsystem"] = "Interconnect (Networking)"
122 conerror["timestamp"] = str(int(time.time()))
123 conerror["UserAction"] = "Correct the issue highlighted in additional details and try again"
124 eventdict = {}
125 eventdict['event0'] = conerror
126 eventdict['numAlerts'] = '1'
Justin Thaler115bca72018-05-25 19:29:08 -0500127 errorMessageStr = json.dumps(eventdict, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600128 return(errorMessageStr)
Justin Thaler115bca72018-05-25 19:29:08 -0500129
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600130 else:
131 return("Unknown Error: "+ str(err))
132
Justin Thalere412dc22018-01-12 16:28:24 -0600133
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600134def setColWidth(keylist, numCols, dictForOutput, colNames):
Justin Thalere412dc22018-01-12 16:28:24 -0600135 """
136 Sets the output width of the columns to display
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600137
138 @param keylist: list, list of strings representing the keys for the dictForOutput
Justin Thalere412dc22018-01-12 16:28:24 -0600139 @param numcols: the total number of columns in the final output
140 @param dictForOutput: dictionary, contains the information to print to the screen
141 @param colNames: list, The strings to use for the column headings, in order of the keylist
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600142 @return: A list of the column widths for each respective column.
Justin Thalere412dc22018-01-12 16:28:24 -0600143 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600144 colWidths = []
145 for x in range(0, numCols):
146 colWidths.append(0)
147 for key in dictForOutput:
148 for x in range(0, numCols):
149 colWidths[x] = max(colWidths[x], len(str(dictForOutput[key][keylist[x]])))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600150
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600151 for x in range(0, numCols):
152 colWidths[x] = max(colWidths[x], len(colNames[x])) +2
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600153
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600154 return colWidths
155
156def loadPolicyTable(pathToPolicyTable):
Justin Thalere412dc22018-01-12 16:28:24 -0600157 """
158 loads a json based policy table into a dictionary
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600159
Justin Thalere412dc22018-01-12 16:28:24 -0600160 @param value: boolean, the value to convert
161 @return: A string of "Yes" or "No"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600162 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600163 policyTable = {}
164 if(os.path.exists(pathToPolicyTable)):
165 with open(pathToPolicyTable, 'r') as stream:
166 try:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600167 contents =json.load(stream)
168 policyTable = contents['events']
Justin Thalere412dc22018-01-12 16:28:24 -0600169 except Exception as err:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600170 print(err)
171 return policyTable
172
Justin Thalere412dc22018-01-12 16:28:24 -0600173
174def boolToString(value):
175 """
176 converts a boolean value to a human readable string value
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600177
Justin Thalere412dc22018-01-12 16:28:24 -0600178 @param value: boolean, the value to convert
179 @return: A string of "Yes" or "No"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600180 """
Justin Thalere412dc22018-01-12 16:28:24 -0600181 if(value):
182 return "Yes"
183 else:
184 return "No"
185
Justin Thalera6b5df72018-07-16 11:10:07 -0500186def stringToInt(text):
187 """
188 returns an integer if the string can be converted, otherwise returns the string
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600189
Justin Thalera6b5df72018-07-16 11:10:07 -0500190 @param text: the string to try to convert to an integer
191 """
192 if text.isdigit():
193 return int(text)
194 else:
195 return text
Justin Thalere412dc22018-01-12 16:28:24 -0600196
Justin Thalera6b5df72018-07-16 11:10:07 -0500197def naturalSort(text):
198 """
199 provides a way to naturally sort a list
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600200
Justin Thalera6b5df72018-07-16 11:10:07 -0500201 @param text: the key to convert for sorting
202 @return list containing the broken up string parts by integers and strings
203 """
204 stringPartList = []
205 for c in re.split('(\d+)', text):
206 stringPartList.append(stringToInt(c))
207 return stringPartList
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600208
Justin Thalere412dc22018-01-12 16:28:24 -0600209def tableDisplay(keylist, colNames, output):
210 """
211 Logs into the BMC and creates a session
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600212
Justin Thalere412dc22018-01-12 16:28:24 -0600213 @param keylist: list, keys for the output dictionary, ordered by colNames
214 @param colNames: Names for the Table of the columns
215 @param output: The dictionary of data to display
216 @return: Session object
217 """
218 colWidth = setColWidth(keylist, len(colNames), output, colNames)
219 row = ""
220 outputText = ""
221 for i in range(len(colNames)):
222 if (i != 0): row = row + "| "
223 row = row + colNames[i].ljust(colWidth[i])
224 outputText += row + "\n"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600225
Justin Thalera6b5df72018-07-16 11:10:07 -0500226 output_keys = list(output.keys())
227 output_keys.sort(key=naturalSort)
228 for key in output_keys:
Justin Thalere412dc22018-01-12 16:28:24 -0600229 row = ""
Justin Thaler8fe0c732018-07-24 14:32:35 -0500230 for i in range(len(keylist)):
Justin Thalere412dc22018-01-12 16:28:24 -0600231 if (i != 0): row = row + "| "
232 row = row + output[key][keylist[i]].ljust(colWidth[i])
233 outputText += row + "\n"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600234
Justin Thalere412dc22018-01-12 16:28:24 -0600235 return outputText
236
Justin Thaler22b1bb52018-03-15 13:31:32 -0500237def checkFWactivation(host, args, session):
238 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600239 Checks the software inventory for an image that is being activated.
240
Justin Thaler22b1bb52018-03-15 13:31:32 -0500241 @return: True if an image is being activated, false is no activations are happening
242 """
243 url="https://"+host+"/xyz/openbmc_project/software/enumerate"
Justin Thaler22b1bb52018-03-15 13:31:32 -0500244 try:
Justin Thaler27197622019-01-23 14:42:11 -0600245 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thaler22b1bb52018-03-15 13:31:32 -0500246 except(requests.exceptions.Timeout):
247 print(connectionErrHandler(args.json, "Timeout", None))
248 return(True)
249 except(requests.exceptions.ConnectionError) as err:
250 print( connectionErrHandler(args.json, "ConnectionError", err))
251 return True
Justin Thaler3a5771b2019-01-23 14:31:52 -0600252 fwInfo = resp.json()['data']
Justin Thaler22b1bb52018-03-15 13:31:32 -0500253 for key in fwInfo:
254 if 'Activation' in fwInfo[key]:
255 if 'Activating' in fwInfo[key]['Activation'] or 'Activating' in fwInfo[key]['RequestedActivation']:
256 return True
257 return False
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600258
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600259def login(host, username, pw,jsonFormat):
Justin Thalere412dc22018-01-12 16:28:24 -0600260 """
261 Logs into the BMC and creates a session
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600262
Justin Thalere412dc22018-01-12 16:28:24 -0600263 @param host: string, the hostname or IP address of the bmc to log into
264 @param username: The user name for the bmc to log into
265 @param pw: The password for the BMC to log into
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600266 @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 -0600267 @return: Session object
268 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600269 if(jsonFormat==False):
270 print("Attempting login...")
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600271 mysess = requests.session()
272 try:
Justin Thaler27197622019-01-23 14:42:11 -0600273 r = mysess.post('https://'+host+'/login', headers=jsonHeader, json = {"data": [username, pw]}, verify=False, timeout=baseTimeout)
Sunitha Harish336cda22019-07-23 02:02:52 -0500274 if r.status_code == 200:
275 cookie = r.headers['Set-Cookie']
276 match = re.search('SESSION=(\w+);', cookie)
277 if match:
278 xAuthHeader['X-Auth-Token'] = match.group(1)
279 jsonHeader.update(xAuthHeader)
280 loginMessage = json.loads(r.text)
281 if (loginMessage['status'] != "ok"):
282 print(loginMessage["data"]["description"].encode('utf-8'))
283 sys.exit(1)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600284# if(sys.version_info < (3,0)):
285# urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
286# if sys.version_info >= (3,0):
287# requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)
Sunitha Harish336cda22019-07-23 02:02:52 -0500288 return mysess
289 else:
290 return None
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600291 except(requests.exceptions.Timeout):
Justin Thaler115bca72018-05-25 19:29:08 -0500292 return (connectionErrHandler(jsonFormat, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600293 except(requests.exceptions.ConnectionError) as err:
Justin Thaler115bca72018-05-25 19:29:08 -0500294 return (connectionErrHandler(jsonFormat, "ConnectionError", err))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600295
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600296
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600297def logout(host, username, pw, session, jsonFormat):
Justin Thalere412dc22018-01-12 16:28:24 -0600298 """
299 Logs out of the bmc and terminates the session
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600300
Justin Thalere412dc22018-01-12 16:28:24 -0600301 @param host: string, the hostname or IP address of the bmc to log out of
302 @param username: The user name for the bmc to log out of
303 @param pw: The password for the BMC to log out of
304 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600305 @param jsonFormat: boolean, flag that will only allow relevant data from user command to be display. This function becomes silent when set to true.
306 """
Justin Thalere412dc22018-01-12 16:28:24 -0600307 try:
Justin Thaler27197622019-01-23 14:42:11 -0600308 r = session.post('https://'+host+'/logout', headers=jsonHeader,json = {"data": [username, pw]}, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600309 except(requests.exceptions.Timeout):
310 print(connectionErrHandler(jsonFormat, "Timeout", None))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600311
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600312 if(jsonFormat==False):
Matt Spinlereae05b02019-01-24 12:59:34 -0600313 if r.status_code == 200:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600314 print('User ' +username + ' has been logged out')
315
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600316
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600317def fru(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -0600318 """
319 prints out the system inventory. deprecated see fruPrint and fruList
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600320
Justin Thalere412dc22018-01-12 16:28:24 -0600321 @param host: string, the hostname or IP address of the bmc
322 @param args: contains additional arguments used by the fru sub command
323 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600324 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
325 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600326 #url="https://"+host+"/org/openbmc/inventory/system/chassis/enumerate"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600327
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600328 #print(url)
329 #res = session.get(url, headers=httpHeader, verify=False)
330 #print(res.text)
331 #sample = res.text
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600332
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600333 #inv_list = json.loads(sample)["data"]
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600334
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600335 url="https://"+host+"/xyz/openbmc_project/inventory/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600336 try:
Justin Thaler27197622019-01-23 14:42:11 -0600337 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600338 except(requests.exceptions.Timeout):
339 return(connectionErrHandler(args.json, "Timeout", None))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600340
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600341 sample = res.text
342# inv_list.update(json.loads(sample)["data"])
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600343#
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600344# #determine column width's
345# colNames = ["FRU Name", "FRU Type", "Has Fault", "Is FRU", "Present", "Version"]
346# colWidths = setColWidth(["FRU Name", "fru_type", "fault", "is_fru", "present", "version"], 6, inv_list, colNames)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600347#
348# 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 -0600349# "Present".ljust(colWidths[4]) + "Version".ljust(colWidths[5]))
350# format the output
351# for key in sorted(inv_list.keys()):
352# keyParts = key.split("/")
353# isFRU = "True" if (inv_list[key]["is_fru"]==1) else "False"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600354#
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600355# fruEntry = (keyParts[len(keyParts) - 1].ljust(colWidths[0]) + inv_list[key]["fru_type"].ljust(colWidths[1])+
356# inv_list[key]["fault"].ljust(colWidths[2])+isFRU.ljust(colWidths[3])+
357# inv_list[key]["present"].ljust(colWidths[4])+ inv_list[key]["version"].ljust(colWidths[5]))
358# if(isTTY):
359# if(inv_list[key]["is_fru"] == 1):
360# color = "green"
361# bold = True
362# else:
363# color='black'
364# bold = False
365# fruEntry = hilight(fruEntry, color, bold)
366# print (fruEntry)
367 return sample
Justin Thalere412dc22018-01-12 16:28:24 -0600368
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600369def fruPrint(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -0600370 """
371 prints out all inventory
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600372
Justin Thalere412dc22018-01-12 16:28:24 -0600373 @param host: string, the hostname or IP address of the bmc
374 @param args: contains additional arguments used by the fru sub command
375 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600376 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
377 @return returns the total fru list.
378 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600379 url="https://"+host+"/xyz/openbmc_project/inventory/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600380 try:
Justin Thaler27197622019-01-23 14:42:11 -0600381 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600382 except(requests.exceptions.Timeout):
383 return(connectionErrHandler(args.json, "Timeout", None))
384
Justin Thaler3a5771b2019-01-23 14:31:52 -0600385 frulist={}
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600386# print(res.text)
Justin Thaler3a5771b2019-01-23 14:31:52 -0600387 if res.status_code==200:
388 frulist['Hardware'] = res.json()['data']
389 else:
390 if not args.json:
391 return "Error retrieving the system inventory. BMC message: {msg}".format(msg=res.json()['message'])
392 else:
393 return res.json()
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600394 url="https://"+host+"/xyz/openbmc_project/software/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600395 try:
Justin Thaler27197622019-01-23 14:42:11 -0600396 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600397 except(requests.exceptions.Timeout):
398 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600399# print(res.text)
Justin Thaler3a5771b2019-01-23 14:31:52 -0600400 if res.status_code==200:
401 frulist['Software'] = res.json()['data']
402 else:
403 if not args.json():
404 return "Error retrieving the system inventory. BMC message: {msg}".format(msg=res.json()['message'])
405 else:
406 return res.json()
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600407 return frulist
408
Justin Thalere412dc22018-01-12 16:28:24 -0600409
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600410def fruList(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -0600411 """
412 prints out all inventory or only a specific specified item
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600413
Justin Thalere412dc22018-01-12 16:28:24 -0600414 @param host: string, the hostname or IP address of the bmc
415 @param args: contains additional arguments used by the fru sub command
416 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600417 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
418 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600419 if(args.items==True):
420 return fruPrint(host, args, session)
421 else:
Justin Thalere412dc22018-01-12 16:28:24 -0600422 return fruPrint(host, args, session)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600423
424
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600425
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600426def fruStatus(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -0600427 """
428 prints out the status of all FRUs
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600429
Justin Thalere412dc22018-01-12 16:28:24 -0600430 @param host: string, the hostname or IP address of the bmc
431 @param args: contains additional arguments used by the fru sub command
432 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600433 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
434 """
Justin Thalere412dc22018-01-12 16:28:24 -0600435 url="https://"+host+"/xyz/openbmc_project/inventory/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600436 try:
Matt Spinler220c3c42019-01-04 15:09:29 -0600437 res = session.get(url, headers=jsonHeader, verify=False)
Justin Thalere412dc22018-01-12 16:28:24 -0600438 except(requests.exceptions.Timeout):
439 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600440# print(res.text)
Justin Thaler3a5771b2019-01-23 14:31:52 -0600441 frulist = res.json()['data']
Justin Thalere412dc22018-01-12 16:28:24 -0600442 frus = {}
443 for key in frulist:
444 component = frulist[key]
445 isFru = False
446 present = False
447 func = False
448 hasSels = False
449 keyPieces = key.split('/')
450 fruName = keyPieces[-1]
451 if 'core' in fruName: #associate cores to cpus
452 fruName = keyPieces[-2] + '-' + keyPieces[-1]
453 if 'Functional' in component:
454 if('Present' in component):
Justin Thalere412dc22018-01-12 16:28:24 -0600455 if 'FieldReplaceable' in component:
456 if component['FieldReplaceable'] == 1:
457 isFru = True
458 if "fan" in fruName:
459 isFru = True;
460 if component['Present'] == 1:
461 present = True
462 if component['Functional'] == 1:
463 func = True
464 if ((key + "/fault") in frulist):
465 hasSels = True;
466 if args.verbose:
467 if hasSels:
468 loglist = []
469 faults = frulist[key+"/fault"]['endpoints']
470 for item in faults:
471 loglist.append(item.split('/')[-1])
472 frus[fruName] = {"compName": fruName, "Functional": boolToString(func), "Present":boolToString(present), "IsFru": boolToString(isFru), "selList": ', '.join(loglist).strip() }
473 else:
474 frus[fruName] = {"compName": fruName, "Functional": boolToString(func), "Present":boolToString(present), "IsFru": boolToString(isFru), "selList": "None" }
475 else:
476 frus[fruName] = {"compName": fruName, "Functional": boolToString(func), "Present":boolToString(present), "IsFru": boolToString(isFru), "hasSEL": boolToString(hasSels) }
Justin Thalerfb9c81c2018-07-16 11:14:37 -0500477 elif "power_supply" in fruName or "powersupply" in fruName:
Justin Thalere412dc22018-01-12 16:28:24 -0600478 if component['Present'] ==1:
479 present = True
480 isFru = True
481 if ((key + "/fault") in frulist):
482 hasSels = True;
483 if args.verbose:
484 if hasSels:
485 loglist = []
486 faults = frulist[key+"/fault"]['endpoints']
Obihörnchenff8035f2018-12-05 21:07:37 +0100487 for item in faults:
488 loglist.append(item.split('/')[-1])
Justin Thalere412dc22018-01-12 16:28:24 -0600489 frus[fruName] = {"compName": fruName, "Functional": "No", "Present":boolToString(present), "IsFru": boolToString(isFru), "selList": ', '.join(loglist).strip() }
490 else:
491 frus[fruName] = {"compName": fruName, "Functional": "Yes", "Present":boolToString(present), "IsFru": boolToString(isFru), "selList": "None" }
492 else:
493 frus[fruName] = {"compName": fruName, "Functional": boolToString(not hasSels), "Present":boolToString(present), "IsFru": boolToString(isFru), "hasSEL": boolToString(hasSels) }
494 if not args.json:
495 if not args.verbose:
496 colNames = ["Component", "Is a FRU", "Present", "Functional", "Has Logs"]
497 keylist = ["compName", "IsFru", "Present", "Functional", "hasSEL"]
498 else:
499 colNames = ["Component", "Is a FRU", "Present", "Functional", "Assoc. Log Number(s)"]
500 keylist = ["compName", "IsFru", "Present", "Functional", "selList"]
501 return tableDisplay(keylist, colNames, frus)
502 else:
503 return str(json.dumps(frus, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600504
Justin Thalere412dc22018-01-12 16:28:24 -0600505def sensor(host, args, session):
506 """
507 prints out all sensors
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600508
Justin Thalere412dc22018-01-12 16:28:24 -0600509 @param host: string, the hostname or IP address of the bmc
510 @param args: contains additional arguments used by the sensor sub command
511 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600512 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
513 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600514 url="https://"+host+"/xyz/openbmc_project/sensors/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600515 try:
Justin Thaler27197622019-01-23 14:42:11 -0600516 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600517 except(requests.exceptions.Timeout):
518 return(connectionErrHandler(args.json, "Timeout", None))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600519
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600520 #Get OCC status
521 url="https://"+host+"/org/open_power/control/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600522 try:
Justin Thaler27197622019-01-23 14:42:11 -0600523 occres = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600524 except(requests.exceptions.Timeout):
525 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600526 if not args.json:
527 colNames = ['sensor', 'type', 'units', 'value', 'target']
Justin Thaler3a5771b2019-01-23 14:31:52 -0600528 sensors = res.json()["data"]
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600529 output = {}
530 for key in sensors:
531 senDict = {}
532 keyparts = key.split("/")
Matt Spinler596ef742019-09-20 08:54:36 -0500533
534 # Associations like the following also show up here:
535 # /xyz/openbmc_project/sensors/<type>/<name>/<assoc-name>
536 # Skip them.
537 # Note: keyparts[0] = '' which is why there are 7 segments.
538 if len(keyparts) > 6:
539 continue
540
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600541 senDict['sensorName'] = keyparts[-1]
542 senDict['type'] = keyparts[-2]
Justin Thalere412dc22018-01-12 16:28:24 -0600543 try:
544 senDict['units'] = sensors[key]['Unit'].split('.')[-1]
545 except KeyError:
Justin Thaler22b1bb52018-03-15 13:31:32 -0500546 senDict['units'] = "N/A"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600547 if('Scale' in sensors[key]):
548 scale = 10 ** sensors[key]['Scale']
549 else:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600550 scale = 1
Justin Thaler22b1bb52018-03-15 13:31:32 -0500551 try:
552 senDict['value'] = str(sensors[key]['Value'] * scale)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600553 except KeyError:
Justin Thaler22b1bb52018-03-15 13:31:32 -0500554 if 'value' in sensors[key]:
555 senDict['value'] = sensors[key]['value']
556 else:
557 senDict['value'] = "N/A"
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600558 if 'Target' in sensors[key]:
559 senDict['target'] = str(sensors[key]['Target'])
560 else:
561 senDict['target'] = 'N/A'
562 output[senDict['sensorName']] = senDict
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600563
Justin Thaler3a5771b2019-01-23 14:31:52 -0600564 occstatus = occres.json()["data"]
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600565 if '/org/open_power/control/occ0' in occstatus:
566 occ0 = occstatus["/org/open_power/control/occ0"]['OccActive']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600567 if occ0 == 1:
568 occ0 = 'Active'
569 else:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600570 occ0 = 'Inactive'
571 output['OCC0'] = {'sensorName':'OCC0', 'type': 'Discrete', 'units': 'N/A', 'value': occ0, 'target': 'Active'}
572 occ1 = occstatus["/org/open_power/control/occ1"]['OccActive']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600573 if occ1 == 1:
574 occ1 = 'Active'
575 else:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600576 occ1 = 'Inactive'
577 output['OCC1'] = {'sensorName':'OCC1', 'type': 'Discrete', 'units': 'N/A', 'value': occ0, 'target': 'Active'}
578 else:
579 output['OCC0'] = {'sensorName':'OCC0', 'type': 'Discrete', 'units': 'N/A', 'value': 'Inactive', 'target': 'Inactive'}
580 output['OCC1'] = {'sensorName':'OCC1', 'type': 'Discrete', 'units': 'N/A', 'value': 'Inactive', 'target': 'Inactive'}
581 keylist = ['sensorName', 'type', 'units', 'value', 'target']
Justin Thalere412dc22018-01-12 16:28:24 -0600582
583 return tableDisplay(keylist, colNames, output)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600584 else:
585 return res.text + occres.text
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600586
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600587def sel(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -0600588 """
589 prints out the bmc alerts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600590
Justin Thalere412dc22018-01-12 16:28:24 -0600591 @param host: string, the hostname or IP address of the bmc
592 @param args: contains additional arguments used by the sel sub command
593 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600594 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
595 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600596
597 url="https://"+host+"/xyz/openbmc_project/logging/entry/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600598 try:
Justin Thaler27197622019-01-23 14:42:11 -0600599 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600600 except(requests.exceptions.Timeout):
601 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600602 return res.text
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600603
604
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600605def parseESEL(args, eselRAW):
Justin Thalere412dc22018-01-12 16:28:24 -0600606 """
607 parses the esel data and gets predetermined search terms
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600608
Justin Thalere412dc22018-01-12 16:28:24 -0600609 @param eselRAW: string, the raw esel string from the bmc
610 @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 -0600611 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600612 eselParts = {}
613 esel_bin = binascii.unhexlify(''.join(eselRAW.split()[16:]))
614 #search terms contains the search term as the key and the return dictionary key as it's value
615 searchTerms = { 'Signature Description':'signatureDescription', 'devdesc':'devdesc',
Justin Thaler22b1bb52018-03-15 13:31:32 -0500616 'Callout type': 'calloutType', 'Procedure':'procedure', 'Sensor Type': 'sensorType'}
Justin Thaler24d4efa2018-11-08 22:48:10 -0600617 uniqueID = str(uuid.uuid4())
618 eselBinPath = tempfile.gettempdir() + os.sep + uniqueID + 'esel.bin'
Justin Thalercf1deae2018-05-25 19:35:21 -0500619 with open(eselBinPath, 'wb') as f:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600620 f.write(esel_bin)
621 errlPath = ""
622 #use the right errl file for the machine architecture
623 arch = platform.machine()
624 if(arch =='x86_64' or arch =='AMD64'):
625 if os.path.exists('/opt/ibm/ras/bin/x86_64/errl'):
626 errlPath = '/opt/ibm/ras/bin/x86_64/errl'
627 elif os.path.exists('errl/x86_64/errl'):
628 errlPath = 'errl/x86_64/errl'
629 else:
630 errlPath = 'x86_64/errl'
631 elif (platform.machine()=='ppc64le'):
632 if os.path.exists('/opt/ibm/ras/bin/ppc64le/errl'):
633 errlPath = '/opt/ibm/ras/bin/ppc64le/errl'
634 elif os.path.exists('errl/ppc64le/errl'):
635 errlPath = 'errl/ppc64le/errl'
636 else:
637 errlPath = 'ppc64le/errl'
638 else:
639 print("machine architecture not supported for parsing eSELs")
640 return eselParts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600641
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600642 if(os.path.exists(errlPath)):
Justin Thalercf1deae2018-05-25 19:35:21 -0500643 output= subprocess.check_output([errlPath, '-d', '--file='+eselBinPath]).decode('utf-8')
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600644# output = proc.communicate()[0]
645 lines = output.split('\n')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600646
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600647 if(hasattr(args, 'fullEsel')):
648 return output
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600649
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600650 for i in range(0, len(lines)):
651 lineParts = lines[i].split(':')
652 if(len(lineParts)>1): #ignore multi lines, output formatting lines, and other information
653 for term in searchTerms:
654 if(term in lineParts[0]):
655 temp = lines[i][lines[i].find(':')+1:].strip()[:-1].strip()
656 if lines[i+1].find(':') != -1:
657 if (len(lines[i+1].split(':')[0][1:].strip())==0):
658 while(len(lines[i][:lines[i].find(':')].strip())>2):
Justin Thaler43030422018-11-08 22:50:21 -0600659 #has multiple lines, process and update line counter
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600660 if((i+1) <= len(lines)):
661 i+=1
662 else:
663 i=i-1
664 break
Justin Thaler43030422018-11-08 22:50:21 -0600665 #Append the content from the next line removing the pretty display characters
666 #Finds the first colon then starts 2 characters after, then removes all whitespace
667 temp = temp + lines[i][lines[i].find(':')+2:].strip()[:-1].strip()[:-1].strip()
Justin Thaler22b1bb52018-03-15 13:31:32 -0500668 if(searchTerms[term] in eselParts):
669 eselParts[searchTerms[term]] = eselParts[searchTerms[term]] + ", " + temp
670 else:
671 eselParts[searchTerms[term]] = temp
Justin Thalercf1deae2018-05-25 19:35:21 -0500672 os.remove(eselBinPath)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600673 else:
674 print("errl file cannot be found")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600675
676 return eselParts
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600677
Justin Thalere412dc22018-01-12 16:28:24 -0600678
Matt Spinler02d0dff2018-08-29 13:19:25 -0500679def getESELSeverity(esel):
680 """
681 Finds the severity type in an eSEL from the User Header section.
682 @param esel - the eSEL data
683 @return severity - e.g. 'Critical'
684 """
685
686 # everything but 1 and 2 are Critical
687 # '1': 'recovered',
688 # '2': 'predictive',
689 # '4': 'unrecoverable',
690 # '5': 'critical',
691 # '6': 'diagnostic',
692 # '7': 'symptom'
693 severities = {
694 '1': 'Informational',
695 '2': 'Warning'
696 }
697
698 try:
699 headerPosition = esel.index('55 48') # 'UH'
700 # The severity is the last byte in the 8 byte section (a byte is ' bb')
701 severity = esel[headerPosition:headerPosition+32].split(' ')[-1]
702 type = severity[0]
703 except ValueError:
704 print("Could not find severity value in UH section in eSEL")
705 type = 'x';
706
707 return severities.get(type, 'Critical')
708
709
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600710def sortSELs(events):
Justin Thalere412dc22018-01-12 16:28:24 -0600711 """
712 sorts the sels by timestamp, then log entry number
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600713
Justin Thalere412dc22018-01-12 16:28:24 -0600714 @param events: Dictionary containing events
715 @return: list containing a list of the ordered log entries, and dictionary of keys
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600716 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600717 logNumList = []
718 timestampList = []
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600719 eventKeyDict = {}
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600720 eventsWithTimestamp = {}
721 logNum2events = {}
722 for key in events:
723 if key == 'numAlerts': continue
724 if 'callout' in key: continue
725 timestamp = (events[key]['timestamp'])
726 if timestamp not in timestampList:
727 eventsWithTimestamp[timestamp] = [events[key]['logNum']]
728 else:
729 eventsWithTimestamp[timestamp].append(events[key]['logNum'])
730 #map logNumbers to the event dictionary keys
731 eventKeyDict[str(events[key]['logNum'])] = key
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600732
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600733 timestampList = list(eventsWithTimestamp.keys())
734 timestampList.sort()
735 for ts in timestampList:
736 if len(eventsWithTimestamp[ts]) > 1:
737 tmplist = eventsWithTimestamp[ts]
738 tmplist.sort()
739 logNumList = logNumList + tmplist
740 else:
741 logNumList = logNumList + eventsWithTimestamp[ts]
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600742
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600743 return [logNumList, eventKeyDict]
744
Justin Thalere412dc22018-01-12 16:28:24 -0600745
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600746def parseAlerts(policyTable, selEntries, args):
Justin Thalere412dc22018-01-12 16:28:24 -0600747 """
748 parses alerts in the IBM CER format, using an IBM policy Table
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600749
Justin Thalere412dc22018-01-12 16:28:24 -0600750 @param policyTable: dictionary, the policy table entries
751 @param selEntries: dictionary, the alerts retrieved from the bmc
752 @return: A dictionary of the parsed entries, in chronological order
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600753 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600754 eventDict = {}
755 eventNum =""
756 count = 0
757 esel = ""
758 eselParts = {}
759 i2cdevice= ""
Matt Spinler02d0dff2018-08-29 13:19:25 -0500760 eselSeverity = None
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600761
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600762 'prepare and sort the event entries'
763 for key in selEntries:
764 if 'callout' not in key:
765 selEntries[key]['logNum'] = key.split('/')[-1]
766 selEntries[key]['timestamp'] = selEntries[key]['Timestamp']
767 sortedEntries = sortSELs(selEntries)
768 logNumList = sortedEntries[0]
769 eventKeyDict = sortedEntries[1]
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600770
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600771 for logNum in logNumList:
772 key = eventKeyDict[logNum]
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600773 hasEsel=False
774 i2creadFail = False
775 if 'callout' in key:
776 continue
777 else:
778 messageID = str(selEntries[key]['Message'])
779 addDataPiece = selEntries[key]['AdditionalData']
780 calloutIndex = 0
781 calloutFound = False
782 for i in range(len(addDataPiece)):
783 if("CALLOUT_INVENTORY_PATH" in addDataPiece[i]):
784 calloutIndex = i
785 calloutFound = True
786 fruCallout = str(addDataPiece[calloutIndex]).split('=')[1]
787 if("CALLOUT_DEVICE_PATH" in addDataPiece[i]):
788 i2creadFail = True
Matt Spinlerd178a472018-08-31 09:48:52 -0500789
790 fruCallout = str(addDataPiece[calloutIndex]).split('=')[1]
791
792 # Fall back to "I2C"/"FSI" if dev path isn't in policy table
793 if (messageID + '||' + fruCallout) not in policyTable:
794 i2cdevice = str(addDataPiece[i]).strip().split('=')[1]
795 i2cdevice = '/'.join(i2cdevice.split('/')[-4:])
796 if 'fsi' in str(addDataPiece[calloutIndex]).split('=')[1]:
797 fruCallout = 'FSI'
798 else:
799 fruCallout = 'I2C'
Justin Thalere34c43a2018-05-25 19:37:55 -0500800 calloutFound = True
801 if("CALLOUT_GPIO_NUM" in addDataPiece[i]):
802 if not calloutFound:
803 fruCallout = 'GPIO'
804 calloutFound = True
805 if("CALLOUT_IIC_BUS" in addDataPiece[i]):
806 if not calloutFound:
807 fruCallout = "I2C"
808 calloutFound = True
809 if("CALLOUT_IPMI_SENSOR_NUM" in addDataPiece[i]):
810 if not calloutFound:
811 fruCallout = "IPMI"
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600812 calloutFound = True
813 if("ESEL" in addDataPiece[i]):
814 esel = str(addDataPiece[i]).strip().split('=')[1]
Matt Spinler02d0dff2018-08-29 13:19:25 -0500815 eselSeverity = getESELSeverity(esel)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600816 if args.devdebug:
817 eselParts = parseESEL(args, esel)
818 hasEsel=True
819 if("GPU" in addDataPiece[i]):
820 fruCallout = '/xyz/openbmc_project/inventory/system/chassis/motherboard/gpu' + str(addDataPiece[i]).strip()[-1]
821 calloutFound = True
822 if("PROCEDURE" in addDataPiece[i]):
823 fruCallout = str(hex(int(str(addDataPiece[i]).split('=')[1])))[2:]
824 calloutFound = True
Justin Thalere412dc22018-01-12 16:28:24 -0600825 if("RAIL_NAME" in addDataPiece[i]):
826 calloutFound=True
827 fruCallout = str(addDataPiece[i]).split('=')[1].strip()
828 if("INPUT_NAME" in addDataPiece[i]):
829 calloutFound=True
830 fruCallout = str(addDataPiece[i]).split('=')[1].strip()
831 if("SENSOR_TYPE" in addDataPiece[i]):
832 calloutFound=True
833 fruCallout = str(addDataPiece[i]).split('=')[1].strip()
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600834
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600835 if(calloutFound):
Justin Thaler22b1bb52018-03-15 13:31:32 -0500836 if fruCallout != "":
837 policyKey = messageID +"||" + fruCallout
Matt Spinler02d0dff2018-08-29 13:19:25 -0500838
839 # Also use the severity for hostboot errors
840 if eselSeverity and messageID == 'org.open_power.Host.Error.Event':
841 policyKey += '||' + eselSeverity
842
843 # if not in the table, fall back to the original key
844 if policyKey not in policyTable:
845 policyKey = policyKey.replace('||'+eselSeverity, '')
846
Justin Thalere34c43a2018-05-25 19:37:55 -0500847 if policyKey not in policyTable:
848 policyKey = messageID
Justin Thaler22b1bb52018-03-15 13:31:32 -0500849 else:
850 policyKey = messageID
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600851 else:
852 policyKey = messageID
853 event = {}
854 eventNum = str(count)
855 if policyKey in policyTable:
856 for pkey in policyTable[policyKey]:
857 if(type(policyTable[policyKey][pkey])== bool):
858 event[pkey] = boolToString(policyTable[policyKey][pkey])
859 else:
860 if (i2creadFail and pkey == 'Message'):
861 event[pkey] = policyTable[policyKey][pkey] + ' ' +i2cdevice
862 else:
863 event[pkey] = policyTable[policyKey][pkey]
864 event['timestamp'] = selEntries[key]['Timestamp']
865 event['resolved'] = bool(selEntries[key]['Resolved'])
866 if(hasEsel):
867 if args.devdebug:
868 event['eselParts'] = eselParts
869 event['raweSEL'] = esel
870 event['logNum'] = key.split('/')[-1]
871 eventDict['event' + eventNum] = event
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600872
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600873 else:
874 severity = str(selEntries[key]['Severity']).split('.')[-1]
875 if severity == 'Error':
876 severity = 'Critical'
877 eventDict['event'+eventNum] = {}
878 eventDict['event' + eventNum]['error'] = "error: Not found in policy table: " + policyKey
879 eventDict['event' + eventNum]['timestamp'] = selEntries[key]['Timestamp']
880 eventDict['event' + eventNum]['Severity'] = severity
881 if(hasEsel):
882 if args.devdebug:
883 eventDict['event' +eventNum]['eselParts'] = eselParts
884 eventDict['event' +eventNum]['raweSEL'] = esel
885 eventDict['event' +eventNum]['logNum'] = key.split('/')[-1]
886 eventDict['event' +eventNum]['resolved'] = bool(selEntries[key]['Resolved'])
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600887 count += 1
888 return eventDict
889
890
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600891def selDisplay(events, args):
Justin Thalere412dc22018-01-12 16:28:24 -0600892 """
893 displays alerts in human readable format
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600894
Justin Thalere412dc22018-01-12 16:28:24 -0600895 @param events: Dictionary containing events
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600896 @return:
897 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600898 activeAlerts = []
899 historyAlerts = []
900 sortedEntries = sortSELs(events)
901 logNumList = sortedEntries[0]
902 eventKeyDict = sortedEntries[1]
903 keylist = ['Entry', 'ID', 'Timestamp', 'Serviceable', 'Severity','Message']
904 if(args.devdebug):
905 colNames = ['Entry', 'ID', 'Timestamp', 'Serviceable', 'Severity','Message', 'eSEL contents']
906 keylist.append('eSEL')
907 else:
908 colNames = ['Entry', 'ID', 'Timestamp', 'Serviceable', 'Severity', 'Message']
909 for log in logNumList:
910 selDict = {}
911 alert = events[eventKeyDict[str(log)]]
912 if('error' in alert):
913 selDict['Entry'] = alert['logNum']
914 selDict['ID'] = 'Unknown'
915 selDict['Timestamp'] = datetime.datetime.fromtimestamp(int(alert['timestamp']/1000)).strftime("%Y-%m-%d %H:%M:%S")
916 msg = alert['error']
917 polMsg = msg.split("policy table:")[0]
918 msg = msg.split("policy table:")[1]
919 msgPieces = msg.split("||")
920 err = msgPieces[0]
921 if(err.find("org.open_power.")!=-1):
922 err = err.split("org.open_power.")[1]
923 elif(err.find("xyz.openbmc_project.")!=-1):
924 err = err.split("xyz.openbmc_project.")[1]
925 else:
926 err = msgPieces[0]
927 callout = ""
928 if len(msgPieces) >1:
929 callout = msgPieces[1]
930 if(callout.find("/org/open_power/")!=-1):
931 callout = callout.split("/org/open_power/")[1]
932 elif(callout.find("/xyz/openbmc_project/")!=-1):
933 callout = callout.split("/xyz/openbmc_project/")[1]
934 else:
935 callout = msgPieces[1]
936 selDict['Message'] = polMsg +"policy table: "+ err + "||" + callout
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600937 selDict['Serviceable'] = 'Unknown'
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600938 selDict['Severity'] = alert['Severity']
939 else:
940 selDict['Entry'] = alert['logNum']
941 selDict['ID'] = alert['CommonEventID']
942 selDict['Timestamp'] = datetime.datetime.fromtimestamp(int(alert['timestamp']/1000)).strftime("%Y-%m-%d %H:%M:%S")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600943 selDict['Message'] = alert['Message']
944 selDict['Serviceable'] = alert['Serviceable']
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600945 selDict['Severity'] = alert['Severity']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600946
947
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600948 eselOrder = ['refCode','signatureDescription', 'eselType', 'devdesc', 'calloutType', 'procedure']
949 if ('eselParts' in alert and args.devdebug):
950 eselOutput = ""
951 for item in eselOrder:
952 if item in alert['eselParts']:
953 eselOutput = eselOutput + item + ": " + alert['eselParts'][item] + " | "
954 selDict['eSEL'] = eselOutput
955 else:
956 if args.devdebug:
957 selDict['eSEL'] = "None"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600958
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600959 if not alert['resolved']:
960 activeAlerts.append(selDict)
961 else:
962 historyAlerts.append(selDict)
963 mergedOutput = activeAlerts + historyAlerts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600964 colWidth = setColWidth(keylist, len(colNames), dict(enumerate(mergedOutput)), colNames)
965
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600966 output = ""
967 if(len(activeAlerts)>0):
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600968 row = ""
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600969 output +="----Active Alerts----\n"
970 for i in range(0, len(colNames)):
971 if i!=0: row =row + "| "
972 row = row + colNames[i].ljust(colWidth[i])
973 output += row + "\n"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600974
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600975 for i in range(0,len(activeAlerts)):
976 row = ""
977 for j in range(len(activeAlerts[i])):
978 if (j != 0): row = row + "| "
979 row = row + activeAlerts[i][keylist[j]].ljust(colWidth[j])
980 output += row + "\n"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600981
982 if(len(historyAlerts)>0):
983 row = ""
984 output+= "----Historical Alerts----\n"
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600985 for i in range(len(colNames)):
986 if i!=0: row =row + "| "
987 row = row + colNames[i].ljust(colWidth[i])
988 output += row + "\n"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600989
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600990 for i in range(0, len(historyAlerts)):
991 row = ""
992 for j in range(len(historyAlerts[i])):
993 if (j != 0): row = row + "| "
994 row = row + historyAlerts[i][keylist[j]].ljust(colWidth[j])
995 output += row + "\n"
996# print(events[eventKeyDict[str(log)]])
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600997 return output
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600998
Justin Thalere412dc22018-01-12 16:28:24 -0600999
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001000def selPrint(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001001 """
1002 prints out all bmc alerts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001003
Justin Thalere412dc22018-01-12 16:28:24 -06001004 @param host: string, the hostname or IP address of the bmc
1005 @param args: contains additional arguments used by the fru sub command
1006 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001007 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1008 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001009 if(args.policyTableLoc is None):
1010 if os.path.exists('policyTable.json'):
1011 ptableLoc = "policyTable.json"
1012 elif os.path.exists('/opt/ibm/ras/lib/policyTable.json'):
1013 ptableLoc = '/opt/ibm/ras/lib/policyTable.json'
1014 else:
1015 ptableLoc = 'lib/policyTable.json'
1016 else:
1017 ptableLoc = args.policyTableLoc
1018 policyTable = loadPolicyTable(ptableLoc)
1019 rawselEntries = ""
1020 if(hasattr(args, 'fileloc') and args.fileloc is not None):
1021 if os.path.exists(args.fileloc):
1022 with open(args.fileloc, 'r') as selFile:
1023 selLines = selFile.readlines()
1024 rawselEntries = ''.join(selLines)
1025 else:
1026 print("Error: File not found")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001027 sys.exit(1)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001028 else:
1029 rawselEntries = sel(host, args, session)
1030 loadFailed = False
1031 try:
1032 selEntries = json.loads(rawselEntries)
1033 except ValueError:
1034 loadFailed = True
1035 if loadFailed:
1036 cleanSels = json.dumps(rawselEntries).replace('\\n', '')
1037 #need to load json twice as original content was string escaped a second time
1038 selEntries = json.loads(json.loads(cleanSels))
1039 selEntries = selEntries['data']
Justin Thalere412dc22018-01-12 16:28:24 -06001040
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001041 if 'description' in selEntries:
1042 if(args.json):
1043 return("{\n\t\"numAlerts\": 0\n}")
1044 else:
1045 return("No log entries found")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001046
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001047 else:
1048 if(len(policyTable)>0):
1049 events = parseAlerts(policyTable, selEntries, args)
1050 if(args.json):
1051 events["numAlerts"] = len(events)
1052 retValue = str(json.dumps(events, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False))
1053 return retValue
1054 elif(hasattr(args, 'fullSel')):
1055 return events
1056 else:
1057 #get log numbers to order event entries sequentially
1058 return selDisplay(events, args)
1059 else:
1060 if(args.json):
1061 return selEntries
1062 else:
1063 print("error: Policy Table not found.")
1064 return selEntries
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001065
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001066def selList(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001067 """
1068 prints out all all bmc alerts, or only prints out the specified alerts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001069
Justin Thalere412dc22018-01-12 16:28:24 -06001070 @param host: string, the hostname or IP address of the bmc
1071 @param args: contains additional arguments used by the fru sub command
1072 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001073 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1074 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001075 return(sel(host, args, session))
1076
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001077
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001078def selClear(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001079 """
1080 clears all alerts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001081
Justin Thalere412dc22018-01-12 16:28:24 -06001082 @param host: string, the hostname or IP address of the bmc
1083 @param args: contains additional arguments used by the fru sub command
1084 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001085 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1086 """
Matt Spinler47b13e92019-01-04 14:58:53 -06001087 url="https://"+host+"/xyz/openbmc_project/logging/action/DeleteAll"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001088 data = "{\"data\": [] }"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001089
Justin Thalere412dc22018-01-12 16:28:24 -06001090 try:
Justin Thaler27197622019-01-23 14:42:11 -06001091 res = session.post(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001092 except(requests.exceptions.Timeout):
1093 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001094 if res.status_code == 200:
1095 return "The Alert Log has been cleared. Please allow a few minutes for the action to complete."
1096 else:
1097 print("Unable to clear the logs, trying to clear 1 at a time")
1098 sels = json.loads(sel(host, args, session))['data']
1099 for key in sels:
1100 if 'callout' not in key:
1101 logNum = key.split('/')[-1]
1102 url = "https://"+ host+ "/xyz/openbmc_project/logging/entry/"+logNum+"/action/Delete"
1103 try:
Justin Thaler27197622019-01-23 14:42:11 -06001104 session.post(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001105 except(requests.exceptions.Timeout):
1106 return connectionErrHandler(args.json, "Timeout", None)
1107 sys.exit(1)
1108 except(requests.exceptions.ConnectionError) as err:
1109 return connectionErrHandler(args.json, "ConnectionError", err)
1110 sys.exit(1)
1111 return ('Sel clearing complete')
1112
1113def selSetResolved(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001114 """
1115 sets a sel entry to resolved
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001116
Justin Thalere412dc22018-01-12 16:28:24 -06001117 @param host: string, the hostname or IP address of the bmc
1118 @param args: contains additional arguments used by the fru sub command
1119 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001120 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1121 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001122 url="https://"+host+"/xyz/openbmc_project/logging/entry/" + str(args.selNum) + "/attr/Resolved"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001123 data = "{\"data\": 1 }"
Justin Thalere412dc22018-01-12 16:28:24 -06001124 try:
Justin Thaler27197622019-01-23 14:42:11 -06001125 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001126 except(requests.exceptions.Timeout):
1127 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001128 if res.status_code == 200:
1129 return "Sel entry "+ str(args.selNum) +" is now set to resolved"
1130 else:
1131 return "Unable to set the alert to resolved"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001132
Justin Thalere412dc22018-01-12 16:28:24 -06001133def selResolveAll(host, args, session):
1134 """
1135 sets a sel entry to resolved
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001136
Justin Thalere412dc22018-01-12 16:28:24 -06001137 @param host: string, the hostname or IP address of the bmc
1138 @param args: contains additional arguments used by the fru sub command
1139 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001140 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1141 """
Justin Thalere412dc22018-01-12 16:28:24 -06001142 rawselEntries = sel(host, args, session)
1143 loadFailed = False
1144 try:
1145 selEntries = json.loads(rawselEntries)
1146 except ValueError:
1147 loadFailed = True
1148 if loadFailed:
1149 cleanSels = json.dumps(rawselEntries).replace('\\n', '')
1150 #need to load json twice as original content was string escaped a second time
1151 selEntries = json.loads(json.loads(cleanSels))
1152 selEntries = selEntries['data']
1153
1154 if 'description' in selEntries:
1155 if(args.json):
1156 return("{\n\t\"selsResolved\": 0\n}")
1157 else:
1158 return("No log entries found")
1159 else:
1160 d = vars(args)
1161 successlist = []
1162 failedlist = []
1163 for key in selEntries:
1164 if 'callout' not in key:
1165 d['selNum'] = key.split('/')[-1]
1166 resolved = selSetResolved(host,args,session)
1167 if 'Sel entry' in resolved:
1168 successlist.append(d['selNum'])
1169 else:
1170 failedlist.append(d['selNum'])
1171 output = ""
1172 successlist.sort()
1173 failedlist.sort()
1174 if len(successlist)>0:
1175 output = "Successfully resolved: " +', '.join(successlist) +"\n"
1176 if len(failedlist)>0:
1177 output += "Failed to resolve: " + ', '.join(failedlist) + "\n"
1178 return output
1179
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001180def chassisPower(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001181 """
1182 called by the chassis function. Controls the power state of the chassis, or gets the status
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001183
Justin Thalere412dc22018-01-12 16:28:24 -06001184 @param host: string, the hostname or IP address of the bmc
1185 @param args: contains additional arguments used by the fru sub command
1186 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001187 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1188 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001189 if(args.powcmd == 'on'):
Justin Thaler22b1bb52018-03-15 13:31:32 -05001190 if checkFWactivation(host, args, session):
1191 return ("Chassis Power control disabled during firmware activation")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001192 print("Attempting to Power on...:")
1193 url="https://"+host+"/xyz/openbmc_project/state/host0/attr/RequestedHostTransition"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001194 data = '{"data":"xyz.openbmc_project.State.Host.Transition.On"}'
Justin Thalere412dc22018-01-12 16:28:24 -06001195 try:
Justin Thaler27197622019-01-23 14:42:11 -06001196 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001197 except(requests.exceptions.Timeout):
1198 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001199 return res.text
Justin Thalere412dc22018-01-12 16:28:24 -06001200 elif(args.powcmd == 'softoff'):
Justin Thaler22b1bb52018-03-15 13:31:32 -05001201 if checkFWactivation(host, args, session):
1202 return ("Chassis Power control disabled during firmware activation")
Justin Thalere412dc22018-01-12 16:28:24 -06001203 print("Attempting to Power off gracefully...:")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001204 url="https://"+host+"/xyz/openbmc_project/state/host0/attr/RequestedHostTransition"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001205 data = '{"data":"xyz.openbmc_project.State.Host.Transition.Off"}'
Justin Thalere412dc22018-01-12 16:28:24 -06001206 try:
Justin Thaler27197622019-01-23 14:42:11 -06001207 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001208 except(requests.exceptions.Timeout):
1209 return(connectionErrHandler(args.json, "Timeout", None))
1210 return res.text
1211 elif(args.powcmd == 'hardoff'):
Justin Thaler22b1bb52018-03-15 13:31:32 -05001212 if checkFWactivation(host, args, session):
1213 return ("Chassis Power control disabled during firmware activation")
Justin Thalere412dc22018-01-12 16:28:24 -06001214 print("Attempting to Power off immediately...:")
1215 url="https://"+host+"/xyz/openbmc_project/state/chassis0/attr/RequestedPowerTransition"
Justin Thalere412dc22018-01-12 16:28:24 -06001216 data = '{"data":"xyz.openbmc_project.State.Chassis.Transition.Off"}'
1217 try:
Justin Thaler27197622019-01-23 14:42:11 -06001218 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001219 except(requests.exceptions.Timeout):
1220 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001221 return res.text
1222 elif(args.powcmd == 'status'):
1223 url="https://"+host+"/xyz/openbmc_project/state/chassis0/attr/CurrentPowerState"
Justin Thalere412dc22018-01-12 16:28:24 -06001224 try:
Justin Thaler27197622019-01-23 14:42:11 -06001225 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001226 except(requests.exceptions.Timeout):
1227 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001228 chassisState = json.loads(res.text)['data'].split('.')[-1]
1229 url="https://"+host+"/xyz/openbmc_project/state/host0/attr/CurrentHostState"
Justin Thalere412dc22018-01-12 16:28:24 -06001230 try:
Justin Thaler27197622019-01-23 14:42:11 -06001231 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001232 except(requests.exceptions.Timeout):
1233 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001234 hostState = json.loads(res.text)['data'].split('.')[-1]
1235 url="https://"+host+"/xyz/openbmc_project/state/bmc0/attr/CurrentBMCState"
Justin Thalere412dc22018-01-12 16:28:24 -06001236 try:
Justin Thaler27197622019-01-23 14:42:11 -06001237 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001238 except(requests.exceptions.Timeout):
1239 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001240 bmcState = json.loads(res.text)['data'].split('.')[-1]
1241 if(args.json):
1242 outDict = {"Chassis Power State" : chassisState, "Host Power State" : hostState, "BMC Power State":bmcState}
1243 return json.dumps(outDict, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False)
1244 else:
1245 return "Chassis Power State: " +chassisState + "\nHost Power State: " + hostState + "\nBMC Power State: " + bmcState
1246 else:
1247 return "Invalid chassis power command"
1248
Justin Thalere412dc22018-01-12 16:28:24 -06001249
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001250def chassisIdent(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001251 """
1252 called by the chassis function. Controls the identify led of the chassis. Sets or gets the state
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001253
Justin Thalere412dc22018-01-12 16:28:24 -06001254 @param host: string, the hostname or IP address of the bmc
1255 @param args: contains additional arguments used by the fru sub command
1256 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001257 @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 -06001258 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001259 if(args.identcmd == 'on'):
1260 print("Attempting to turn identify light on...:")
1261 url="https://"+host+"/xyz/openbmc_project/led/groups/enclosure_identify/attr/Asserted"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001262 data = '{"data":true}'
Justin Thalere412dc22018-01-12 16:28:24 -06001263 try:
Justin Thaler27197622019-01-23 14:42:11 -06001264 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001265 except(requests.exceptions.Timeout):
1266 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001267 return res.text
1268 elif(args.identcmd == 'off'):
1269 print("Attempting to turn identify light off...:")
1270 url="https://"+host+"/xyz/openbmc_project/led/groups/enclosure_identify/attr/Asserted"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001271 data = '{"data":false}'
Justin Thalere412dc22018-01-12 16:28:24 -06001272 try:
Justin Thaler27197622019-01-23 14:42:11 -06001273 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001274 except(requests.exceptions.Timeout):
1275 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001276 return res.text
1277 elif(args.identcmd == 'status'):
1278 url="https://"+host+"/xyz/openbmc_project/led/groups/enclosure_identify"
Justin Thalere412dc22018-01-12 16:28:24 -06001279 try:
Justin Thaler27197622019-01-23 14:42:11 -06001280 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001281 except(requests.exceptions.Timeout):
1282 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001283 status = json.loads(res.text)['data']
1284 if(args.json):
1285 return status
1286 else:
1287 if status['Asserted'] == 0:
1288 return "Identify light is off"
1289 else:
1290 return "Identify light is blinking"
1291 else:
1292 return "Invalid chassis identify command"
1293
Justin Thalere412dc22018-01-12 16:28:24 -06001294
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001295def chassis(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001296 """
1297 controls the different chassis commands
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001298
Justin Thalere412dc22018-01-12 16:28:24 -06001299 @param host: string, the hostname or IP address of the bmc
1300 @param args: contains additional arguments used by the fru sub command
1301 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001302 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1303 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001304 if(hasattr(args, 'powcmd')):
1305 result = chassisPower(host,args,session)
1306 elif(hasattr(args, 'identcmd')):
1307 result = chassisIdent(host, args, session)
1308 else:
Justin Thaler22b1bb52018-03-15 13:31:32 -05001309 return "This feature is not yet implemented"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001310 return result
Justin Thalere412dc22018-01-12 16:28:24 -06001311
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001312def bmcDumpRetrieve(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001313 """
1314 Downloads a dump file from the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001315
Justin Thalere412dc22018-01-12 16:28:24 -06001316 @param host: string, the hostname or IP address of the bmc
1317 @param args: contains additional arguments used by the collectServiceData sub command
1318 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001319 @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 -06001320 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001321 dumpNum = args.dumpNum
1322 if (args.dumpSaveLoc is not None):
1323 saveLoc = args.dumpSaveLoc
1324 else:
Justin Thalercf1deae2018-05-25 19:35:21 -05001325 saveLoc = tempfile.gettempdir()
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001326 url ='https://'+host+'/download/dump/' + str(dumpNum)
1327 try:
Justin Thaler27197622019-01-23 14:42:11 -06001328 r = session.get(url, headers=jsonHeader, stream=True, verify=False, timeout=baseTimeout)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001329 if (args.dumpSaveLoc is not None):
1330 if os.path.exists(saveLoc):
1331 if saveLoc[-1] != os.path.sep:
1332 saveLoc = saveLoc + os.path.sep
1333 filename = saveLoc + host+'-dump' + str(dumpNum) + '.tar.xz'
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001334
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001335 else:
1336 return 'Invalid save location specified'
1337 else:
Justin Thalercf1deae2018-05-25 19:35:21 -05001338 filename = tempfile.gettempdir()+os.sep + host+'-dump' + str(dumpNum) + '.tar.xz'
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001339
1340 with open(filename, 'wb') as f:
1341 for chunk in r.iter_content(chunk_size =1024):
1342 if chunk:
1343 f.write(chunk)
1344 return 'Saved as ' + filename
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001345
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001346 except(requests.exceptions.Timeout):
1347 return connectionErrHandler(args.json, "Timeout", None)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001348
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001349 except(requests.exceptions.ConnectionError) as err:
1350 return connectionErrHandler(args.json, "ConnectionError", err)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001351
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001352def bmcDumpList(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001353 """
1354 Lists the number of dump files on the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001355
Justin Thalere412dc22018-01-12 16:28:24 -06001356 @param host: string, the hostname or IP address of the bmc
1357 @param args: contains additional arguments used by the collectServiceData sub command
1358 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001359 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1360 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001361 url ='https://'+host+'/xyz/openbmc_project/dump/list'
1362 try:
Justin Thaler27197622019-01-23 14:42:11 -06001363 r = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thaler3a5771b2019-01-23 14:31:52 -06001364 dumpList = r.json()
1365 return dumpList
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001366 except(requests.exceptions.Timeout):
1367 return connectionErrHandler(args.json, "Timeout", None)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001368
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001369 except(requests.exceptions.ConnectionError) as err:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001370 return connectionErrHandler(args.json, "ConnectionError", err)
1371
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001372def bmcDumpDelete(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001373 """
1374 Deletes BMC dump files from the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001375
Justin Thalere412dc22018-01-12 16:28:24 -06001376 @param host: string, the hostname or IP address of the bmc
1377 @param args: contains additional arguments used by the collectServiceData sub command
1378 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001379 @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 -06001380 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001381 dumpList = []
1382 successList = []
1383 failedList = []
1384 if args.dumpNum is not None:
1385 if isinstance(args.dumpNum, list):
1386 dumpList = args.dumpNum
1387 else:
1388 dumpList.append(args.dumpNum)
1389 for dumpNum in dumpList:
1390 url ='https://'+host+'/xyz/openbmc_project/dump/entry/'+str(dumpNum)+'/action/Delete'
1391 try:
Justin Thaler27197622019-01-23 14:42:11 -06001392 r = session.post(url, headers=jsonHeader, json = {"data": []}, verify=False, timeout=baseTimeout)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001393 if r.status_code == 200:
1394 successList.append(str(dumpNum))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001395 else:
1396 failedList.append(str(dumpNum))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001397 except(requests.exceptions.Timeout):
1398 return connectionErrHandler(args.json, "Timeout", None)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001399 except(requests.exceptions.ConnectionError) as err:
1400 return connectionErrHandler(args.json, "ConnectionError", err)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001401 output = "Successfully deleted dumps: " + ', '.join(successList)
1402 if(len(failedList)>0):
1403 output+= '\nFailed to delete dumps: ' + ', '.join(failedList)
1404 return output
1405 else:
1406 return 'You must specify an entry number to delete'
1407
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001408def bmcDumpDeleteAll(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001409 """
1410 Deletes All BMC dump files from the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001411
Justin Thalere412dc22018-01-12 16:28:24 -06001412 @param host: string, the hostname or IP address of the bmc
1413 @param args: contains additional arguments used by the collectServiceData sub command
1414 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001415 @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 -06001416 """
1417 dumpResp = bmcDumpList(host, args, session)
1418 if 'FQPSPIN0000M' in dumpResp or 'FQPSPIN0001M'in dumpResp:
1419 return dumpResp
Justin Thaler3a5771b2019-01-23 14:31:52 -06001420 dumpList = dumpResp['data']
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001421 d = vars(args)
1422 dumpNums = []
1423 for dump in dumpList:
1424 if '/xyz/openbmc_project/dump/internal/manager' not in dump:
1425 dumpNums.append(int(dump.strip().split('/')[-1]))
1426 d['dumpNum'] = dumpNums
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001427
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001428 return bmcDumpDelete(host, args, session)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001429
Justin Thalere412dc22018-01-12 16:28:24 -06001430
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001431def bmcDumpCreate(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001432 """
1433 Creates a bmc dump file
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001434
Justin Thalere412dc22018-01-12 16:28:24 -06001435 @param host: string, the hostname or IP address of the bmc
1436 @param args: contains additional arguments used by the collectServiceData sub command
1437 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001438 @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 -06001439 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001440 url = 'https://'+host+'/xyz/openbmc_project/dump/action/CreateDump'
1441 try:
Justin Thaler27197622019-01-23 14:42:11 -06001442 r = session.post(url, headers=jsonHeader, json = {"data": []}, verify=False, timeout=baseTimeout)
Matt Spinlereae05b02019-01-24 12:59:34 -06001443 if(r.status_code == 200 and not args.json):
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001444 return ('Dump successfully created')
Justin Thaler3a5771b2019-01-23 14:31:52 -06001445 elif(args.json):
1446 return r.json()
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001447 else:
1448 return ('Failed to create dump')
1449 except(requests.exceptions.Timeout):
1450 return connectionErrHandler(args.json, "Timeout", None)
1451 except(requests.exceptions.ConnectionError) as err:
1452 return connectionErrHandler(args.json, "ConnectionError", err)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001453
1454
Justin Thaler666cf342019-01-23 14:44:27 -06001455def csdDumpInitiate(host, args, session):
1456 """
1457 Starts the process of getting the current list of dumps then initiates the creation of one.
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001458
Justin Thaler666cf342019-01-23 14:44:27 -06001459 @param host: string, the hostname or IP address of the bmc
1460 @param args: contains additional arguments used by the collectServiceData sub command
1461 @param session: the active session to use
1462 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1463 """
1464 errorInfo = ""
1465 dumpcount = 0
1466 try:
1467 d = vars(args)
1468 d['json'] = True
1469 except Exception as e:
1470 errorInfo += "Failed to set the json flag to True \n Exception: {eInfo}\n".format(eInfo=e)
1471
1472 try:
1473 for i in range(3):
1474 dumpInfo = bmcDumpList(host, args, session)
1475 if 'data' in dumpInfo:
1476 dumpcount = len(dumpInfo['data'])
1477 break
1478 else:
1479 errorInfo+= "Dump List Message returned: " + json.dumps(dumpInfo,indent=0, separators=(',', ':')).replace('\n','') +"\n"
1480 except Exception as e:
1481 errorInfo+= "Failed to collect the list of dumps.\nException: {eInfo}\n".format(eInfo=e)
1482
1483 #Create a user initiated dump
1484 try:
1485 for i in range(3):
1486 dumpcreated = bmcDumpCreate(host, args, session)
1487 if 'message' in dumpcreated:
1488 if 'ok' in dumpcreated['message'].lower():
1489 break
1490 else:
1491 errorInfo+= "Dump create message returned: " + json.dumps(dumpInfo,indent=0, separators=(',', ':')).replace('\n','') +"\n"
1492 else:
1493 errorInfo+= "Dump create message returned: " + json.dumps(dumpInfo,indent=0, separators=(',', ':')).replace('\n','') +"\n"
1494 except Exception as e:
1495 errorInfo+= "Dump create exception encountered: {eInfo}\n".format(eInfo=e)
1496
1497 output = {}
1498 output['errors'] = errorInfo
1499 output['dumpcount'] = dumpcount
1500 return output
1501
1502def csdInventory(host, args,session, fileDir):
1503 """
1504 Collects the BMC inventory, retrying if necessary
1505
1506 @param host: string, the hostname or IP address of the bmc
1507 @param args: contains additional arguments used by the collectServiceData sub command
1508 @param session: the active session to use
1509 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1510 @param fileDir: string representation of the path to use for putting files created
1511 """
1512 errorInfo = "===========Inventory =============\n"
1513 output={}
1514 inventoryCollected = False
1515 try:
1516 for i in range(3):
1517 frulist = fruPrint(host, args, session)
1518 if 'Hardware' in frulist:
1519 inventoryCollected = True
1520 break
1521 else:
1522 errorInfo += json.dumps(frulist, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n'
1523 except Exception as e:
1524 errorInfo += "Inventory collection exception: {eInfo}\n".format(eInfo=e)
1525 if inventoryCollected:
1526 try:
1527 with open(fileDir +os.sep+'inventory.txt', 'w') as f:
1528 f.write(json.dumps(frulist, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n')
1529 print("Inventory collected and stored in " + fileDir + os.sep + "inventory.txt")
1530 output['fileLoc'] = fileDir+os.sep+'inventory.txt'
1531 except Exception as e:
1532 print("Failed to write inventory to file.")
1533 errorInfo += "Error writing inventory to the file. Exception: {eInfo}\n".format(eInfo=e)
1534
1535 output['errors'] = errorInfo
1536
1537 return output
1538
1539def csdSensors(host, args,session, fileDir):
1540 """
1541 Collects the BMC sensor readings, retrying if necessary
1542
1543 @param host: string, the hostname or IP address of the bmc
1544 @param args: contains additional arguments used by the collectServiceData sub command
1545 @param session: the active session to use
1546 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1547 @param fileDir: string representation of the path to use for putting files created
1548 """
1549 errorInfo = "===========Sensors =============\n"
1550 sensorsCollected = False
1551 output={}
1552 try:
1553 d = vars(args)
1554 d['json'] = False
1555 except Exception as e:
1556 errorInfo += "Failed to set the json flag to False \n Exception: {eInfo}\n".format(eInfo=e)
1557
1558 try:
1559 for i in range(3):
1560 sensorReadings = sensor(host, args, session)
1561 if 'OCC0' in sensorReadings:
1562 sensorsCollected = True
1563 break
1564 else:
1565 errorInfo += sensorReadings
1566 except Exception as e:
1567 errorInfo += "Sensor reading collection exception: {eInfo}\n".format(eInfo=e)
1568 if sensorsCollected:
1569 try:
1570 with open(fileDir +os.sep+'sensorReadings.txt', 'w') as f:
1571 f.write(sensorReadings)
1572 print("Sensor readings collected and stored in " + fileDir + os.sep+ "sensorReadings.txt")
1573 output['fileLoc'] = fileDir+os.sep+'sensorReadings.txt'
1574 except Exception as e:
1575 print("Failed to write sensor readings to file system.")
1576 errorInfo += "Error writing sensor readings to the file. Exception: {eInfo}\n".format(eInfo=e)
1577
1578 output['errors'] = errorInfo
1579 return output
1580
1581def csdLEDs(host,args, session, fileDir):
1582 """
1583 Collects the BMC LED status, retrying if necessary
1584
1585 @param host: string, the hostname or IP address of the bmc
1586 @param args: contains additional arguments used by the collectServiceData sub command
1587 @param session: the active session to use
1588 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1589 @param fileDir: string representation of the path to use for putting files created
1590 """
1591 errorInfo = "===========LEDs =============\n"
1592 ledsCollected = False
1593 output={}
1594 try:
1595 d = vars(args)
1596 d['json'] = True
1597 except Exception as e:
1598 errorInfo += "Failed to set the json flag to False \n Exception: {eInfo}\n".format(eInfo=e)
1599 try:
1600 url="https://"+host+"/xyz/openbmc_project/led/enumerate"
1601 httpHeader = {'Content-Type':'application/json'}
1602 for i in range(3):
1603 try:
1604 ledRes = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
1605 if ledRes.status_code == 200:
1606 ledsCollected = True
1607 leds = ledRes.json()['data']
1608 break
1609 else:
1610 errorInfo += ledRes.text
1611 except(requests.exceptions.Timeout):
1612 errorInfo+=json.dumps( connectionErrHandler(args.json, "Timeout", None), sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n'
1613 except(requests.exceptions.ConnectionError) as err:
1614 errorInfo += json.dumps(connectionErrHandler(args.json, "ConnectionError", err), sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n'
1615 except Exception as e:
1616 errorInfo += "LED status collection exception: {eInfo}\n".format(eInfo=e)
1617
1618 if ledsCollected:
1619 try:
1620 with open(fileDir +os.sep+'ledStatus.txt', 'w') as f:
1621 f.write(json.dumps(leds, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n')
1622 print("LED status collected and stored in " + fileDir + os.sep+ "ledStatus.txt")
1623 output['fileLoc'] = fileDir+os.sep+'ledStatus.txt'
1624 except Exception as e:
1625 print("Failed to write LED status to file system.")
1626 errorInfo += "Error writing LED status to the file. Exception: {eInfo}\n".format(eInfo=e)
1627
1628 output['errors'] = errorInfo
1629 return output
1630
1631def csdSelShortList(host, args, session, fileDir):
1632 """
1633 Collects the BMC log entries, retrying if necessary
1634
1635 @param host: string, the hostname or IP address of the bmc
1636 @param args: contains additional arguments used by the collectServiceData sub command
1637 @param session: the active session to use
1638 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1639 @param fileDir: string representation of the path to use for putting files created
1640 """
1641 errorInfo = "===========SEL Short List =============\n"
1642 selsCollected = False
1643 output={}
1644 try:
1645 d = vars(args)
1646 d['json'] = False
1647 except Exception as e:
1648 errorInfo += "Failed to set the json flag to False \n Exception: {eInfo}\n".format(eInfo=e)
1649
1650 try:
1651 for i in range(3):
1652 sels = selPrint(host,args,session)
1653 if '----Active Alerts----' in sels or 'No log entries found' in sels or '----Historical Alerts----' in sels:
1654 selsCollected = True
1655 break
1656 else:
1657 errorInfo += sels + '\n'
1658 except Exception as e:
1659 errorInfo += "SEL short list collection exception: {eInfo}\n".format(eInfo=e)
1660
1661 if selsCollected:
1662 try:
1663 with open(fileDir +os.sep+'SELshortlist.txt', 'w') as f:
1664 f.write(sels)
1665 print("SEL short list collected and stored in " + fileDir + os.sep+ "SELshortlist.txt")
1666 output['fileLoc'] = fileDir+os.sep+'SELshortlist.txt'
1667 except Exception as e:
1668 print("Failed to write SEL short list to file system.")
1669 errorInfo += "Error writing SEL short list to the file. Exception: {eInfo}\n".format(eInfo=e)
1670
1671 output['errors'] = errorInfo
1672 return output
1673
1674def csdParsedSels(host, args, session, fileDir):
1675 """
1676 Collects the BMC log entries, retrying if necessary
1677
1678 @param host: string, the hostname or IP address of the bmc
1679 @param args: contains additional arguments used by the collectServiceData sub command
1680 @param session: the active session to use
1681 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1682 @param fileDir: string representation of the path to use for putting files created
1683 """
1684 errorInfo = "===========SEL Parsed List =============\n"
1685 selsCollected = False
1686 output={}
1687 try:
1688 d = vars(args)
1689 d['json'] = True
1690 d['fullEsel'] = True
1691 except Exception as e:
1692 errorInfo += "Failed to set the json flag to True \n Exception: {eInfo}\n".format(eInfo=e)
1693
1694 try:
1695 for i in range(3):
1696 parsedfullsels = json.loads(selPrint(host,args,session))
1697 if 'numAlerts' in parsedfullsels:
1698 selsCollected = True
1699 break
1700 else:
1701 errorInfo += parsedfullsels + '\n'
1702 except Exception as e:
1703 errorInfo += "Parsed full SELs collection exception: {eInfo}\n".format(eInfo=e)
1704
1705 if selsCollected:
1706 try:
1707 sortedSELs = sortSELs(parsedfullsels)
1708 with open(fileDir +os.sep+'parsedSELs.txt', 'w') as f:
1709 for log in sortedSELs[0]:
1710 esel = ""
1711 parsedfullsels[sortedSELs[1][str(log)]]['timestamp'] = datetime.datetime.fromtimestamp(int(parsedfullsels[sortedSELs[1][str(log)]]['timestamp']/1000)).strftime("%Y-%m-%d %H:%M:%S")
1712 if ('raweSEL' in parsedfullsels[sortedSELs[1][str(log)]] and args.devdebug):
1713 esel = parsedfullsels[sortedSELs[1][str(log)]]['raweSEL']
1714 del parsedfullsels[sortedSELs[1][str(log)]]['raweSEL']
1715 f.write(json.dumps(parsedfullsels[sortedSELs[1][str(log)]],sort_keys=True, indent=4, separators=(',', ': ')))
1716 if(args.devdebug and esel != ""):
1717 f.write(parseESEL(args, esel))
1718 print("Parsed SELs collected and stored in " + fileDir + os.sep+ "parsedSELs.txt")
1719 output['fileLoc'] = fileDir+os.sep+'parsedSELs.txt'
1720 except Exception as e:
1721 print("Failed to write fully parsed SELs to file system.")
1722 errorInfo += "Error writing fully parsed SELs to the file. Exception: {eInfo}\n".format(eInfo=e)
1723
1724 output['errors'] = errorInfo
1725 return output
1726
1727def csdFullEnumeration(host, args, session, fileDir):
1728 """
1729 Collects a full enumeration of /xyz/openbmc_project/, retrying if necessary
1730
1731 @param host: string, the hostname or IP address of the bmc
1732 @param args: contains additional arguments used by the collectServiceData sub command
1733 @param session: the active session to use
1734 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1735 @param fileDir: string representation of the path to use for putting files created
1736 """
1737 errorInfo = "===========BMC Full Enumeration =============\n"
1738 bmcFullCollected = False
1739 output={}
1740 try:
1741 d = vars(args)
1742 d['json'] = True
1743 except Exception as e:
1744 errorInfo += "Failed to set the json flag to False \n Exception: {eInfo}\n".format(eInfo=e)
1745 try:
1746 print("Attempting to get a full BMC enumeration")
1747 url="https://"+host+"/xyz/openbmc_project/enumerate"
1748 httpHeader = {'Content-Type':'application/json'}
1749 for i in range(3):
1750 try:
1751 bmcRes = session.get(url, headers=jsonHeader, verify=False, timeout=180)
1752 if bmcRes.status_code == 200:
1753 bmcFullCollected = True
1754 fullEnumeration = bmcRes.json()
1755 break
1756 else:
1757 errorInfo += bmcRes.text
1758 except(requests.exceptions.Timeout):
1759 errorInfo+=json.dumps( connectionErrHandler(args.json, "Timeout", None), sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n'
1760 except(requests.exceptions.ConnectionError) as err:
1761 errorInfo += json.dumps(connectionErrHandler(args.json, "ConnectionError", err), sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n'
1762 except Exception as e:
1763 errorInfo += "RAW BMC data collection exception: {eInfo}\n".format(eInfo=e)
1764
1765 if bmcFullCollected:
1766 try:
1767 with open(fileDir +os.sep+'bmcFullRaw.txt', 'w') as f:
1768 f.write(json.dumps(fullEnumeration, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n')
1769 print("RAW BMC data collected and saved into " + fileDir + os.sep+ "bmcFullRaw.txt")
1770 output['fileLoc'] = fileDir+os.sep+'bmcFullRaw.txt'
1771 except Exception as e:
1772 print("Failed to write RAW BMC data to file system.")
1773 errorInfo += "Error writing RAW BMC data collection to the file. Exception: {eInfo}\n".format(eInfo=e)
1774
1775 output['errors'] = errorInfo
1776 return output
1777
1778def csdCollectAllDumps(host, args, session, fileDir):
1779 """
1780 Collects all of the bmc dump files and stores them in fileDir
1781
1782 @param host: string, the hostname or IP address of the bmc
1783 @param args: contains additional arguments used by the collectServiceData sub command
1784 @param session: the active session to use
1785 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1786 @param fileDir: string representation of the path to use for putting files created
1787 """
1788
1789 errorInfo = "===========BMC Dump Collection =============\n"
1790 dumpListCollected = False
1791 output={}
1792 dumpList = {}
1793 try:
1794 d = vars(args)
1795 d['json'] = True
1796 d['dumpSaveLoc'] = fileDir
1797 except Exception as e:
1798 errorInfo += "Failed to set the json flag to True, or failed to set the dumpSave Location \n Exception: {eInfo}\n".format(eInfo=e)
1799
1800 print('Collecting bmc dump files')
1801
1802 try:
1803 for i in range(3):
1804 dumpResp = bmcDumpList(host, args, session)
1805 if 'message' in dumpResp:
1806 if 'ok' in dumpResp['message'].lower():
1807 dumpList = dumpResp['data']
1808 dumpListCollected = True
1809 break
1810 else:
1811 errorInfo += "Status was not OK when retrieving the list of dumps available. \n Response: \n{resp}\n".format(resp=dumpResp)
1812 else:
1813 errorInfo += "Invalid response received from the BMC while retrieving the list of dumps available.\n {resp}\n".format(resp=dumpResp)
1814 except Exception as e:
1815 errorInfo += "BMC dump list exception: {eInfo}\n".format(eInfo=e)
1816
1817 if dumpListCollected:
1818 output['fileList'] = []
1819 for dump in dumpList:
1820 try:
1821 if '/xyz/openbmc_project/dump/internal/manager' not in dump:
1822 d['dumpNum'] = int(dump.strip().split('/')[-1])
1823 print('retrieving dump file ' + str(d['dumpNum']))
1824 filename = bmcDumpRetrieve(host, args, session).split('Saved as ')[-1]
1825 output['fileList'].append(filename)
1826 except Exception as e:
1827 print("Unable to collect dump: {dumpInfo}".format(dumpInfo=dump))
1828 errorInfo += "Exception collecting a bmc dump {dumpInfo}\n {eInfo}\n".format(dumpInfo=dump, eInfo=e)
1829 output['errors'] = errorInfo
1830 return output
Justin Thalere412dc22018-01-12 16:28:24 -06001831
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001832def collectServiceData(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001833 """
1834 Collects all data needed for service from the BMC
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001835
Justin Thalere412dc22018-01-12 16:28:24 -06001836 @param host: string, the hostname or IP address of the bmc
1837 @param args: contains additional arguments used by the collectServiceData sub command
1838 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001839 @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 -06001840 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001841
Justin Thaler22b1bb52018-03-15 13:31:32 -05001842 global toolVersion
Justin Thaler666cf342019-01-23 14:44:27 -06001843 filelist = []
1844 errorInfo = ""
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001845
Justin Thaler666cf342019-01-23 14:44:27 -06001846 #get current number of bmc dumps and create a new bmc dump
1847 dumpInitdata = csdDumpInitiate(host, args, session)
1848 dumpcount = dumpInitdata['dumpcount']
1849 errorInfo += dumpInitdata['errors']
1850 #create the directory to put files
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001851 try:
1852 args.silent = True
Justin Thalercf1deae2018-05-25 19:35:21 -05001853 myDir = tempfile.gettempdir()+os.sep + host + "--" + datetime.datetime.now().strftime("%Y-%m-%d_%H.%M.%S")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001854 os.makedirs(myDir)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001855
Justin Thaler666cf342019-01-23 14:44:27 -06001856 except Exception as e:
1857 print('Unable to create the temporary directory for data collection. Ensure sufficient privileges to create temporary directory. Aborting.')
1858 return("Python exception: {eInfo}".format(eInfo = e))
1859
1860 #Collect Inventory
1861 inventoryData = csdInventory(host, args, session, myDir)
1862 if 'fileLoc' in inventoryData:
1863 filelist.append(inventoryData['fileLoc'])
1864 errorInfo += inventoryData['errors']
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001865 #Read all the sensor and OCC status
Justin Thaler666cf342019-01-23 14:44:27 -06001866 sensorData = csdSensors(host,args,session,myDir)
1867 if 'fileLoc' in sensorData:
1868 filelist.append(sensorData['fileLoc'])
1869 errorInfo += sensorData['errors']
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001870 #Collect all of the LEDs status
Justin Thaler666cf342019-01-23 14:44:27 -06001871 ledStatus = csdLEDs(host, args, session, myDir)
1872 if 'fileLoc' in ledStatus:
1873 filelist.append(ledStatus['fileLoc'])
1874 errorInfo += ledStatus['errors']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001875
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001876 #Collect the bmc logs
Justin Thaler666cf342019-01-23 14:44:27 -06001877 selShort = csdSelShortList(host, args, session, myDir)
1878 if 'fileLoc' in selShort:
1879 filelist.append(selShort['fileLoc'])
1880 errorInfo += selShort['errors']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001881
Justin Thaler666cf342019-01-23 14:44:27 -06001882 parsedSELs = csdParsedSels(host, args, session, myDir)
1883 if 'fileLoc' in parsedSELs:
1884 filelist.append(parsedSELs['fileLoc'])
1885 errorInfo += parsedSELs['errors']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001886
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001887 #collect RAW bmc enumeration
Justin Thaler666cf342019-01-23 14:44:27 -06001888 bmcRaw = csdFullEnumeration(host, args, session, myDir)
1889 if 'fileLoc' in bmcRaw:
1890 filelist.append(bmcRaw['fileLoc'])
1891 errorInfo += bmcRaw['errors']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001892
Justin Thaler666cf342019-01-23 14:44:27 -06001893 #wait for new dump to finish being created
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001894 waitingForNewDump = True
1895 count = 0;
Justin Thaler666cf342019-01-23 14:44:27 -06001896 print("Waiting for new BMC dump to finish being created.")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001897 while(waitingForNewDump):
Justin Thaler666cf342019-01-23 14:44:27 -06001898 dumpList = bmcDumpList(host, args, session)['data']
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001899 if len(dumpList) > dumpcount:
1900 waitingForNewDump = False
1901 break;
1902 elif(count>30):
1903 print("Timed out waiting for bmc to make a new dump file. Dump space may be full.")
1904 break;
1905 else:
1906 time.sleep(2)
1907 count += 1
Justin Thaler666cf342019-01-23 14:44:27 -06001908
1909 #collect all of the dump files
1910 getBMCDumps = csdCollectAllDumps(host, args, session, myDir)
1911 if 'fileList' in getBMCDumps:
1912 filelist+= getBMCDumps['fileList']
1913 errorInfo += getBMCDumps['errors']
1914
1915 #write the runtime errors to a file
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001916 try:
Justin Thaler666cf342019-01-23 14:44:27 -06001917 with open(myDir +os.sep+'openbmctoolRuntimeErrors.txt', 'w') as f:
1918 f.write(errorInfo)
1919 print("OpenBMC tool runtime errors collected and stored in " + myDir + os.sep+ "openbmctoolRuntimeErrors.txt")
1920 filelist.append(myDir+os.sep+'openbmctoolRuntimeErrors.txt')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001921 except Exception as e:
Justin Thaler666cf342019-01-23 14:44:27 -06001922 print("Failed to write OpenBMC tool runtime errors to file system.")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001923
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001924 #create the zip file
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001925 try:
Justin Thalercf1deae2018-05-25 19:35:21 -05001926 filename = myDir.split(tempfile.gettempdir()+os.sep)[-1] + "_" + toolVersion + '_openbmc.zip'
Justin Thaler666cf342019-01-23 14:44:27 -06001927 zf = zipfile.ZipFile(myDir+os.sep + filename, 'w')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001928 for myfile in filelist:
1929 zf.write(myfile, os.path.basename(myfile))
1930 zf.close()
Justin Thaler666cf342019-01-23 14:44:27 -06001931 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 -06001932 except Exception as e:
1933 print("Failed to create zip file with collected information")
Justin Thaler666cf342019-01-23 14:44:27 -06001934 return "data collection finished"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001935
Justin Thalere412dc22018-01-12 16:28:24 -06001936
1937def healthCheck(host, args, session):
1938 """
1939 runs a health check on the platform
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001940
Justin Thalere412dc22018-01-12 16:28:24 -06001941 @param host: string, the hostname or IP address of the bmc
1942 @param args: contains additional arguments used by the bmc sub command
1943 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001944 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1945 """
Justin Thalere412dc22018-01-12 16:28:24 -06001946 #check fru status and get as json to easily work through
1947 d = vars(args)
1948 useJson = d['json']
1949 d['json'] = True
1950 d['verbose']= False
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001951
Justin Thalere412dc22018-01-12 16:28:24 -06001952 frus = json.loads(fruStatus(host, args, session))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001953
Justin Thalere412dc22018-01-12 16:28:24 -06001954 hwStatus= "OK"
1955 performanceStatus = "OK"
1956 for key in frus:
1957 if frus[key]["Functional"] == "No" and frus[key]["Present"] == "Yes":
1958 hwStatus= "Degraded"
Justin Thalerfb9c81c2018-07-16 11:14:37 -05001959 if("power_supply" in key or "powersupply" in key):
1960 gpuCount =0
1961 for comp in frus:
Justin Thalere412dc22018-01-12 16:28:24 -06001962 if "gv100card" in comp:
1963 gpuCount +=1
1964 if gpuCount > 4:
1965 hwStatus = "Critical"
1966 performanceStatus="Degraded"
1967 break;
1968 elif("fan" in key):
1969 hwStatus = "Degraded"
1970 else:
1971 performanceStatus = "Degraded"
1972 if useJson:
1973 output = {"Hardware Status": hwStatus, "Performance": performanceStatus}
1974 output = json.dumps(output, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False)
1975 else:
1976 output = ("Hardware Status: " + hwStatus +
1977 "\nPerformance: " +performanceStatus )
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001978
1979
Justin Thalere412dc22018-01-12 16:28:24 -06001980 #SW407886: Clear the duplicate entries
1981 #collect the dups
1982 d['devdebug'] = False
1983 sels = json.loads(selPrint(host, args, session))
1984 logNums2Clr = []
1985 oldestLogNum={"logNum": "bogus" ,"key" : ""}
1986 count = 0
1987 if sels['numAlerts'] > 0:
1988 for key in sels:
1989 if "numAlerts" in key:
1990 continue
1991 try:
1992 if "slave@00:00/00:00:00:06/sbefifo1-dev0/occ1-dev0" in sels[key]['Message']:
1993 count += 1
1994 if count > 1:
1995 #preserve first occurrence
1996 if sels[key]['timestamp'] < sels[oldestLogNum['key']]['timestamp']:
1997 oldestLogNum['key']=key
1998 oldestLogNum['logNum'] = sels[key]['logNum']
1999 else:
2000 oldestLogNum['key']=key
2001 oldestLogNum['logNum'] = sels[key]['logNum']
2002 logNums2Clr.append(sels[key]['logNum'])
2003 except KeyError:
2004 continue
2005 if(count >0):
2006 logNums2Clr.remove(oldestLogNum['logNum'])
2007 #delete the dups
2008 if count >1:
Justin Thalere412dc22018-01-12 16:28:24 -06002009 data = "{\"data\": [] }"
2010 for logNum in logNums2Clr:
2011 url = "https://"+ host+ "/xyz/openbmc_project/logging/entry/"+logNum+"/action/Delete"
2012 try:
Justin Thaler27197622019-01-23 14:42:11 -06002013 session.post(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002014 except(requests.exceptions.Timeout):
2015 deleteFailed = True
2016 except(requests.exceptions.ConnectionError) as err:
2017 deleteFailed = True
2018 #End of defect resolve code
2019 d['json'] = useJson
2020 return output
2021
2022
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002023
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002024def bmc(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06002025 """
2026 handles various bmc level commands, currently bmc rebooting
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002027
Justin Thalere412dc22018-01-12 16:28:24 -06002028 @param host: string, the hostname or IP address of the bmc
2029 @param args: contains additional arguments used by the bmc sub command
2030 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002031 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
2032 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002033 if(args.type is not None):
2034 return bmcReset(host, args, session)
Justin Thalere412dc22018-01-12 16:28:24 -06002035 if(args.info):
2036 return "Not implemented at this time"
2037
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002038
Justin Thalere412dc22018-01-12 16:28:24 -06002039
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002040def bmcReset(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06002041 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002042 controls resetting the bmc. warm reset reboots the bmc, cold reset removes the configuration and reboots.
2043
Justin Thalere412dc22018-01-12 16:28:24 -06002044 @param host: string, the hostname or IP address of the bmc
2045 @param args: contains additional arguments used by the bmcReset sub command
2046 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002047 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
2048 """
Justin Thaler22b1bb52018-03-15 13:31:32 -05002049 if checkFWactivation(host, args, session):
2050 return ("BMC reset control disabled during firmware activation")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002051 if(args.type == "warm"):
2052 print("\nAttempting to reboot the BMC...:")
2053 url="https://"+host+"/xyz/openbmc_project/state/bmc0/attr/RequestedBMCTransition"
Justin Thalere412dc22018-01-12 16:28:24 -06002054 data = '{"data":"xyz.openbmc_project.State.BMC.Transition.Reboot"}'
Justin Thaler27197622019-01-23 14:42:11 -06002055 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002056 return res.text
2057 elif(args.type =="cold"):
Justin Thalere412dc22018-01-12 16:28:24 -06002058 print("\nAttempting to reboot the BMC...:")
2059 url="https://"+host+"/xyz/openbmc_project/state/bmc0/attr/RequestedBMCTransition"
Justin Thalere412dc22018-01-12 16:28:24 -06002060 data = '{"data":"xyz.openbmc_project.State.BMC.Transition.Reboot"}'
Justin Thaler27197622019-01-23 14:42:11 -06002061 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002062 return res.text
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002063 else:
2064 return "invalid command"
Justin Thalere412dc22018-01-12 16:28:24 -06002065
2066def gardClear(host, args, session):
2067 """
2068 clears the gard records from the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002069
Justin Thalere412dc22018-01-12 16:28:24 -06002070 @param host: string, the hostname or IP address of the bmc
2071 @param args: contains additional arguments used by the gardClear sub command
2072 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002073 """
Justin Thalere412dc22018-01-12 16:28:24 -06002074 url="https://"+host+"/org/open_power/control/gard/action/Reset"
Justin Thalere412dc22018-01-12 16:28:24 -06002075 data = '{"data":[]}'
2076 try:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002077
Justin Thaler27197622019-01-23 14:42:11 -06002078 res = session.post(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002079 if res.status_code == 404:
2080 return "Command not supported by this firmware version"
2081 else:
2082 return res.text
2083 except(requests.exceptions.Timeout):
2084 return connectionErrHandler(args.json, "Timeout", None)
2085 except(requests.exceptions.ConnectionError) as err:
2086 return connectionErrHandler(args.json, "ConnectionError", err)
2087
2088def activateFWImage(host, args, session):
2089 """
2090 activates a firmware image on the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002091
Justin Thalere412dc22018-01-12 16:28:24 -06002092 @param host: string, the hostname or IP address of the bmc
2093 @param args: contains additional arguments used by the fwflash sub command
2094 @param session: the active session to use
2095 @param fwID: the unique ID of the fw image to activate
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002096 """
Justin Thalere412dc22018-01-12 16:28:24 -06002097 fwID = args.imageID
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002098
Justin Thalere412dc22018-01-12 16:28:24 -06002099 #determine the existing versions
Justin Thalere412dc22018-01-12 16:28:24 -06002100 url="https://"+host+"/xyz/openbmc_project/software/enumerate"
2101 try:
Justin Thaler27197622019-01-23 14:42:11 -06002102 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002103 except(requests.exceptions.Timeout):
2104 return connectionErrHandler(args.json, "Timeout", None)
2105 except(requests.exceptions.ConnectionError) as err:
2106 return connectionErrHandler(args.json, "ConnectionError", err)
2107 existingSoftware = json.loads(resp.text)['data']
2108 altVersionID = ''
2109 versionType = ''
2110 imageKey = '/xyz/openbmc_project/software/'+fwID
2111 if imageKey in existingSoftware:
2112 versionType = existingSoftware[imageKey]['Purpose']
2113 for key in existingSoftware:
2114 if imageKey == key:
2115 continue
2116 if 'Purpose' in existingSoftware[key]:
2117 if versionType == existingSoftware[key]['Purpose']:
2118 altVersionID = key.split('/')[-1]
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002119
2120
2121
2122
Justin Thalere412dc22018-01-12 16:28:24 -06002123 url="https://"+host+"/xyz/openbmc_project/software/"+ fwID + "/attr/Priority"
2124 url1="https://"+host+"/xyz/openbmc_project/software/"+ altVersionID + "/attr/Priority"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002125 data = "{\"data\": 0}"
Justin Thalere412dc22018-01-12 16:28:24 -06002126 data1 = "{\"data\": 1 }"
2127 try:
Justin Thaler27197622019-01-23 14:42:11 -06002128 resp = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
2129 resp1 = session.put(url1, headers=jsonHeader, data=data1, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002130 except(requests.exceptions.Timeout):
2131 return connectionErrHandler(args.json, "Timeout", None)
2132 except(requests.exceptions.ConnectionError) as err:
2133 return connectionErrHandler(args.json, "ConnectionError", err)
2134 if(not args.json):
2135 if resp.status_code == 200 and resp1.status_code == 200:
Justin Thaler22b1bb52018-03-15 13:31:32 -05002136 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 -06002137 else:
2138 return "Firmware activation failed."
2139 else:
2140 return resp.text + resp1.text
Justin Thaler22b1bb52018-03-15 13:31:32 -05002141
2142def activateStatus(host, args, session):
2143 if checkFWactivation(host, args, session):
2144 return("Firmware is currently being activated. Do not reboot the BMC or start the Host OS")
2145 else:
2146 return("No firmware activations are pending")
2147
2148def extractFWimage(path, imageType):
2149 """
2150 extracts the bmc image and returns information about the package
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002151
Justin Thaler22b1bb52018-03-15 13:31:32 -05002152 @param path: the path and file name of the firmware image
2153 @param imageType: The type of image the user is trying to flash. Host or BMC
2154 @return: the image id associated with the package. returns an empty string on error.
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002155 """
Justin Thaler22b1bb52018-03-15 13:31:32 -05002156 f = tempfile.TemporaryFile()
2157 tmpDir = tempfile.gettempdir()
2158 newImageID = ""
2159 if os.path.exists(path):
2160 try:
2161 imageFile = tarfile.open(path,'r')
2162 contents = imageFile.getmembers()
2163 for tf in contents:
2164 if 'MANIFEST' in tf.name:
2165 imageFile.extract(tf.name, path=tmpDir)
2166 with open(tempfile.gettempdir() +os.sep+ tf.name, 'r') as imageInfo:
2167 for line in imageInfo:
2168 if 'purpose' in line:
2169 purpose = line.split('=')[1]
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002170 if imageType not in purpose.split('.')[-1]:
Justin Thaler22b1bb52018-03-15 13:31:32 -05002171 print('The specified image is not for ' + imageType)
2172 print('Please try again with the image for ' + imageType)
2173 return ""
2174 if 'version' == line.split('=')[0]:
2175 version = line.split('=')[1].strip().encode('utf-8')
2176 m = hashlib.sha512()
2177 m.update(version)
2178 newImageID = m.hexdigest()[:8]
2179 break
2180 try:
2181 os.remove(tempfile.gettempdir() +os.sep+ tf.name)
2182 except OSError:
2183 pass
2184 return newImageID
2185 except tarfile.ExtractError as e:
2186 print('Unable to extract information from the firmware file.')
2187 print('Ensure you have write access to the directory: ' + tmpDir)
2188 return newImageID
2189 except tarfile.TarError as e:
2190 print('This is not a valid firmware file.')
2191 return newImageID
2192 print("This is not a valid firmware file.")
2193 return newImageID
2194 else:
2195 print('The filename and path provided are not valid.')
2196 return newImageID
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002197
Justin Thaler22b1bb52018-03-15 13:31:32 -05002198def getAllFWImageIDs(fwInvDict):
2199 """
2200 gets a list of all the firmware image IDs
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002201
Justin Thaler22b1bb52018-03-15 13:31:32 -05002202 @param fwInvDict: the dictionary to search for FW image IDs
2203 @return: list containing string representation of the found image ids
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002204 """
Justin Thaler22b1bb52018-03-15 13:31:32 -05002205 idList = []
2206 for key in fwInvDict:
2207 if 'Version' in fwInvDict[key]:
2208 idList.append(key.split('/')[-1])
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002209 return idList
2210
Justin Thalere412dc22018-01-12 16:28:24 -06002211def fwFlash(host, args, session):
2212 """
2213 updates the bmc firmware and pnor firmware
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002214
Justin Thalere412dc22018-01-12 16:28:24 -06002215 @param host: string, the hostname or IP address of the bmc
2216 @param args: contains additional arguments used by the fwflash sub command
2217 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002218 """
Justin Thaler22b1bb52018-03-15 13:31:32 -05002219 d = vars(args)
Justin Thalere412dc22018-01-12 16:28:24 -06002220 if(args.type == 'bmc'):
2221 purp = 'BMC'
2222 else:
2223 purp = 'Host'
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002224
2225 #check power state of the machine. No concurrent FW updates allowed
Justin Thaler22b1bb52018-03-15 13:31:32 -05002226 d['powcmd'] = 'status'
2227 powerstate = chassisPower(host, args, session)
2228 if 'Chassis Power State: On' in powerstate:
2229 return("Aborting firmware update. Host is powered on. Please turn off the host and try again.")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002230
Justin Thaler22b1bb52018-03-15 13:31:32 -05002231 #determine the existing images on the bmc
Justin Thalere412dc22018-01-12 16:28:24 -06002232 url="https://"+host+"/xyz/openbmc_project/software/enumerate"
2233 try:
Justin Thaler27197622019-01-23 14:42:11 -06002234 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002235 except(requests.exceptions.Timeout):
2236 return connectionErrHandler(args.json, "Timeout", None)
2237 except(requests.exceptions.ConnectionError) as err:
2238 return connectionErrHandler(args.json, "ConnectionError", err)
2239 oldsoftware = json.loads(resp.text)['data']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002240
Justin Thaler22b1bb52018-03-15 13:31:32 -05002241 #Extract the tar and get information from the manifest file
2242 newversionID = extractFWimage(args.fileloc, purp)
2243 if newversionID == "":
2244 return "Unable to verify FW image."
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002245
2246
Justin Thaler22b1bb52018-03-15 13:31:32 -05002247 #check if the new image is already on the bmc
2248 if newversionID not in getAllFWImageIDs(oldsoftware):
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002249
Justin Thaler22b1bb52018-03-15 13:31:32 -05002250 #upload the file
2251 httpHeader = {'Content-Type':'application/octet-stream'}
Matt Spinler220c3c42019-01-04 15:09:29 -06002252 httpHeader.update(xAuthHeader)
Justin Thaler22b1bb52018-03-15 13:31:32 -05002253 url="https://"+host+"/upload/image"
2254 data=open(args.fileloc,'rb').read()
2255 print("Uploading file to BMC")
Justin Thalere412dc22018-01-12 16:28:24 -06002256 try:
Justin Thaler22b1bb52018-03-15 13:31:32 -05002257 resp = session.post(url, headers=httpHeader, data=data, verify=False)
Justin Thalere412dc22018-01-12 16:28:24 -06002258 except(requests.exceptions.Timeout):
2259 return connectionErrHandler(args.json, "Timeout", None)
2260 except(requests.exceptions.ConnectionError) as err:
2261 return connectionErrHandler(args.json, "ConnectionError", err)
Justin Thaler22b1bb52018-03-15 13:31:32 -05002262 if resp.status_code != 200:
2263 return "Failed to upload the file to the bmc"
Justin Thalere412dc22018-01-12 16:28:24 -06002264 else:
Justin Thaler22b1bb52018-03-15 13:31:32 -05002265 print("Upload complete.")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002266
Justin Thaler22b1bb52018-03-15 13:31:32 -05002267 #verify bmc processed the image
2268 software ={}
2269 for i in range(0, 5):
Justin Thaler22b1bb52018-03-15 13:31:32 -05002270 url="https://"+host+"/xyz/openbmc_project/software/enumerate"
2271 try:
Justin Thaler27197622019-01-23 14:42:11 -06002272 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thaler22b1bb52018-03-15 13:31:32 -05002273 except(requests.exceptions.Timeout):
2274 return connectionErrHandler(args.json, "Timeout", None)
2275 except(requests.exceptions.ConnectionError) as err:
2276 return connectionErrHandler(args.json, "ConnectionError", err)
2277 software = json.loads(resp.text)['data']
2278 #check if bmc is done processing the new image
2279 if (newversionID in getAllFWImageIDs(software)):
Justin Thalere412dc22018-01-12 16:28:24 -06002280 break
Justin Thaler22b1bb52018-03-15 13:31:32 -05002281 else:
2282 time.sleep(15)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002283
Justin Thaler22b1bb52018-03-15 13:31:32 -05002284 #activate the new image
2285 print("Activating new image: "+newversionID)
2286 url="https://"+host+"/xyz/openbmc_project/software/"+ newversionID + "/attr/RequestedActivation"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002287 data = '{"data":"xyz.openbmc_project.Software.Activation.RequestedActivations.Active"}'
Justin Thaler22b1bb52018-03-15 13:31:32 -05002288 try:
Justin Thaler27197622019-01-23 14:42:11 -06002289 resp = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thaler22b1bb52018-03-15 13:31:32 -05002290 except(requests.exceptions.Timeout):
2291 return connectionErrHandler(args.json, "Timeout", None)
2292 except(requests.exceptions.ConnectionError) as err:
2293 return connectionErrHandler(args.json, "ConnectionError", err)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002294
Justin Thaler22b1bb52018-03-15 13:31:32 -05002295 #wait for the activation to complete, timeout after ~1 hour
2296 i=0
2297 while i < 360:
2298 url="https://"+host+"/xyz/openbmc_project/software/"+ newversionID
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002299 data = '{"data":"xyz.openbmc_project.Software.Activation.RequestedActivations.Active"}'
Justin Thaler22b1bb52018-03-15 13:31:32 -05002300 try:
Justin Thaler27197622019-01-23 14:42:11 -06002301 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thaler22b1bb52018-03-15 13:31:32 -05002302 except(requests.exceptions.Timeout):
2303 return connectionErrHandler(args.json, "Timeout", None)
2304 except(requests.exceptions.ConnectionError) as err:
2305 return connectionErrHandler(args.json, "ConnectionError", err)
2306 fwInfo = json.loads(resp.text)['data']
2307 if 'Activating' not in fwInfo['Activation'] and 'Activating' not in fwInfo['RequestedActivation']:
2308 print('')
2309 break
2310 else:
2311 sys.stdout.write('.')
2312 sys.stdout.flush()
2313 time.sleep(10) #check every 10 seconds
2314 return "Firmware flash and activation completed. Please reboot the bmc and then boot the host OS for the changes to take effect. "
2315 else:
2316 print("This image has been found on the bmc. Activating image: " + newversionID)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002317
Justin Thaler22b1bb52018-03-15 13:31:32 -05002318 d['imageID'] = newversionID
2319 return activateFWImage(host, args, session)
Justin Thalere412dc22018-01-12 16:28:24 -06002320
Justin Thaler3d71d402018-07-24 14:35:39 -05002321def getFWInventoryAttributes(rawFWInvItem, ID):
2322 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002323 gets and lists all of the firmware in the system.
2324
Justin Thaler3d71d402018-07-24 14:35:39 -05002325 @return: returns a dictionary containing the image attributes
2326 """
2327 reqActivation = rawFWInvItem["RequestedActivation"].split('.')[-1]
2328 pendingActivation = ""
2329 if reqActivation == "None":
2330 pendingActivation = "No"
2331 else:
2332 pendingActivation = "Yes"
2333 firmwareAttr = {ID: {
2334 "Purpose": rawFWInvItem["Purpose"].split('.')[-1],
2335 "Version": rawFWInvItem["Version"],
2336 "RequestedActivation": pendingActivation,
2337 "ID": ID}}
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002338
Justin Thaler3d71d402018-07-24 14:35:39 -05002339 if "ExtendedVersion" in rawFWInvItem:
2340 firmwareAttr[ID]['ExtendedVersion'] = rawFWInvItem['ExtendedVersion'].split(',')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002341 else:
Justin Thaler3d71d402018-07-24 14:35:39 -05002342 firmwareAttr[ID]['ExtendedVersion'] = ""
2343 return firmwareAttr
2344
2345def parseFWdata(firmwareDict):
2346 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002347 creates a dictionary with parsed firmware data
2348
Justin Thaler3d71d402018-07-24 14:35:39 -05002349 @return: returns a dictionary containing the image attributes
2350 """
2351 firmwareInfoDict = {"Functional": {}, "Activated":{}, "NeedsActivated":{}}
2352 for key in firmwareDict['data']:
2353 #check for valid endpoint
2354 if "Purpose" in firmwareDict['data'][key]:
2355 id = key.split('/')[-1]
2356 if firmwareDict['data'][key]['Activation'].split('.')[-1] == "Active":
2357 fwActivated = True
2358 else:
2359 fwActivated = False
Justin Thalercb68e062019-03-26 19:04:52 -05002360 if 'Priority' in firmwareDict['data'][key]:
2361 if firmwareDict['data'][key]['Priority'] == 0:
2362 firmwareInfoDict['Functional'].update(getFWInventoryAttributes(firmwareDict['data'][key], id))
2363 elif firmwareDict['data'][key]['Priority'] >= 0 and fwActivated:
2364 firmwareInfoDict['Activated'].update(getFWInventoryAttributes(firmwareDict['data'][key], id))
2365 else:
2366 firmwareInfoDict['NeedsActivated'].update(getFWInventoryAttributes(firmwareDict['data'][key], id))
Justin Thaler3d71d402018-07-24 14:35:39 -05002367 else:
Justin Thalercb68e062019-03-26 19:04:52 -05002368 firmwareInfoDict['NeedsActivated'].update(getFWInventoryAttributes(firmwareDict['data'][key], id))
Justin Thaler3d71d402018-07-24 14:35:39 -05002369 emptySections = []
2370 for key in firmwareInfoDict:
2371 if len(firmwareInfoDict[key])<=0:
2372 emptySections.append(key)
2373 for key in emptySections:
2374 del firmwareInfoDict[key]
2375 return firmwareInfoDict
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002376
Justin Thaler3d71d402018-07-24 14:35:39 -05002377def displayFWInvenory(firmwareInfoDict, args):
2378 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002379 gets and lists all of the firmware in the system.
2380
Justin Thaler3d71d402018-07-24 14:35:39 -05002381 @return: returns a string containing all of the firmware information
2382 """
2383 output = ""
2384 if not args.json:
2385 for key in firmwareInfoDict:
2386 for subkey in firmwareInfoDict[key]:
2387 firmwareInfoDict[key][subkey]['ExtendedVersion'] = str(firmwareInfoDict[key][subkey]['ExtendedVersion'])
2388 if not args.verbose:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002389 output = "---Running Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002390 colNames = ["Purpose", "Version", "ID"]
2391 keylist = ["Purpose", "Version", "ID"]
2392 output += tableDisplay(keylist, colNames, firmwareInfoDict["Functional"])
2393 if "Activated" in firmwareInfoDict:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002394 output += "\n---Available Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002395 output += tableDisplay(keylist, colNames, firmwareInfoDict["Activated"])
2396 if "NeedsActivated" in firmwareInfoDict:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002397 output += "\n---Needs Activated Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002398 output += tableDisplay(keylist, colNames, firmwareInfoDict["NeedsActivated"])
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002399
Justin Thaler3d71d402018-07-24 14:35:39 -05002400 else:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002401 output = "---Running Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002402 colNames = ["Purpose", "Version", "ID", "Pending Activation", "Extended Version"]
2403 keylist = ["Purpose", "Version", "ID", "RequestedActivation", "ExtendedVersion"]
2404 output += tableDisplay(keylist, colNames, firmwareInfoDict["Functional"])
2405 if "Activated" in firmwareInfoDict:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002406 output += "\n---Available Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002407 output += tableDisplay(keylist, colNames, firmwareInfoDict["Activated"])
2408 if "NeedsActivated" in firmwareInfoDict:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002409 output += "\n---Needs Activated Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002410 output += tableDisplay(keylist, colNames, firmwareInfoDict["NeedsActivated"])
2411 return output
2412 else:
2413 return str(json.dumps(firmwareInfoDict, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False))
2414
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002415def firmwareList(host, args, session):
Justin Thaler3d71d402018-07-24 14:35:39 -05002416 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002417 gets and lists all of the firmware in the system.
2418
Justin Thaler3d71d402018-07-24 14:35:39 -05002419 @return: returns a string containing all of the firmware information
2420 """
Justin Thaler3d71d402018-07-24 14:35:39 -05002421 url="https://{hostname}/xyz/openbmc_project/software/enumerate".format(hostname=host)
2422 try:
Justin Thaler27197622019-01-23 14:42:11 -06002423 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thaler3d71d402018-07-24 14:35:39 -05002424 except(requests.exceptions.Timeout):
2425 return(connectionErrHandler(args.json, "Timeout", None))
2426 firmwareDict = json.loads(res.text)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002427
Justin Thaler3d71d402018-07-24 14:35:39 -05002428 #sort the received information
2429 firmwareInfoDict = parseFWdata(firmwareDict)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002430
Justin Thaler3d71d402018-07-24 14:35:39 -05002431 #display the information
2432 return displayFWInvenory(firmwareInfoDict, args)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002433
2434
Adriana Kobylak5af2fad2018-11-08 12:33:43 -06002435def deleteFWVersion(host, args, session):
2436 """
2437 deletes a firmware version on the BMC
2438
2439 @param host: string, the hostname or IP address of the BMC
2440 @param args: contains additional arguments used by the fwflash sub command
2441 @param session: the active session to use
2442 @param fwID: the unique ID of the fw version to delete
2443 """
2444 fwID = args.versionID
2445
2446 print("Deleting version: "+fwID)
2447 url="https://"+host+"/xyz/openbmc_project/software/"+ fwID + "/action/Delete"
Adriana Kobylak5af2fad2018-11-08 12:33:43 -06002448 data = "{\"data\": [] }"
2449
2450 try:
Justin Thaler27197622019-01-23 14:42:11 -06002451 res = session.post(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Adriana Kobylak5af2fad2018-11-08 12:33:43 -06002452 except(requests.exceptions.Timeout):
2453 return(connectionErrHandler(args.json, "Timeout", None))
2454 if res.status_code == 200:
2455 return ('The firmware version has been deleted')
2456 else:
2457 return ('Unable to delete the specified firmware version')
2458
2459
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05002460def restLogging(host, args, session):
2461 """
2462 Called by the logging function. Turns REST API logging on/off.
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002463
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05002464 @param host: string, the hostname or IP address of the bmc
2465 @param args: contains additional arguments used by the logging sub command
2466 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002467 @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 -05002468 """
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05002469 url="https://"+host+"/xyz/openbmc_project/logging/rest_api_logs/attr/Enabled"
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05002470
2471 if(args.rest_logging == 'on'):
2472 data = '{"data": 1}'
2473 elif(args.rest_logging == 'off'):
2474 data = '{"data": 0}'
2475 else:
2476 return "Invalid logging rest_api command"
2477
2478 try:
Justin Thaler27197622019-01-23 14:42:11 -06002479 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05002480 except(requests.exceptions.Timeout):
2481 return(connectionErrHandler(args.json, "Timeout", None))
2482 return res.text
2483
2484
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002485def remoteLogging(host, args, session):
2486 """
2487 Called by the logging function. View config information for/disable remote logging (rsyslog).
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002488
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002489 @param host: string, the hostname or IP address of the bmc
2490 @param args: contains additional arguments used by the logging sub command
2491 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002492 @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 -05002493 """
2494
2495 url="https://"+host+"/xyz/openbmc_project/logging/config/remote"
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002496
2497 try:
2498 if(args.remote_logging == 'view'):
Justin Thaler27197622019-01-23 14:42:11 -06002499 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002500 elif(args.remote_logging == 'disable'):
Justin Thaler27197622019-01-23 14:42:11 -06002501 res = session.put(url + '/attr/Port', headers=jsonHeader, json = {"data": 0}, verify=False, timeout=baseTimeout)
2502 res = session.put(url + '/attr/Address', headers=jsonHeader, json = {"data": ""}, verify=False, timeout=baseTimeout)
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002503 else:
2504 return "Invalid logging remote_logging command"
2505 except(requests.exceptions.Timeout):
2506 return(connectionErrHandler(args.json, "Timeout", None))
2507 return res.text
2508
2509
2510def remoteLoggingConfig(host, args, session):
2511 """
2512 Called by the logging function. Configures remote logging (rsyslog).
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002513
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002514 @param host: string, the hostname or IP address of the bmc
2515 @param args: contains additional arguments used by the logging sub command
2516 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002517 @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 -05002518 """
2519
2520 url="https://"+host+"/xyz/openbmc_project/logging/config/remote"
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002521
2522 try:
Justin Thaler27197622019-01-23 14:42:11 -06002523 res = session.put(url + '/attr/Port', headers=jsonHeader, json = {"data": args.port}, verify=False, timeout=baseTimeout)
2524 res = session.put(url + '/attr/Address', headers=jsonHeader, json = {"data": args.address}, verify=False, timeout=baseTimeout)
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002525 except(requests.exceptions.Timeout):
2526 return(connectionErrHandler(args.json, "Timeout", None))
2527 return res.text
2528
Marri Devender Rao82590dc2019-06-06 04:54:22 -05002529def redfishSupportPresent(host, session):
2530 url = "https://" + host + "/redfish/v1"
2531 try:
2532 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
2533 except(requests.exceptions.Timeout):
2534 return False
2535 except(requests.exceptions.ConnectionError) as err:
2536 return False
2537 if resp.status_code != 200:
2538 return False
2539 else:
2540 return True
Ratan Gupta9166cd22018-10-01 18:09:40 +05302541
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002542def certificateUpdate(host, args, session):
2543 """
2544 Called by certificate management function. update server/client/authority certificates
2545 Example:
2546 certificate update server https -f cert.pem
2547 certificate update authority ldap -f Root-CA.pem
2548 certificate update client ldap -f cert.pem
2549 @param host: string, the hostname or IP address of the bmc
2550 @param args: contains additional arguments used by the certificate update sub command
2551 @param session: the active session to use
2552 """
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002553 httpHeader = {'Content-Type': 'application/octet-stream'}
Matt Spinler220c3c42019-01-04 15:09:29 -06002554 httpHeader.update(xAuthHeader)
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002555 data = open(args.fileloc, 'rb').read()
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002556 try:
Marri Devender Rao82590dc2019-06-06 04:54:22 -05002557 if redfishSupportPresent(host, session):
Marri Devender Rao62db08a2019-08-22 03:16:02 -05002558 if(args.type.lower() == 'server' and args.service.lower() != "https"):
2559 return "Invalid service type"
2560 if(args.type.lower() == 'client' and args.service.lower() != "ldap"):
2561 return "Invalid service type"
2562 if(args.type.lower() == 'authority' and args.service.lower() != "ldap"):
2563 return "Invalid service type"
Marri Devender Rao82590dc2019-06-06 04:54:22 -05002564 url = "";
2565 if(args.type.lower() == 'server'):
2566 url = "https://" + host + \
2567 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"
2568 elif(args.type.lower() == 'client'):
2569 url = "https://" + host + \
2570 "/redfish/v1/AccountService/LDAP/Certificates"
2571 elif(args.type.lower() == 'authority'):
2572 url = "https://" + host + \
2573 "/redfish/v1/Managers/bmc/Truststore/Certificates"
2574 else:
2575 return "Unsupported certificate type"
2576 resp = session.post(url, headers=httpHeader, data=data,
2577 verify=False)
2578 else:
2579 url = "https://" + host + "/xyz/openbmc_project/certs/" + \
2580 args.type.lower() + "/" + args.service.lower()
2581 resp = session.put(url, headers=httpHeader, data=data, verify=False)
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002582 except(requests.exceptions.Timeout):
2583 return(connectionErrHandler(args.json, "Timeout", None))
2584 except(requests.exceptions.ConnectionError) as err:
2585 return connectionErrHandler(args.json, "ConnectionError", err)
2586 if resp.status_code != 200:
2587 print(resp.text)
2588 return "Failed to update the certificate"
2589 else:
Marri Devender Rao82590dc2019-06-06 04:54:22 -05002590 print("Update complete.")
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002591
2592def certificateDelete(host, args, session):
2593 """
2594 Called by certificate management function to delete certificate
2595 Example:
2596 certificate delete server https
2597 certificate delete authority ldap
2598 certificate delete client ldap
2599 @param host: string, the hostname or IP address of the bmc
2600 @param args: contains additional arguments used by the certificate delete sub command
2601 @param session: the active session to use
2602 """
Marri Devender Rao77e78682019-07-17 03:18:35 -05002603 if redfishSupportPresent(host, session):
2604 return "Not supported, please use certificate replace instead";
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002605 httpHeader = {'Content-Type': 'multipart/form-data'}
Matt Spinler220c3c42019-01-04 15:09:29 -06002606 httpHeader.update(xAuthHeader)
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002607 url = "https://" + host + "/xyz/openbmc_project/certs/" + args.type.lower() + "/" + args.service.lower()
2608 print("Deleting certificate url=" + url)
2609 try:
2610 resp = session.delete(url, headers=httpHeader)
2611 except(requests.exceptions.Timeout):
2612 return(connectionErrHandler(args.json, "Timeout", None))
2613 except(requests.exceptions.ConnectionError) as err:
2614 return connectionErrHandler(args.json, "ConnectionError", err)
2615 if resp.status_code != 200:
2616 print(resp.text)
2617 return "Failed to delete the certificate"
2618 else:
Marri Devender Rao77e78682019-07-17 03:18:35 -05002619 print("Delete complete.")
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002620
Marri Devender Raodfe81ad2019-07-01 05:38:09 -05002621def certificateReplace(host, args, session):
2622 """
2623 Called by certificate management function. replace server/client/
2624 authority certificates
2625 Example:
2626 certificate replace server https -f cert.pem
2627 certificate replace authority ldap -f Root-CA.pem
2628 certificate replace client ldap -f cert.pem
2629 @param host: string, the hostname or IP address of the bmc
2630 @param args: contains additional arguments used by the certificate
2631 replace sub command
2632 @param session: the active session to use
2633 """
2634 cert = open(args.fileloc, 'rb').read()
2635 try:
2636 if redfishSupportPresent(host, session):
2637 httpHeader = {'Content-Type': 'application/json'}
2638 httpHeader.update(xAuthHeader)
2639 url = "";
Marri Devender Rao62db08a2019-08-22 03:16:02 -05002640 if(args.type.lower() == 'server' and args.service.lower() != "https"):
2641 return "Invalid service type"
2642 if(args.type.lower() == 'client' and args.service.lower() != "ldap"):
2643 return "Invalid service type"
2644 if(args.type.lower() == 'authority' and args.service.lower() != "ldap"):
2645 return "Invalid service type"
Marri Devender Raodfe81ad2019-07-01 05:38:09 -05002646 if(args.type.lower() == 'server'):
2647 url = "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/1"
2648 elif(args.type.lower() == 'client'):
2649 url = "/redfish/v1/AccountService/LDAP/Certificates/1"
2650 elif(args.type.lower() == 'authority'):
2651 url = "/redfish/v1/Managers/bmc/Truststore/Certificates/1"
2652 replaceUrl = "https://" + host + \
2653 "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate"
2654 data ={"CertificateUri":{"@odata.id":url}, "CertificateType":"PEM",
2655 "CertificateString":cert}
2656 resp = session.post(replaceUrl, headers=httpHeader, json=data, verify=False)
2657 else:
2658 httpHeader = {'Content-Type': 'application/octet-stream'}
2659 httpHeader.update(xAuthHeader)
2660 url = "https://" + host + "/xyz/openbmc_project/certs/" + \
2661 args.type.lower() + "/" + args.service.lower()
2662 resp = session.delete(url, headers=httpHeader)
2663 resp = session.put(url, headers=httpHeader, data=cert, verify=False)
2664 except(requests.exceptions.Timeout):
2665 return(connectionErrHandler(args.json, "Timeout", None))
2666 except(requests.exceptions.ConnectionError) as err:
2667 return connectionErrHandler(args.json, "ConnectionError", err)
2668 if resp.status_code != 200:
2669 print(resp.text)
2670 return "Failed to replace the certificate"
2671 else:
2672 print("Replace complete.")
2673 return resp.text
2674
Marri Devender Rao34646402019-07-01 05:46:03 -05002675def certificateDisplay(host, args, session):
2676 """
2677 Called by certificate management function. display server/client/
2678 authority certificates
2679 Example:
2680 certificate display server
2681 certificate display authority
2682 certificate display client
2683 @param host: string, the hostname or IP address of the bmc
2684 @param args: contains additional arguments used by the certificate
2685 display sub command
2686 @param session: the active session to use
2687 """
2688 if not redfishSupportPresent(host, session):
2689 return "Not supported";
2690
2691 httpHeader = {'Content-Type': 'application/octet-stream'}
2692 httpHeader.update(xAuthHeader)
2693 if(args.type.lower() == 'server'):
2694 url = "https://" + host + \
2695 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/1"
2696 elif(args.type.lower() == 'client'):
2697 url = "https://" + host + \
2698 "/redfish/v1/AccountService/LDAP/Certificates/1"
2699 elif(args.type.lower() == 'authority'):
2700 url = "https://" + host + \
2701 "/redfish/v1/Managers/bmc/Truststore/Certificates/1"
2702 try:
2703 resp = session.get(url, headers=httpHeader, verify=False)
2704 except(requests.exceptions.Timeout):
2705 return(connectionErrHandler(args.json, "Timeout", None))
2706 except(requests.exceptions.ConnectionError) as err:
2707 return connectionErrHandler(args.json, "ConnectionError", err)
2708 if resp.status_code != 200:
2709 print(resp.text)
2710 return "Failed to display the certificate"
2711 else:
2712 print("Display complete.")
2713 return resp.text
2714
Marri Devender Raoa208ff82019-07-01 05:51:27 -05002715def certificateList(host, args, session):
2716 """
2717 Called by certificate management function.
2718 Example:
2719 certificate list
2720 @param host: string, the hostname or IP address of the bmc
2721 @param args: contains additional arguments used by the certificate
2722 list sub command
2723 @param session: the active session to use
2724 """
2725 if not redfishSupportPresent(host, session):
2726 return "Not supported";
2727
2728 httpHeader = {'Content-Type': 'application/octet-stream'}
2729 httpHeader.update(xAuthHeader)
2730 url = "https://" + host + \
2731 "/redfish/v1/CertificateService/CertificateLocations/"
2732 try:
2733 resp = session.get(url, headers=httpHeader, verify=False)
2734 except(requests.exceptions.Timeout):
2735 return(connectionErrHandler(args.json, "Timeout", None))
2736 except(requests.exceptions.ConnectionError) as err:
2737 return connectionErrHandler(args.json, "ConnectionError", err)
2738 if resp.status_code != 200:
2739 print(resp.text)
2740 return "Failed to list certificates"
2741 else:
2742 print("List certificates complete.")
2743 return resp.text
2744
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05002745def certificateGenerateCSR(host, args, session):
2746 """
2747 Called by certificate management function. Generate CSR for server/
2748 client certificates
2749 Example:
Marri Devender Raodf0e1a42019-09-09 08:18:27 -05002750 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
2751 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 -05002752 @param host: string, the hostname or IP address of the bmc
2753 @param args: contains additional arguments used by the certificate replace sub command
2754 @param session: the active session to use
2755 """
2756 if not redfishSupportPresent(host, session):
2757 return "Not supported";
2758
2759 httpHeader = {'Content-Type': 'application/octet-stream'}
2760 httpHeader.update(xAuthHeader)
2761 url = "";
2762 if(args.type.lower() == 'server'):
2763 url = "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/"
Marri Devender Rao88064f02019-08-19 09:00:30 -05002764 usage_list = ["ServerAuthentication"]
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05002765 elif(args.type.lower() == 'client'):
2766 url = "/redfish/v1/AccountService/LDAP/Certificates/"
Marri Devender Rao88064f02019-08-19 09:00:30 -05002767 usage_list = ["ClientAuthentication"]
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05002768 elif(args.type.lower() == 'authority'):
2769 url = "/redfish/v1/Managers/bmc/Truststore/Certificates/"
2770 print("Generating CSR url=" + url)
2771 generateCSRUrl = "https://" + host + \
2772 "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR"
2773 try:
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05002774 alt_name_list = args.alternativeNames.split(",")
2775 data ={"CertificateCollection":{"@odata.id":url},
2776 "CommonName":args.commonName, "City":args.city,
2777 "Country":args.country, "Organization":args.organization,
2778 "OrganizationalUnit":args.organizationUnit, "State":args.state,
Marri Devender Raodf0e1a42019-09-09 08:18:27 -05002779 "KeyPairAlgorithm":args.keyPairAlgorithm, "KeyCurveId":args.keyCurveId,
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05002780 "AlternativeNames":alt_name_list, "ContactPerson":args.contactPerson,
2781 "Email":args.email, "GivenName":args.givenname, "Initials":args.initials,
2782 "KeyUsage":usage_list, "Surname":args.surname,
2783 "UnstructuredName":args.unstructuredname}
2784 resp = session.post(generateCSRUrl, headers=httpHeader,
2785 json=data, verify=False)
2786 except(requests.exceptions.Timeout):
2787 return(connectionErrHandler(args.json, "Timeout", None))
2788 except(requests.exceptions.ConnectionError) as err:
2789 return connectionErrHandler(args.json, "ConnectionError", err)
2790 if resp.status_code != 200:
2791 print(resp.text)
2792 return "Failed to generate CSR"
2793 else:
2794 print("GenerateCSR complete.")
2795 return resp.text
2796
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05002797def enableLDAPConfig(host, args, session):
Ratan Gupta9166cd22018-10-01 18:09:40 +05302798 """
2799 Called by the ldap function. Configures LDAP.
2800
2801 @param host: string, the hostname or IP address of the bmc
2802 @param args: contains additional arguments used by the ldap subcommand
2803 @param session: the active session to use
2804 @param args.json: boolean, if this flag is set to true, the output will
2805 be provided in json format for programmatic consumption
2806 """
2807
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05002808 if(isRedfishSupport):
2809 return enableLDAP(host, args, session)
2810 else:
2811 return enableLegacyLDAP(host, args, session)
2812
2813def enableLegacyLDAP(host, args, session):
2814 """
2815 Called by the ldap function. Configures LDAP on Lagecy systems.
2816
2817 @param host: string, the hostname or IP address of the bmc
2818 @param args: contains additional arguments used by the ldap subcommand
2819 @param session: the active session to use
2820 @param args.json: boolean, if this flag is set to true, the output will
2821 be provided in json format for programmatic consumption
2822 """
2823
Ratan Gupta9166cd22018-10-01 18:09:40 +05302824 url='https://'+host+'/xyz/openbmc_project/user/ldap/action/CreateConfig'
Ratan Gupta9166cd22018-10-01 18:09:40 +05302825 scope = {
2826 'sub' : 'xyz.openbmc_project.User.Ldap.Create.SearchScope.sub',
2827 'one' : 'xyz.openbmc_project.User.Ldap.Create.SearchScope.one',
2828 'base': 'xyz.openbmc_project.User.Ldap.Create.SearchScope.base'
2829 }
2830
2831 serverType = {
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05002832 'ActiveDirectory' : 'xyz.openbmc_project.User.Ldap.Create.Type.ActiveDirectory',
2833 'OpenLDAP' : 'xyz.openbmc_project.User.Ldap.Create.Type.OpenLdap'
Ratan Gupta9166cd22018-10-01 18:09:40 +05302834 }
2835
2836 data = {"data": [args.uri, args.bindDN, args.baseDN, args.bindPassword, scope[args.scope], serverType[args.serverType]]}
2837
2838 try:
Justin Thaler27197622019-01-23 14:42:11 -06002839 res = session.post(url, headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
Ratan Gupta9166cd22018-10-01 18:09:40 +05302840 except(requests.exceptions.Timeout):
2841 return(connectionErrHandler(args.json, "Timeout", None))
2842 except(requests.exceptions.ConnectionError) as err:
2843 return connectionErrHandler(args.json, "ConnectionError", err)
2844
2845 return res.text
2846
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05002847def enableLDAP(host, args, session):
2848 """
2849 Called by the ldap function. Configures LDAP for systems with latest user-manager design changes
2850
2851 @param host: string, the hostname or IP address of the bmc
2852 @param args: contains additional arguments used by the ldap subcommand
2853 @param session: the active session to use
2854 @param args.json: boolean, if this flag is set to true, the output will
2855 be provided in json format for programmatic consumption
2856 """
2857
2858 scope = {
2859 'sub' : 'xyz.openbmc_project.User.Ldap.Config.SearchScope.sub',
2860 'one' : 'xyz.openbmc_project.User.Ldap.Config.SearchScope.one',
2861 'base': 'xyz.openbmc_project.User.Ldap.Config.SearchScope.base'
2862 }
2863
2864 serverType = {
2865 'ActiveDirectory' : 'xyz.openbmc_project.User.Ldap.Config.Type.ActiveDirectory',
2866 'OpenLDAP' : 'xyz.openbmc_project.User.Ldap.Config.Type.OpenLdap'
2867 }
2868
2869 url = "https://"+host+"/xyz/openbmc_project/user/ldap/"
2870
2871 serverTypeEnabled = getLDAPTypeEnabled(host,session)
2872 serverTypeToBeEnabled = args.serverType
2873
2874 #If the given LDAP type is already enabled, then return
2875 if (serverTypeToBeEnabled == serverTypeEnabled):
2876 return("Server type " + serverTypeToBeEnabled + " is already enabled...")
2877
2878 try:
2879
2880 # Copy the role map from the currently enabled LDAP server type
2881 # to the newly enabled server type
2882 # Disable the currently enabled LDAP server type. Unless
2883 # it is disabled, we cannot enable a new LDAP server type
2884 if (serverTypeEnabled is not None):
2885
2886 if (serverTypeToBeEnabled != serverTypeEnabled):
2887 res = syncRoleMap(host,args,session,serverTypeEnabled,serverTypeToBeEnabled)
2888
2889 data = "{\"data\": 0 }"
2890 res = session.put(url + serverTypeMap[serverTypeEnabled] + '/attr/Enabled', headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
2891
2892 data = {"data": args.baseDN}
2893 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/LDAPBaseDN', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
2894 if (res.status_code != requests.codes.ok):
2895 print("Updates to the property LDAPBaseDN failed...")
2896 return(res.text)
2897
2898 data = {"data": args.bindDN}
2899 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/LDAPBindDN', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
2900 if (res.status_code != requests.codes.ok):
2901 print("Updates to the property LDAPBindDN failed...")
2902 return(res.text)
2903
2904 data = {"data": args.bindPassword}
2905 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/LDAPBindDNPassword', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
2906 if (res.status_code != requests.codes.ok):
2907 print("Updates to the property LDAPBindDNPassword failed...")
2908 return(res.text)
2909
2910 data = {"data": scope[args.scope]}
2911 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/LDAPSearchScope', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
2912 if (res.status_code != requests.codes.ok):
2913 print("Updates to the property LDAPSearchScope failed...")
2914 return(res.text)
2915
2916 data = {"data": args.uri}
2917 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/LDAPServerURI', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
2918 if (res.status_code != requests.codes.ok):
2919 print("Updates to the property LDAPServerURI failed...")
2920 return(res.text)
2921
2922 data = {"data": args.groupAttrName}
2923 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/GroupNameAttribute', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
2924 if (res.status_code != requests.codes.ok):
2925 print("Updates to the property GroupNameAttribute failed...")
2926 return(res.text)
2927
2928 data = {"data": args.userAttrName}
2929 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/UserNameAttribute', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
2930 if (res.status_code != requests.codes.ok):
2931 print("Updates to the property UserNameAttribute failed...")
2932 return(res.text)
2933
2934 #After updating the properties, enable the new server type
2935 data = "{\"data\": 1 }"
2936 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/Enabled', headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
2937
2938 except(requests.exceptions.Timeout):
2939 return(connectionErrHandler(args.json, "Timeout", None))
2940 except(requests.exceptions.ConnectionError) as err:
2941 return connectionErrHandler(args.json, "ConnectionError", err)
2942 return res.text
Ratan Gupta9166cd22018-10-01 18:09:40 +05302943
2944def disableLDAP(host, args, session):
2945 """
2946 Called by the ldap function. Deletes the LDAP Configuration.
2947
2948 @param host: string, the hostname or IP address of the bmc
2949 @param args: contains additional arguments used by the ldap subcommand
2950 @param session: the active session to use
2951 @param args.json: boolean, if this flag is set to true, the output
2952 will be provided in json format for programmatic consumption
2953 """
2954
Ratan Gupta9166cd22018-10-01 18:09:40 +05302955 try:
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05002956 if (isRedfishSupport) :
2957
2958 url = "https://"+host+"/xyz/openbmc_project/user/ldap/"
2959
2960 serverTypeEnabled = getLDAPTypeEnabled(host,session)
2961
2962 if (serverTypeEnabled is not None):
2963 #To keep the role map in sync,
2964 #If the server type being disabled has role map, then
2965 # - copy the role map to the other server type(s)
2966 for serverType in serverTypeMap.keys():
2967 if (serverType != serverTypeEnabled):
2968 res = syncRoleMap(host,args,session,serverTypeEnabled,serverType)
2969
2970 #Disable the currently enabled LDAP server type
2971 data = "{\"data\": 0 }"
2972 res = session.put(url + serverTypeMap[serverTypeEnabled] + '/attr/Enabled', headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
2973
2974 else:
2975 return("LDAP server has not been enabled...")
2976
2977 else :
2978 url='https://'+host+'/xyz/openbmc_project/user/ldap/config/action/delete'
2979 data = {"data": []}
2980 res = session.post(url, headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
2981
Ratan Gupta9166cd22018-10-01 18:09:40 +05302982 except(requests.exceptions.Timeout):
2983 return(connectionErrHandler(args.json, "Timeout", None))
2984 except(requests.exceptions.ConnectionError) as err:
2985 return connectionErrHandler(args.json, "ConnectionError", err)
2986
2987 return res.text
2988
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06002989def enableDHCP(host, args, session):
2990
2991 """
2992 Called by the network function. Enables DHCP.
2993
2994 @param host: string, the hostname or IP address of the bmc
2995 @param args: contains additional arguments used by the ldap subcommand
2996 args.json: boolean, if this flag is set to true, the output
2997 will be provided in json format for programmatic consumption
2998 @param session: the active session to use
2999 """
3000
3001 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3002 "/attr/DHCPEnabled"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003003 data = "{\"data\": 1 }"
3004 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003005 res = session.put(url, headers=jsonHeader, data=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003006 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003007
3008 except(requests.exceptions.Timeout):
3009 return(connectionErrHandler(args.json, "Timeout", None))
3010 except(requests.exceptions.ConnectionError) as err:
3011 return connectionErrHandler(args.json, "ConnectionError", err)
3012 if res.status_code == 403:
3013 return "The specified Interface"+"("+args.Interface+")"+\
3014 " doesn't exist"
3015
3016 return res.text
3017
3018
3019def disableDHCP(host, args, session):
3020 """
3021 Called by the network function. Disables DHCP.
3022
3023 @param host: string, the hostname or IP address of the bmc
3024 @param args: contains additional arguments used by the ldap subcommand
3025 args.json: boolean, if this flag is set to true, the output
3026 will be provided in json format for programmatic consumption
3027 @param session: the active session to use
3028 """
3029
3030 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3031 "/attr/DHCPEnabled"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003032 data = "{\"data\": 0 }"
3033 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003034 res = session.put(url, headers=jsonHeader, data=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003035 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003036 except(requests.exceptions.Timeout):
3037 return(connectionErrHandler(args.json, "Timeout", None))
3038 except(requests.exceptions.ConnectionError) as err:
3039 return connectionErrHandler(args.json, "ConnectionError", err)
3040 if res.status_code == 403:
3041 return "The specified Interface"+"("+args.Interface+")"+\
3042 " doesn't exist"
3043 return res.text
3044
3045
3046def getHostname(host, args, session):
3047
3048 """
3049 Called by the network function. Prints out the Hostname.
3050
3051 @param host: string, the hostname or IP address of the bmc
3052 @param args: contains additional arguments used by the ldap subcommand
3053 args.json: boolean, if this flag is set to true, the output
3054 will be provided in json format for programmatic consumption
3055 @param session: the active session to use
3056 """
3057
3058 url = "https://"+host+"/xyz/openbmc_project/network/config/attr/HostName"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003059
3060 try:
Justin Thaler27197622019-01-23 14:42:11 -06003061 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003062 except(requests.exceptions.Timeout):
3063 return(connectionErrHandler(args.json, "Timeout", None))
3064 except(requests.exceptions.ConnectionError) as err:
3065 return connectionErrHandler(args.json, "ConnectionError", err)
3066
3067 return res.text
3068
3069
3070def setHostname(host, args, session):
3071 """
3072 Called by the network function. Sets the Hostname.
3073
3074 @param host: string, the hostname or IP address of the bmc
3075 @param args: contains additional arguments used by the ldap subcommand
3076 args.json: boolean, if this flag is set to true, the output
3077 will be provided in json format for programmatic consumption
3078 @param session: the active session to use
3079 """
3080
3081 url = "https://"+host+"/xyz/openbmc_project/network/config/attr/HostName"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003082
3083 data = {"data": args.HostName}
3084
3085 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003086 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003087 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003088 except(requests.exceptions.Timeout):
3089 return(connectionErrHandler(args.json, "Timeout", None))
3090 except(requests.exceptions.ConnectionError) as err:
3091 return connectionErrHandler(args.json, "ConnectionError", err)
3092
3093 return res.text
3094
3095
3096def getDomainName(host, args, session):
3097
3098 """
3099 Called by the network function. Prints out the DomainName.
3100
3101 @param host: string, the hostname or IP address of the bmc
3102 @param args: contains additional arguments used by the ldap subcommand
3103 args.json: boolean, if this flag is set to true, the output
3104 will be provided in json format for programmatic consumption
3105 @param session: the active session to use
3106 """
3107
3108 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3109 "/attr/DomainName"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003110
3111 try:
Justin Thaler27197622019-01-23 14:42:11 -06003112 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003113 except(requests.exceptions.Timeout):
3114 return(connectionErrHandler(args.json, "Timeout", None))
3115 except(requests.exceptions.ConnectionError) as err:
3116 return connectionErrHandler(args.json, "ConnectionError", err)
3117 if res.status_code == 404:
Sunitha Harishf9bb2fa2019-09-19 01:48:00 -05003118 return "The DomainName is not configured on Interface"+"("+args.Interface+")"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003119
3120 return res.text
3121
3122
3123def setDomainName(host, args, session):
3124 """
3125 Called by the network function. Sets the DomainName.
3126
3127 @param host: string, the hostname or IP address of the bmc
3128 @param args: contains additional arguments used by the ldap subcommand
3129 args.json: boolean, if this flag is set to true, the output
3130 will be provided in json format for programmatic consumption
3131 @param session: the active session to use
3132 """
3133
3134 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3135 "/attr/DomainName"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003136
3137 data = {"data": args.DomainName.split(",")}
3138
3139 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003140 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003141 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003142 except(requests.exceptions.Timeout):
3143 return(connectionErrHandler(args.json, "Timeout", None))
3144 except(requests.exceptions.ConnectionError) as err:
3145 return connectionErrHandler(args.json, "ConnectionError", err)
3146 if res.status_code == 403:
3147 return "The specified Interface"+"("+args.Interface+")"+\
3148 " doesn't exist"
3149
3150 return res.text
3151
3152
3153def getMACAddress(host, args, session):
3154
3155 """
3156 Called by the network function. Prints out the MACAddress.
3157
3158 @param host: string, the hostname or IP address of the bmc
3159 @param args: contains additional arguments used by the ldap subcommand
3160 args.json: boolean, if this flag is set to true, the output
3161 will be provided in json format for programmatic consumption
3162 @param session: the active session to use
3163 """
3164
3165 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3166 "/attr/MACAddress"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003167
3168 try:
Justin Thaler27197622019-01-23 14:42:11 -06003169 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003170 except(requests.exceptions.Timeout):
3171 return(connectionErrHandler(args.json, "Timeout", None))
3172 except(requests.exceptions.ConnectionError) as err:
3173 return connectionErrHandler(args.json, "ConnectionError", err)
3174 if res.status_code == 404:
3175 return "The specified Interface"+"("+args.Interface+")"+\
3176 " doesn't exist"
3177
3178 return res.text
3179
3180
3181def setMACAddress(host, args, session):
3182 """
3183 Called by the network function. Sets the MACAddress.
3184
3185 @param host: string, the hostname or IP address of the bmc
3186 @param args: contains additional arguments used by the ldap subcommand
3187 args.json: boolean, if this flag is set to true, the output
3188 will be provided in json format for programmatic consumption
3189 @param session: the active session to use
3190 """
3191
3192 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3193 "/attr/MACAddress"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003194
3195 data = {"data": args.MACAddress}
3196
3197 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003198 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003199 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003200 except(requests.exceptions.Timeout):
3201 return(connectionErrHandler(args.json, "Timeout", None))
3202 except(requests.exceptions.ConnectionError) as err:
3203 return connectionErrHandler(args.json, "ConnectionError", err)
3204 if res.status_code == 403:
3205 return "The specified Interface"+"("+args.Interface+")"+\
3206 " doesn't exist"
3207
3208 return res.text
3209
3210
3211def getDefaultGateway(host, args, session):
3212
3213 """
3214 Called by the network function. Prints out the DefaultGateway.
3215
3216 @param host: string, the hostname or IP address of the bmc
3217 @param args: contains additional arguments used by the ldap subcommand
3218 args.json: boolean, if this flag is set to true, the output
3219 will be provided in json format for programmatic consumption
3220 @param session: the active session to use
3221 """
3222
3223 url = "https://"+host+"/xyz/openbmc_project/network/config/attr/DefaultGateway"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003224
3225 try:
Justin Thaler27197622019-01-23 14:42:11 -06003226 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003227 except(requests.exceptions.Timeout):
3228 return(connectionErrHandler(args.json, "Timeout", None))
3229 except(requests.exceptions.ConnectionError) as err:
3230 return connectionErrHandler(args.json, "ConnectionError", err)
3231 if res.status_code == 404:
3232 return "Failed to get Default Gateway info!!"
3233
3234 return res.text
3235
3236
3237def setDefaultGateway(host, args, session):
3238 """
3239 Called by the network function. Sets the DefaultGateway.
3240
3241 @param host: string, the hostname or IP address of the bmc
3242 @param args: contains additional arguments used by the ldap subcommand
3243 args.json: boolean, if this flag is set to true, the output
3244 will be provided in json format for programmatic consumption
3245 @param session: the active session to use
3246 """
3247
3248 url = "https://"+host+"/xyz/openbmc_project/network/config/attr/DefaultGateway"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003249
3250 data = {"data": args.DefaultGW}
3251
3252 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003253 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003254 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003255 except(requests.exceptions.Timeout):
3256 return(connectionErrHandler(args.json, "Timeout", None))
3257 except(requests.exceptions.ConnectionError) as err:
3258 return connectionErrHandler(args.json, "ConnectionError", err)
3259 if res.status_code == 403:
3260 return "Failed to set Default Gateway!!"
3261
3262 return res.text
3263
3264
3265def viewNWConfig(host, args, session):
3266 """
3267 Called by the ldap function. Prints out network configured properties
3268
3269 @param host: string, the hostname or IP address of the bmc
3270 @param args: contains additional arguments used by the ldap subcommand
3271 args.json: boolean, if this flag is set to true, the output
3272 will be provided in json format for programmatic consumption
3273 @param session: the active session to use
3274 @return returns LDAP's configured properties.
3275 """
3276 url = "https://"+host+"/xyz/openbmc_project/network/enumerate"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003277 try:
Justin Thaler27197622019-01-23 14:42:11 -06003278 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003279 except(requests.exceptions.Timeout):
3280 return(connectionErrHandler(args.json, "Timeout", None))
3281 except(requests.exceptions.ConnectionError) as err:
3282 return connectionErrHandler(args.json, "ConnectionError", err)
3283 except(requests.exceptions.RequestException) as err:
3284 return connectionErrHandler(args.json, "RequestException", err)
3285 if res.status_code == 404:
3286 return "LDAP server config has not been created"
3287 return res.text
3288
3289
3290def getDNS(host, args, session):
3291
3292 """
3293 Called by the network function. Prints out DNS servers on the interface
3294
3295 @param host: string, the hostname or IP address of the bmc
3296 @param args: contains additional arguments used by the ldap subcommand
3297 args.json: boolean, if this flag is set to true, the output
3298 will be provided in json format for programmatic consumption
3299 @param session: the active session to use
3300 """
3301
3302 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
3303 + "/attr/Nameservers"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003304
3305 try:
Justin Thaler27197622019-01-23 14:42:11 -06003306 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003307 except(requests.exceptions.Timeout):
3308 return(connectionErrHandler(args.json, "Timeout", None))
3309 except(requests.exceptions.ConnectionError) as err:
3310 return connectionErrHandler(args.json, "ConnectionError", err)
3311 if res.status_code == 404:
Sunitha Harishf9bb2fa2019-09-19 01:48:00 -05003312 return "The NameServer is not configured on Interface"+"("+args.Interface+")"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003313
3314 return res.text
3315
3316
3317def setDNS(host, args, session):
3318 """
3319 Called by the network function. Sets DNS servers on the interface.
3320
3321 @param host: string, the hostname or IP address of the bmc
3322 @param args: contains additional arguments used by the ldap subcommand
3323 args.json: boolean, if this flag is set to true, the output
3324 will be provided in json format for programmatic consumption
3325 @param session: the active session to use
3326 """
3327
3328 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
3329 + "/attr/Nameservers"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003330
3331 data = {"data": args.DNSServers.split(",")}
3332
3333 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003334 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003335 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003336 except(requests.exceptions.Timeout):
3337 return(connectionErrHandler(args.json, "Timeout", None))
3338 except(requests.exceptions.ConnectionError) as err:
3339 return connectionErrHandler(args.json, "ConnectionError", err)
3340 if res.status_code == 403:
3341 return "The specified Interface"+"("+args.Interface+")" +\
3342 " doesn't exist"
3343
3344 return res.text
3345
3346
3347def getNTP(host, args, session):
3348
3349 """
3350 Called by the network function. Prints out NTP servers on the interface
3351
3352 @param host: string, the hostname or IP address of the bmc
3353 @param args: contains additional arguments used by the ldap subcommand
3354 args.json: boolean, if this flag is set to true, the output
3355 will be provided in json format for programmatic consumption
3356 @param session: the active session to use
3357 """
3358
3359 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
3360 + "/attr/NTPServers"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003361 try:
Justin Thaler27197622019-01-23 14:42:11 -06003362 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003363 except(requests.exceptions.Timeout):
3364 return(connectionErrHandler(args.json, "Timeout", None))
3365 except(requests.exceptions.ConnectionError) as err:
3366 return connectionErrHandler(args.json, "ConnectionError", err)
3367 if res.status_code == 404:
Sunitha Harishf9bb2fa2019-09-19 01:48:00 -05003368 return "The NTPServer is not configured on Interface"+"("+args.Interface+")"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003369
3370 return res.text
3371
3372
3373def setNTP(host, args, session):
3374 """
3375 Called by the network function. Sets NTP servers on the interface.
3376
3377 @param host: string, the hostname or IP address of the bmc
3378 @param args: contains additional arguments used by the ldap subcommand
3379 args.json: boolean, if this flag is set to true, the output
3380 will be provided in json format for programmatic consumption
3381 @param session: the active session to use
3382 """
3383
3384 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
3385 + "/attr/NTPServers"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003386
3387 data = {"data": args.NTPServers.split(",")}
3388
3389 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003390 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003391 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003392 except(requests.exceptions.Timeout):
3393 return(connectionErrHandler(args.json, "Timeout", None))
3394 except(requests.exceptions.ConnectionError) as err:
3395 return connectionErrHandler(args.json, "ConnectionError", err)
3396 if res.status_code == 403:
3397 return "The specified Interface"+"("+args.Interface+")" +\
3398 " doesn't exist"
3399
3400 return res.text
3401
3402
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003403def addIP(host, args, session):
3404 """
3405 Called by the network function. Configures IP address on given interface
3406
3407 @param host: string, the hostname or IP address of the bmc
3408 @param args: contains additional arguments used by the ldap subcommand
3409 args.json: boolean, if this flag is set to true, the output
3410 will be provided in json format for programmatic consumption
3411 @param session: the active session to use
3412 """
3413
3414 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
3415 + "/action/IP"
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003416 protocol = {
3417 'ipv4': 'xyz.openbmc_project.Network.IP.Protocol.IPv4',
3418 'ipv6': 'xyz.openbmc_project.Network.IP.Protocol.IPv6'
3419 }
3420
3421 data = {"data": [protocol[args.type], args.address, int(args.prefixLength),
3422 args.gateway]}
3423
3424 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003425 res = session.post(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003426 timeout=baseTimeout)
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003427 except(requests.exceptions.Timeout):
3428 return(connectionErrHandler(args.json, "Timeout", None))
3429 except(requests.exceptions.ConnectionError) as err:
3430 return connectionErrHandler(args.json, "ConnectionError", err)
3431 if res.status_code == 404:
3432 return "The specified Interface" + "(" + args.Interface + ")" +\
3433 " doesn't exist"
3434
3435 return res.text
3436
3437
3438def getIP(host, args, session):
3439 """
3440 Called by the network function. Prints out IP address of given interface
3441
3442 @param host: string, the hostname or IP address of the bmc
3443 @param args: contains additional arguments used by the ldap subcommand
3444 args.json: boolean, if this flag is set to true, the output
3445 will be provided in json format for programmatic consumption
3446 @param session: the active session to use
3447 """
3448
3449 url = "https://" + host+"/xyz/openbmc_project/network/" + args.Interface +\
3450 "/enumerate"
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003451 try:
Justin Thaler27197622019-01-23 14:42:11 -06003452 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003453 except(requests.exceptions.Timeout):
3454 return(connectionErrHandler(args.json, "Timeout", None))
3455 except(requests.exceptions.ConnectionError) as err:
3456 return connectionErrHandler(args.json, "ConnectionError", err)
3457 if res.status_code == 404:
3458 return "The specified Interface" + "(" + args.Interface + ")" +\
3459 " doesn't exist"
3460
3461 return res.text
3462
3463
3464def deleteIP(host, args, session):
3465 """
3466 Called by the network function. Deletes the IP address from given Interface
3467
3468 @param host: string, the hostname or IP address of the bmc
3469 @param args: contains additional arguments used by the ldap subcommand
3470 @param session: the active session to use
3471 @param args.json: boolean, if this flag is set to true, the output
3472 will be provided in json format for programmatic consumption
3473 """
3474
3475 url = "https://"+host+"/xyz/openbmc_project/network/" + args.Interface+\
3476 "/enumerate"
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003477 data = {"data": []}
3478 try:
Justin Thaler27197622019-01-23 14:42:11 -06003479 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003480 except(requests.exceptions.Timeout):
3481 return(connectionErrHandler(args.json, "Timeout", None))
3482 except(requests.exceptions.ConnectionError) as err:
3483 return connectionErrHandler(args.json, "ConnectionError", err)
3484 if res.status_code == 404:
3485 return "The specified Interface" + "(" + args.Interface + ")" +\
3486 " doesn't exist"
3487 objDict = json.loads(res.text)
3488 if not objDict['data']:
3489 return "No object found for given address on given Interface"
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003490 for obj in objDict['data']:
Sunitha Harish0baf6372019-07-31 03:59:03 -05003491 try:
3492 if args.address in objDict['data'][obj]['Address']:
3493 url = "https://"+host+obj+"/action/Delete"
3494 try:
3495 res = session.post(url, headers=jsonHeader, json=data,
3496 verify=False, timeout=baseTimeout)
3497 except(requests.exceptions.Timeout):
3498 return(connectionErrHandler(args.json, "Timeout", None))
3499 except(requests.exceptions.ConnectionError) as err:
3500 return connectionErrHandler(args.json, "ConnectionError", err)
3501 return res.text
3502 else:
3503 continue
3504 except KeyError:
Sunitha Harishf9bb2fa2019-09-19 01:48:00 -05003505 continue
3506 return "No object found for address " + args.address + \
3507 " on Interface(" + args.Interface + ")"
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003508
3509
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003510def addVLAN(host, args, session):
3511 """
3512 Called by the network function. Creates VLAN on given interface.
3513
3514 @param host: string, the hostname or IP address of the bmc
3515 @param args: contains additional arguments used by the ldap subcommand
3516 args.json: boolean, if this flag is set to true, the output
3517 will be provided in json format for programmatic consumption
3518 @param session: the active session to use
3519 """
3520
3521 url = "https://" + host+"/xyz/openbmc_project/network/action/VLAN"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003522
Sunitha Harish0baf6372019-07-31 03:59:03 -05003523 data = {"data": [args.Interface,int(args.Identifier)]}
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003524 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003525 res = session.post(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003526 timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003527 except(requests.exceptions.Timeout):
3528 return(connectionErrHandler(args.json, "Timeout", None))
3529 except(requests.exceptions.ConnectionError) as err:
3530 return connectionErrHandler(args.json, "ConnectionError", err)
3531 if res.status_code == 400:
Sunitha Harish0baf6372019-07-31 03:59:03 -05003532 return "Adding VLAN to interface" + "(" + args.Interface + ")" +\
3533 " failed"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003534
3535 return res.text
3536
3537
3538def deleteVLAN(host, args, session):
3539 """
3540 Called by the network function. Creates VLAN on given interface.
3541
3542 @param host: string, the hostname or IP address of the bmc
3543 @param args: contains additional arguments used by the ldap subcommand
3544 args.json: boolean, if this flag is set to true, the output
3545 will be provided in json format for programmatic consumption
3546 @param session: the active session to use
3547 """
3548
Sunitha Harish577a5032019-08-08 06:27:40 -05003549 url = "https://" + host+"/xyz/openbmc_project/network/"+args.Interface+"/action/Delete"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003550 data = {"data": []}
3551
3552 try:
Justin Thaler27197622019-01-23 14:42:11 -06003553 res = session.post(url, headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003554 except(requests.exceptions.Timeout):
3555 return(connectionErrHandler(args.json, "Timeout", None))
3556 except(requests.exceptions.ConnectionError) as err:
3557 return connectionErrHandler(args.json, "ConnectionError", err)
3558 if res.status_code == 404:
Sunitha Harish577a5032019-08-08 06:27:40 -05003559 return "The specified VLAN"+"("+args.Interface+")" +" doesn't exist"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003560
3561 return res.text
3562
3563
3564def viewDHCPConfig(host, args, session):
3565 """
3566 Called by the network function. Shows DHCP configured Properties.
3567
3568 @param host: string, the hostname or IP address of the bmc
3569 @param args: contains additional arguments used by the ldap subcommand
3570 args.json: boolean, if this flag is set to true, the output
3571 will be provided in json format for programmatic consumption
3572 @param session: the active session to use
3573 """
3574
3575 url="https://"+host+"/xyz/openbmc_project/network/config/dhcp"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003576
3577 try:
Justin Thaler27197622019-01-23 14:42:11 -06003578 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003579 except(requests.exceptions.Timeout):
3580 return(connectionErrHandler(args.json, "Timeout", None))
3581 except(requests.exceptions.ConnectionError) as err:
3582 return connectionErrHandler(args.json, "ConnectionError", err)
3583
3584 return res.text
3585
3586
3587def configureDHCP(host, args, session):
3588 """
3589 Called by the network function. Configures/updates DHCP Properties.
3590
3591 @param host: string, the hostname or IP address of the bmc
3592 @param args: contains additional arguments used by the ldap subcommand
3593 args.json: boolean, if this flag is set to true, the output
3594 will be provided in json format for programmatic consumption
3595 @param session: the active session to use
3596 """
3597
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003598
3599 try:
3600 url="https://"+host+"/xyz/openbmc_project/network/config/dhcp"
3601 if(args.DNSEnabled == True):
3602 data = '{"data": 1}'
3603 else:
3604 data = '{"data": 0}'
Matt Spinler220c3c42019-01-04 15:09:29 -06003605 res = session.put(url + '/attr/DNSEnabled', headers=jsonHeader,
Justin Thaler27197622019-01-23 14:42:11 -06003606 data=data, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003607 if(args.HostNameEnabled == True):
3608 data = '{"data": 1}'
3609 else:
3610 data = '{"data": 0}'
Matt Spinler220c3c42019-01-04 15:09:29 -06003611 res = session.put(url + '/attr/HostNameEnabled', headers=jsonHeader,
Justin Thaler27197622019-01-23 14:42:11 -06003612 data=data, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003613 if(args.NTPEnabled == True):
3614 data = '{"data": 1}'
3615 else:
3616 data = '{"data": 0}'
Matt Spinler220c3c42019-01-04 15:09:29 -06003617 res = session.put(url + '/attr/NTPEnabled', headers=jsonHeader,
Justin Thaler27197622019-01-23 14:42:11 -06003618 data=data, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003619 if(args.SendHostNameEnabled == True):
3620 data = '{"data": 1}'
3621 else:
3622 data = '{"data": 0}'
Matt Spinler220c3c42019-01-04 15:09:29 -06003623 res = session.put(url + '/attr/SendHostNameEnabled', headers=jsonHeader,
Justin Thaler27197622019-01-23 14:42:11 -06003624 data=data, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003625 except(requests.exceptions.Timeout):
3626 return(connectionErrHandler(args.json, "Timeout", None))
3627 except(requests.exceptions.ConnectionError) as err:
3628 return connectionErrHandler(args.json, "ConnectionError", err)
3629
3630 return res.text
3631
3632
3633def nwReset(host, args, session):
3634
3635 """
3636 Called by the network function. Resets networks setting to factory defaults.
3637
3638 @param host: string, the hostname or IP address of the bmc
3639 @param args: contains additional arguments used by the ldap subcommand
3640 args.json: boolean, if this flag is set to true, the output
3641 will be provided in json format for programmatic consumption
3642 @param session: the active session to use
3643 """
3644
3645 url = "https://"+host+"/xyz/openbmc_project/network/action/Reset"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003646 data = '{"data":[] }'
3647 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003648 res = session.post(url, headers=jsonHeader, data=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003649 timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003650
3651 except(requests.exceptions.Timeout):
3652 return(connectionErrHandler(args.json, "Timeout", None))
3653 except(requests.exceptions.ConnectionError) as err:
3654 return connectionErrHandler(args.json, "ConnectionError", err)
3655
3656 return res.text
3657
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003658def getLDAPTypeEnabled(host,session):
3659
3660 """
3661 Called by LDAP related functions to find the LDAP server type that has been enabled.
3662 Returns None if LDAP has not been configured.
3663
3664 @param host: string, the hostname or IP address of the bmc
3665 @param session: the active session to use
3666 """
3667
3668 enabled = False
3669 url = 'https://'+host+'/xyz/openbmc_project/user/ldap/'
3670 for key,value in serverTypeMap.items():
3671 data = {"data": []}
3672 try:
3673 res = session.get(url + value + '/attr/Enabled', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
3674 except(requests.exceptions.Timeout):
3675 print(connectionErrHandler(args.json, "Timeout", None))
3676 return
3677 except(requests.exceptions.ConnectionError) as err:
3678 print(connectionErrHandler(args.json, "ConnectionError", err))
3679 return
3680
3681 enabled = res.json()['data']
3682 if (enabled):
3683 return key
3684
3685def syncRoleMap(host,args,session,fromServerType,toServerType):
3686
3687 """
3688 Called by LDAP related functions to sync the role maps
3689 Returns False if LDAP has not been configured.
3690
3691 @param host: string, the hostname or IP address of the bmc
3692 @param session: the active session to use
3693 @param fromServerType : Server type whose role map has to be copied
3694 @param toServerType : Server type to which role map has to be copied
3695 """
3696
3697 url = "https://"+host+"/xyz/openbmc_project/user/ldap/"
3698
3699 try:
3700 #Note: If the fromServerType has no role map, then
3701 #the toServerType will not have any role map.
3702
3703 #delete the privilege mapping from the toServerType and
3704 #then copy the privilege mapping from fromServerType to
3705 #toServerType.
3706 args.serverType = toServerType
3707 res = deleteAllPrivilegeMapping(host, args, session)
3708
3709 data = {"data": []}
3710 res = session.get(url + serverTypeMap[fromServerType] + '/role_map/enumerate', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
3711 #Previously enabled server type has no role map
3712 if (res.status_code != requests.codes.ok):
3713
3714 #fromServerType has no role map; So, no need to copy
3715 #role map to toServerType.
3716 return
3717
3718 objDict = json.loads(res.text)
3719 dataDict = objDict['data']
3720 for key,value in dataDict.items():
3721 data = {"data": [value["GroupName"], value["Privilege"]]}
3722 res = session.post(url + serverTypeMap[toServerType] + '/action/Create', headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
3723
3724 except(requests.exceptions.Timeout):
3725 return(connectionErrHandler(args.json, "Timeout", None))
3726 except(requests.exceptions.ConnectionError) as err:
3727 return connectionErrHandler(args.json, "ConnectionError", err)
3728 return res.text
3729
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003730
Ratan Guptafeee6372018-10-17 23:25:51 +05303731def createPrivilegeMapping(host, args, session):
3732 """
3733 Called by the ldap function. Creates the group and the privilege mapping.
3734
3735 @param host: string, the hostname or IP address of the bmc
3736 @param args: contains additional arguments used by the ldap subcommand
3737 @param session: the active session to use
3738 @param args.json: boolean, if this flag is set to true, the output
3739 will be provided in json format for programmatic consumption
3740 """
3741
Ratan Guptafeee6372018-10-17 23:25:51 +05303742 try:
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003743 if (isRedfishSupport):
3744 url = 'https://'+host+'/xyz/openbmc_project/user/ldap/'
3745
3746 #To maintain the interface compatibility between op930 and op940, the server type has been made
3747 #optional. If the server type is not specified, then create the role-mapper for the currently
3748 #enabled server type.
3749 serverType = args.serverType
3750 if (serverType is None):
3751 serverType = getLDAPTypeEnabled(host,session)
3752 if (serverType is None):
3753 return("LDAP server has not been enabled. Please specify LDAP serverType to proceed further...")
3754
3755 data = {"data": [args.groupName,args.privilege]}
3756 res = session.post(url + serverTypeMap[serverType] + '/action/Create', headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
3757
3758 else:
3759 url = 'https://'+host+'/xyz/openbmc_project/user/ldap/action/Create'
3760 data = {"data": [args.groupName,args.privilege]}
3761 res = session.post(url, headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
3762
Ratan Guptafeee6372018-10-17 23:25:51 +05303763 except(requests.exceptions.Timeout):
3764 return(connectionErrHandler(args.json, "Timeout", None))
3765 except(requests.exceptions.ConnectionError) as err:
3766 return connectionErrHandler(args.json, "ConnectionError", err)
3767 return res.text
3768
3769def listPrivilegeMapping(host, args, session):
3770 """
3771 Called by the ldap function. Lists the group and the privilege mapping.
3772
3773 @param host: string, the hostname or IP address of the bmc
3774 @param args: contains additional arguments used by the ldap subcommand
3775 @param session: the active session to use
3776 @param args.json: boolean, if this flag is set to true, the output
3777 will be provided in json format for programmatic consumption
3778 """
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003779
3780 if (isRedfishSupport):
3781 serverType = args.serverType
3782 if (serverType is None):
3783 serverType = getLDAPTypeEnabled(host,session)
3784 if (serverType is None):
3785 return("LDAP has not been enabled. Please specify LDAP serverType to proceed further...")
3786
3787 url = 'https://'+host+'/xyz/openbmc_project/user/ldap/'+serverTypeMap[serverType]+'/role_map/enumerate'
3788
3789 else:
3790 url = 'https://'+host+'/xyz/openbmc_project/user/ldap/enumerate'
3791
Ratan Guptafeee6372018-10-17 23:25:51 +05303792 data = {"data": []}
3793
3794 try:
Justin Thaler27197622019-01-23 14:42:11 -06003795 res = session.get(url, headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
Ratan Guptafeee6372018-10-17 23:25:51 +05303796 except(requests.exceptions.Timeout):
3797 return(connectionErrHandler(args.json, "Timeout", None))
3798 except(requests.exceptions.ConnectionError) as err:
3799 return connectionErrHandler(args.json, "ConnectionError", err)
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003800
Ratan Guptafeee6372018-10-17 23:25:51 +05303801 return res.text
3802
3803def deletePrivilegeMapping(host, args, session):
3804 """
3805 Called by the ldap function. Deletes the mapping associated with the group.
3806
3807 @param host: string, the hostname or IP address of the bmc
3808 @param args: contains additional arguments used by the ldap subcommand
3809 @param session: the active session to use
3810 @param args.json: boolean, if this flag is set to true, the output
3811 will be provided in json format for programmatic consumption
3812 """
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003813
3814 ldapNameSpaceObjects = listPrivilegeMapping(host, args, session)
Ratan Guptafeee6372018-10-17 23:25:51 +05303815 ldapNameSpaceObjects = json.loads(ldapNameSpaceObjects)["data"]
3816 path = ''
Ratan Guptafeee6372018-10-17 23:25:51 +05303817 data = {"data": []}
3818
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003819 if (isRedfishSupport):
3820 if (args.serverType is None):
3821 serverType = getLDAPTypeEnabled(host,session)
3822 if (serverType is None):
3823 return("LDAP has not been enabled. Please specify LDAP serverType to proceed further...")
3824 # search for the object having the mapping for the given group
3825 for key,value in ldapNameSpaceObjects.items():
3826 if value['GroupName'] == args.groupName:
3827 path = key
3828 break
3829
3830 if path == '':
3831 return "No privilege mapping found for this group."
3832
3833 # delete the object
3834 url = 'https://'+host+path+'/action/Delete'
3835
3836 else:
3837 # not interested in the config objet
3838 ldapNameSpaceObjects.pop('/xyz/openbmc_project/user/ldap/config', None)
3839
3840 # search for the object having the mapping for the given group
3841 for key,value in ldapNameSpaceObjects.items():
3842 if value['GroupName'] == args.groupName:
3843 path = key
3844 break
3845
3846 if path == '':
3847 return "No privilege mapping found for this group."
3848
3849 # delete the object
3850 url = 'https://'+host+path+'/action/delete'
3851
Ratan Guptafeee6372018-10-17 23:25:51 +05303852 try:
Justin Thaler27197622019-01-23 14:42:11 -06003853 res = session.post(url, headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
Ratan Guptafeee6372018-10-17 23:25:51 +05303854 except(requests.exceptions.Timeout):
3855 return(connectionErrHandler(args.json, "Timeout", None))
3856 except(requests.exceptions.ConnectionError) as err:
3857 return connectionErrHandler(args.json, "ConnectionError", err)
3858 return res.text
Ratan Gupta9166cd22018-10-01 18:09:40 +05303859
Sivas SRR78835272018-11-27 05:27:19 -06003860def deleteAllPrivilegeMapping(host, args, session):
3861 """
3862 Called by the ldap function. Deletes all the privilege mapping and group defined.
3863 @param host: string, the hostname or IP address of the bmc
3864 @param args: contains additional arguments used by the ldap subcommand
3865 @param session: the active session to use
3866 @param args.json: boolean, if this flag is set to true, the output
3867 will be provided in json format for programmatic consumption
3868 """
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003869
Sivas SRR78835272018-11-27 05:27:19 -06003870 ldapNameSpaceObjects = listPrivilegeMapping(host, args, session)
3871 ldapNameSpaceObjects = json.loads(ldapNameSpaceObjects)["data"]
3872 path = ''
Sivas SRR78835272018-11-27 05:27:19 -06003873 data = {"data": []}
3874
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003875 if (isRedfishSupport):
3876 if (args.serverType is None):
3877 serverType = getLDAPTypeEnabled(host,session)
3878 if (serverType is None):
3879 return("LDAP has not been enabled. Please specify LDAP serverType to proceed further...")
3880
3881 else:
3882 # Remove the config object.
3883 ldapNameSpaceObjects.pop('/xyz/openbmc_project/user/ldap/config', None)
3884
Sivas SRR78835272018-11-27 05:27:19 -06003885 try:
3886 # search for GroupName property and delete if it is available.
3887 for path in ldapNameSpaceObjects.keys():
3888 # delete the object
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003889 url = 'https://'+host+path+'/action/Delete'
Justin Thaler27197622019-01-23 14:42:11 -06003890 res = session.post(url, headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003891
Sivas SRR78835272018-11-27 05:27:19 -06003892 except(requests.exceptions.Timeout):
3893 return(connectionErrHandler(args.json, "Timeout", None))
3894 except(requests.exceptions.ConnectionError) as err:
3895 return connectionErrHandler(args.json, "ConnectionError", err)
3896 return res.text
3897
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06003898def viewLDAPConfig(host, args, session):
3899 """
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003900 Called by the ldap function. Prints out active LDAP configuration properties
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06003901
3902 @param host: string, the hostname or IP address of the bmc
3903 @param args: contains additional arguments used by the ldap subcommand
3904 args.json: boolean, if this flag is set to true, the output
3905 will be provided in json format for programmatic consumption
3906 @param session: the active session to use
3907 @return returns LDAP's configured properties.
3908 """
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003909
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06003910 try:
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003911 if (isRedfishSupport):
3912
3913 url = "https://"+host+"/xyz/openbmc_project/user/ldap/"
3914
3915 serverTypeEnabled = getLDAPTypeEnabled(host,session)
3916
3917 if (serverTypeEnabled is not None):
3918 data = {"data": []}
3919 res = session.get(url + serverTypeMap[serverTypeEnabled], headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
3920 else:
3921 return("LDAP server has not been enabled...")
3922
3923 else :
3924 url = "https://"+host+"/xyz/openbmc_project/user/ldap/config"
3925 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
3926
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06003927 except(requests.exceptions.Timeout):
3928 return(connectionErrHandler(args.json, "Timeout", None))
3929 except(requests.exceptions.ConnectionError) as err:
3930 return connectionErrHandler(args.json, "ConnectionError", err)
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06003931 if res.status_code == 404:
3932 return "LDAP server config has not been created"
3933 return res.text
3934
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003935def str2bool(v):
3936 if v.lower() in ('yes', 'true', 't', 'y', '1'):
3937 return True
3938 elif v.lower() in ('no', 'false', 'f', 'n', '0'):
3939 return False
3940 else:
3941 raise argparse.ArgumentTypeError('Boolean value expected.')
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06003942
Matt Spinler7d426c22018-09-24 14:42:07 -05003943def localUsers(host, args, session):
3944 """
3945 Enables and disables local BMC users.
3946
3947 @param host: string, the hostname or IP address of the bmc
3948 @param args: contains additional arguments used by the logging sub command
3949 @param session: the active session to use
3950 """
3951
Matt Spinler7d426c22018-09-24 14:42:07 -05003952 url="https://{hostname}/xyz/openbmc_project/user/enumerate".format(hostname=host)
3953 try:
Justin Thaler27197622019-01-23 14:42:11 -06003954 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Matt Spinler7d426c22018-09-24 14:42:07 -05003955 except(requests.exceptions.Timeout):
3956 return(connectionErrHandler(args.json, "Timeout", None))
3957 usersDict = json.loads(res.text)
3958
3959 if not usersDict['data']:
3960 return "No users found"
3961
3962 output = ""
3963 for user in usersDict['data']:
Matt Spinler015adc22018-10-23 14:30:19 -05003964
3965 # Skip LDAP and another non-local users
3966 if 'UserEnabled' not in usersDict['data'][user]:
3967 continue
3968
Matt Spinler7d426c22018-09-24 14:42:07 -05003969 name = user.split('/')[-1]
3970 url = "https://{hostname}{user}/attr/UserEnabled".format(hostname=host, user=user)
3971
3972 if args.local_users == "queryenabled":
3973 try:
Justin Thaler27197622019-01-23 14:42:11 -06003974 res = session.get(url, headers=jsonHeader,verify=False, timeout=baseTimeout)
Matt Spinler7d426c22018-09-24 14:42:07 -05003975 except(requests.exceptions.Timeout):
3976 return(connectionErrHandler(args.json, "Timeout", None))
3977
3978 result = json.loads(res.text)
3979 output += ("User: {name} Enabled: {result}\n").format(name=name, result=result['data'])
3980
3981 elif args.local_users in ["enableall", "disableall"]:
3982 action = ""
3983 if args.local_users == "enableall":
3984 data = '{"data": true}'
3985 action = "Enabling"
3986 else:
3987 data = '{"data": false}'
3988 action = "Disabling"
3989
3990 output += "{action} {name}\n".format(action=action, name=name)
3991
3992 try:
Justin Thaler27197622019-01-23 14:42:11 -06003993 resp = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Matt Spinler7d426c22018-09-24 14:42:07 -05003994 except(requests.exceptions.Timeout):
3995 return connectionErrHandler(args.json, "Timeout", None)
3996 except(requests.exceptions.ConnectionError) as err:
3997 return connectionErrHandler(args.json, "ConnectionError", err)
3998 else:
3999 return "Invalid local users argument"
4000
4001 return output
4002
Marri Devender Rao2c2a5162018-11-05 08:57:11 -06004003def setPassword(host, args, session):
4004 """
4005 Set local user password
4006 @param host: string, the hostname or IP address of the bmc
4007 @param args: contains additional arguments used by the logging sub
4008 command
4009 @param session: the active session to use
4010 @param args.json: boolean, if this flag is set to true, the output
4011 will be provided in json format for programmatic consumption
4012 @return: Session object
4013 """
Marri Devender Rao2c2a5162018-11-05 08:57:11 -06004014 try:
Sunitha Harishc99faba2019-07-19 06:55:22 -05004015 if(isRedfishSupport):
4016 url = "https://" + host + "/redfish/v1/AccountService/Accounts/"+ \
4017 args.user
4018 data = {"Password":args.password}
4019 res = session.patch(url, headers=jsonHeader, json=data,
4020 verify=False, timeout=baseTimeout)
4021 else:
4022 url = "https://" + host + "/xyz/openbmc_project/user/" + args.user + \
4023 "/action/SetPassword"
4024 res = session.post(url, headers=jsonHeader,
Marri Devender Rao2c2a5162018-11-05 08:57:11 -06004025 json={"data": [args.password]}, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06004026 timeout=baseTimeout)
Marri Devender Rao2c2a5162018-11-05 08:57:11 -06004027 except(requests.exceptions.Timeout):
4028 return(connectionErrHandler(args.json, "Timeout", None))
4029 except(requests.exceptions.ConnectionError) as err:
4030 return connectionErrHandler(args.json, "ConnectionError", err)
4031 except(requests.exceptions.RequestException) as err:
4032 return connectionErrHandler(args.json, "RequestException", err)
Sunitha Harishc99faba2019-07-19 06:55:22 -05004033 return res.status_code
Matthew Barth368e83c2019-02-01 13:48:25 -06004034
4035def getThermalZones(host, args, session):
4036 """
4037 Get the available thermal control zones
4038 @param host: string, the hostname or IP address of the bmc
4039 @param args: contains additional arguments used to get the thermal
4040 control zones
4041 @param session: the active session to use
4042 @return: Session object
4043 """
4044 url = "https://" + host + "/xyz/openbmc_project/control/thermal/enumerate"
4045
4046 try:
4047 res = session.get(url, headers=jsonHeader, verify=False, timeout=30)
4048 except(requests.exceptions.Timeout):
4049 return(connectionErrHandler(args.json, "Timeout", None))
4050 except(requests.exceptions.ConnectionError) as err:
4051 return connectionErrHandler(args.json, "ConnectionError", err)
4052 except(requests.exceptions.RequestException) as err:
4053 return connectionErrHandler(args.json, "RequestException", err)
4054
4055 if (res.status_code == 404):
Matthew Barth0939e822019-09-27 15:47:50 -05004056 return "No thermal control zones found"
Matthew Barth368e83c2019-02-01 13:48:25 -06004057
4058 zonesDict = json.loads(res.text)
4059 if not zonesDict['data']:
4060 return "No thermal control zones found"
4061 for zone in zonesDict['data']:
4062 z = ",".join(str(zone.split('/')[-1]) for zone in zonesDict['data'])
4063
4064 return "Zones: [ " + z + " ]"
4065
4066
4067def getThermalMode(host, args, session):
4068 """
4069 Get thermal control mode
4070 @param host: string, the hostname or IP address of the bmc
4071 @param args: contains additional arguments used to get the thermal
4072 control mode
4073 @param session: the active session to use
4074 @param args.zone: the zone to get the mode on
4075 @return: Session object
4076 """
4077 url = "https://" + host + "/xyz/openbmc_project/control/thermal/" + \
4078 args.zone
4079
4080 try:
4081 res = session.get(url, headers=jsonHeader, verify=False, timeout=30)
4082 except(requests.exceptions.Timeout):
4083 return(connectionErrHandler(args.json, "Timeout", None))
4084 except(requests.exceptions.ConnectionError) as err:
4085 return connectionErrHandler(args.json, "ConnectionError", err)
4086 except(requests.exceptions.RequestException) as err:
4087 return connectionErrHandler(args.json, "RequestException", err)
4088
4089 if (res.status_code == 404):
Matthew Barth0939e822019-09-27 15:47:50 -05004090 return "Thermal control zone(" + args.zone + ") not found"
Matthew Barth368e83c2019-02-01 13:48:25 -06004091
4092 propsDict = json.loads(res.text)
4093 if not propsDict['data']:
4094 return "No thermal control properties found on zone(" + args.zone + ")"
4095 curMode = "Current"
4096 supModes = "Supported"
4097 result = "\n"
4098 for prop in propsDict['data']:
4099 if (prop.casefold() == curMode.casefold()):
4100 result += curMode + " Mode: " + propsDict['data'][curMode] + "\n"
4101 if (prop.casefold() == supModes.casefold()):
4102 s = ", ".join(str(sup) for sup in propsDict['data'][supModes])
4103 result += supModes + " Modes: [ " + s + " ]\n"
4104
4105 return result
4106
4107def setThermalMode(host, args, session):
4108 """
4109 Set thermal control mode
4110 @param host: string, the hostname or IP address of the bmc
4111 @param args: contains additional arguments used for setting the thermal
4112 control mode
4113 @param session: the active session to use
4114 @param args.zone: the zone to set the mode on
4115 @param args.mode: the mode to enable
4116 @return: Session object
4117 """
4118 url = "https://" + host + "/xyz/openbmc_project/control/thermal/" + \
4119 args.zone + "/attr/Current"
4120
4121 # Check args.mode against supported modes using `getThermalMode` output
4122 modes = getThermalMode(host, args, session)
4123 modes = os.linesep.join([m for m in modes.splitlines() if m])
4124 modes = modes.replace("\n", ";").strip()
4125 modesDict = dict(m.split(': ') for m in modes.split(';'))
4126 sModes = ''.join(s for s in modesDict['Supported Modes'] if s not in '[ ]')
4127 if args.mode.casefold() not in \
4128 (m.casefold() for m in sModes.split(',')) or not args.mode:
4129 result = ("Unsupported mode('" + args.mode + "') given, " +
4130 "select a supported mode: \n" +
4131 getThermalMode(host, args, session))
4132 return result
4133
4134 data = '{"data":"' + args.mode + '"}'
4135 try:
4136 res = session.get(url, headers=jsonHeader, verify=False, timeout=30)
4137 except(requests.exceptions.Timeout):
4138 return(connectionErrHandler(args.json, "Timeout", None))
4139 except(requests.exceptions.ConnectionError) as err:
4140 return connectionErrHandler(args.json, "ConnectionError", err)
4141 except(requests.exceptions.RequestException) as err:
4142 return connectionErrHandler(args.json, "RequestException", err)
4143
4144 if (data and res.status_code != 404):
4145 try:
4146 res = session.put(url, headers=jsonHeader,
4147 data=data, verify=False,
4148 timeout=30)
4149 except(requests.exceptions.Timeout):
4150 return(connectionErrHandler(args.json, "Timeout", None))
4151 except(requests.exceptions.ConnectionError) as err:
4152 return connectionErrHandler(args.json, "ConnectionError", err)
4153 except(requests.exceptions.RequestException) as err:
4154 return connectionErrHandler(args.json, "RequestException", err)
4155
4156 if res.status_code == 403:
4157 return "The specified thermal control zone(" + args.zone + ")" + \
4158 " does not exist"
4159
4160 return res.text
4161 else:
4162 return "Setting thermal control mode(" + args.mode + ")" + \
Matthew Barth0939e822019-09-27 15:47:50 -05004163 " not supported or operation not available"
Matthew Barth368e83c2019-02-01 13:48:25 -06004164
4165
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004166def createCommandParser():
Justin Thalere412dc22018-01-12 16:28:24 -06004167 """
4168 creates the parser for the command line along with help for each command and subcommand
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004169
Justin Thalere412dc22018-01-12 16:28:24 -06004170 @return: returns the parser for the command line
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004171 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004172 parser = argparse.ArgumentParser(description='Process arguments')
Justin Thalere412dc22018-01-12 16:28:24 -06004173 parser.add_argument("-H", "--host", help='A hostname or IP for the BMC')
4174 parser.add_argument("-U", "--user", help='The username to login with')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004175 group = parser.add_mutually_exclusive_group()
4176 group.add_argument("-A", "--askpw", action='store_true', help='prompt for password')
4177 group.add_argument("-P", "--PW", help='Provide the password in-line')
Joseph Reynoldsa2d54c52019-06-11 22:02:57 -05004178 group.add_argument("-E", "--PWenvvar", action='store_true', help='Get password from envvar OPENBMCTOOL_PASSWORD')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004179 parser.add_argument('-j', '--json', action='store_true', help='output json data only')
4180 parser.add_argument('-t', '--policyTableLoc', help='The location of the policy table to parse alerts')
4181 parser.add_argument('-c', '--CerFormat', action='store_true', help=argparse.SUPPRESS)
4182 parser.add_argument('-T', '--procTime', action='store_true', help= argparse.SUPPRESS)
Justin Thalere412dc22018-01-12 16:28:24 -06004183 parser.add_argument('-V', '--version', action='store_true', help='Display the version number of the openbmctool')
4184 subparsers = parser.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004185
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004186 #fru command
4187 parser_inv = subparsers.add_parser("fru", help='Work with platform inventory')
Justin Thalere412dc22018-01-12 16:28:24 -06004188 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 -05004189 inv_subparser.required = True
4190 #fru print
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004191 inv_print = inv_subparser.add_parser("print", help="prints out a list of all FRUs")
4192 inv_print.set_defaults(func=fruPrint)
4193 #fru list [0....n]
4194 inv_list = inv_subparser.add_parser("list", help="print out details on selected FRUs. Specifying no items will list the entire inventory")
4195 inv_list.add_argument('items', nargs='?', help="print out details on selected FRUs. Specifying no items will list the entire inventory")
4196 inv_list.set_defaults(func=fruList)
4197 #fru status
4198 inv_status = inv_subparser.add_parser("status", help="prints out the status of all FRUs")
Justin Thalere412dc22018-01-12 16:28:24 -06004199 inv_status.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004200 inv_status.set_defaults(func=fruStatus)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004201
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004202 #sensors command
4203 parser_sens = subparsers.add_parser("sensors", help="Work with platform sensors")
Justin Thalere412dc22018-01-12 16:28:24 -06004204 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 -05004205 sens_subparser.required = True
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004206 #sensor print
4207 sens_print= sens_subparser.add_parser('print', help="prints out a list of all Sensors.")
4208 sens_print.set_defaults(func=sensor)
4209 #sensor list[0...n]
4210 sens_list=sens_subparser.add_parser("list", help="Lists all Sensors in the platform. Specify a sensor for full details. ")
4211 sens_list.add_argument("sensNum", nargs='?', help="The Sensor number to get full details on" )
4212 sens_list.set_defaults(func=sensor)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004213
Matthew Barth368e83c2019-02-01 13:48:25 -06004214 #thermal control commands
4215 parser_therm = subparsers.add_parser("thermal", help="Work with thermal control parameters")
4216 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')
4217 #thermal control zones
4218 parser_thermZones = therm_subparser.add_parser("zones", help="Get a list of available thermal control zones")
4219 parser_thermZones.set_defaults(func=getThermalZones)
4220 #thermal control modes
4221 parser_thermMode = therm_subparser.add_parser("modes", help="Work with thermal control modes")
4222 thermMode_sub = parser_thermMode.add_subparsers(title='subactions', description='Work with thermal control modes', help="Work with thermal control modes")
4223 #get thermal control mode
4224 parser_getThermMode = thermMode_sub.add_parser("get", help="Get current and supported thermal control modes")
4225 parser_getThermMode.add_argument('-z', '--zone', required=True, help='Thermal zone to work with')
4226 parser_getThermMode.set_defaults(func=getThermalMode)
4227 #set thermal control mode
4228 parser_setThermMode = thermMode_sub.add_parser("set", help="Set the thermal control mode")
4229 parser_setThermMode.add_argument('-z', '--zone', required=True, help='Thermal zone to work with')
4230 parser_setThermMode.add_argument('-m', '--mode', required=True, help='The supported thermal control mode')
4231 parser_setThermMode.set_defaults(func=setThermalMode)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004232
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004233 #sel command
4234 parser_sel = subparsers.add_parser("sel", help="Work with platform alerts")
Justin Thalere412dc22018-01-12 16:28:24 -06004235 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 -05004236 sel_subparser.required = True
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004237 #sel print
4238 sel_print = sel_subparser.add_parser("print", help="prints out a list of all sels in a condensed list")
4239 sel_print.add_argument('-d', '--devdebug', action='store_true', help=argparse.SUPPRESS)
4240 sel_print.add_argument('-v', '--verbose', action='store_true', help="Changes the output to being very verbose")
4241 sel_print.add_argument('-f', '--fileloc', help='Parse a file instead of the BMC output')
4242 sel_print.set_defaults(func=selPrint)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004243
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004244 #sel list
4245 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")
4246 sel_list.add_argument("selNum", nargs='?', type=int, help="The SEL entry to get details on")
4247 sel_list.set_defaults(func=selList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004248
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004249 sel_get = sel_subparser.add_parser("get", help="Gets the verbose details of a specified SEL entry")
4250 sel_get.add_argument('selNum', type=int, help="the number of the SEL entry to get")
4251 sel_get.set_defaults(func=selList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004252
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004253 sel_clear = sel_subparser.add_parser("clear", help="Clears all entries from the SEL")
4254 sel_clear.set_defaults(func=selClear)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004255
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004256 sel_setResolved = sel_subparser.add_parser("resolve", help="Sets the sel entry to resolved")
Justin Thalere412dc22018-01-12 16:28:24 -06004257 sel_setResolved.add_argument('-n', '--selNum', type=int, help="the number of the SEL entry to resolve")
4258 sel_ResolveAll_sub = sel_setResolved.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
4259 sel_ResolveAll = sel_ResolveAll_sub.add_parser('all', help='Resolve all SEL entries')
4260 sel_ResolveAll.set_defaults(func=selResolveAll)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004261 sel_setResolved.set_defaults(func=selSetResolved)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004262
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004263 parser_chassis = subparsers.add_parser("chassis", help="Work with chassis power and status")
Justin Thalere412dc22018-01-12 16:28:24 -06004264 chas_sub = parser_chassis.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004265
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004266 parser_chassis.add_argument('status', action='store_true', help='Returns the current status of the platform')
4267 parser_chassis.set_defaults(func=chassis)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004268
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004269 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 -06004270 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 -06004271 parser_chasPower.set_defaults(func=chassisPower)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004272
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004273 #control the chassis identify led
4274 parser_chasIdent = chas_sub.add_parser("identify", help="Control the chassis identify led")
4275 parser_chasIdent.add_argument('identcmd', choices=['on', 'off', 'status'], help='The control option for the led: on, off, blink, status')
4276 parser_chasIdent.set_defaults(func=chassisIdent)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004277
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004278 #collect service data
4279 parser_servData = subparsers.add_parser("collect_service_data", help="Collect all bmc data needed for service")
4280 parser_servData.add_argument('-d', '--devdebug', action='store_true', help=argparse.SUPPRESS)
4281 parser_servData.set_defaults(func=collectServiceData)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004282
Justin Thalere412dc22018-01-12 16:28:24 -06004283 #system quick health check
4284 parser_healthChk = subparsers.add_parser("health_check", help="Work with platform sensors")
4285 parser_healthChk.set_defaults(func=healthCheck)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004286
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004287 #work with bmc dumps
4288 parser_bmcdump = subparsers.add_parser("dump", help="Work with bmc dump files")
Justin Thalere412dc22018-01-12 16:28:24 -06004289 bmcDump_sub = parser_bmcdump.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Justin Thaler53bf2f12018-07-16 14:05:32 -05004290 bmcDump_sub.required = True
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004291 dump_Create = bmcDump_sub.add_parser('create', help="Create a bmc dump")
4292 dump_Create.set_defaults(func=bmcDumpCreate)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004293
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004294 dump_list = bmcDump_sub.add_parser('list', help="list all bmc dump files")
4295 dump_list.set_defaults(func=bmcDumpList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004296
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004297 parserdumpdelete = bmcDump_sub.add_parser('delete', help="Delete bmc dump files")
4298 parserdumpdelete.add_argument("-n", "--dumpNum", nargs='*', type=int, help="The Dump entry to delete")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004299 parserdumpdelete.set_defaults(func=bmcDumpDelete)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004300
Justin Thalere412dc22018-01-12 16:28:24 -06004301 bmcDumpDelsub = parserdumpdelete.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004302 deleteAllDumps = bmcDumpDelsub.add_parser('all', help='Delete all bmc dump files')
4303 deleteAllDumps.set_defaults(func=bmcDumpDeleteAll)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004304
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004305 parser_dumpretrieve = bmcDump_sub.add_parser('retrieve', help='Retrieve a dump file')
4306 parser_dumpretrieve.add_argument("dumpNum", type=int, help="The Dump entry to delete")
4307 parser_dumpretrieve.add_argument("-s", "--dumpSaveLoc", help="The location to save the bmc dump file")
4308 parser_dumpretrieve.set_defaults(func=bmcDumpRetrieve)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004309
Justin Thaler22b1bb52018-03-15 13:31:32 -05004310 #bmc command for reseting the bmc
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004311 parser_bmc = subparsers.add_parser('bmc', help="Work with the bmc")
Justin Thalere412dc22018-01-12 16:28:24 -06004312 bmc_sub = parser_bmc.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004313 parser_BMCReset = bmc_sub.add_parser('reset', help='Reset the bmc' )
4314 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 -06004315 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.")
4316 parser_bmc.set_defaults(func=bmc)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004317
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004318 #add alias to the bmc command
4319 parser_mc = subparsers.add_parser('mc', help="Work with the management controller")
Justin Thalere412dc22018-01-12 16:28:24 -06004320 mc_sub = parser_mc.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004321 parser_MCReset = mc_sub.add_parser('reset', help='Reset the bmc' )
4322 parser_MCReset.add_argument('type', choices=['warm','cold'], help="Reboot the BMC")
4323 #parser_MCReset.add_argument('cold', action='store_true', help="Reboot the BMC and CLEAR the configuration")
4324 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 -06004325 parser_MCReset.set_defaults(func=bmcReset)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004326 parser_mc.set_defaults(func=bmc)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004327
Justin Thalere412dc22018-01-12 16:28:24 -06004328 #gard clear
4329 parser_gc = subparsers.add_parser("gardclear", help="Used to clear gard records")
4330 parser_gc.set_defaults(func=gardClear)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004331
Justin Thalere412dc22018-01-12 16:28:24 -06004332 #firmware_flash
4333 parser_fw = subparsers.add_parser("firmware", help="Work with the system firmware")
4334 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 -05004335 fwflash_subproc.required = True
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004336
Justin Thalere412dc22018-01-12 16:28:24 -06004337 fwflash = fwflash_subproc.add_parser('flash', help="Flash the system firmware")
4338 fwflash.add_argument('type', choices=['bmc', 'pnor'], help="image type to flash")
4339 fwflash.add_argument('-f', '--fileloc', required=True, help="The absolute path to the firmware image")
4340 fwflash.set_defaults(func=fwFlash)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004341
Justin Thaler22b1bb52018-03-15 13:31:32 -05004342 fwActivate = fwflash_subproc.add_parser('activate', help="Activate existing image on the bmc")
Justin Thalere412dc22018-01-12 16:28:24 -06004343 fwActivate.add_argument('imageID', help="The image ID to activate from the firmware list. Ex: 63c95399")
4344 fwActivate.set_defaults(func=activateFWImage)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004345
Justin Thaler22b1bb52018-03-15 13:31:32 -05004346 fwActivateStatus = fwflash_subproc.add_parser('activation_status', help="Check Status of activations")
4347 fwActivateStatus.set_defaults(func=activateStatus)
4348
Justin Thaler3d71d402018-07-24 14:35:39 -05004349 fwList = fwflash_subproc.add_parser('list', help="List all of the installed firmware")
4350 fwList.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
4351 fwList.set_defaults(func=firmwareList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004352
Justin Thaler3d71d402018-07-24 14:35:39 -05004353 fwprint = fwflash_subproc.add_parser('print', help="List all of the installed firmware")
4354 fwprint.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
4355 fwprint.set_defaults(func=firmwareList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004356
Adriana Kobylak5af2fad2018-11-08 12:33:43 -06004357 fwDelete = fwflash_subproc.add_parser('delete', help="Delete an existing firmware version")
4358 fwDelete.add_argument('versionID', help="The version ID to delete from the firmware list. Ex: 63c95399")
4359 fwDelete.set_defaults(func=deleteFWVersion)
4360
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05004361 #logging
4362 parser_logging = subparsers.add_parser("logging", help="logging controls")
4363 logging_sub = parser_logging.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004364
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05004365 #turn rest api logging on/off
4366 parser_rest_logging = logging_sub.add_parser("rest_api", help="turn rest api logging on/off")
4367 parser_rest_logging.add_argument('rest_logging', choices=['on', 'off'], help='The control option for rest logging: on, off')
4368 parser_rest_logging.set_defaults(func=restLogging)
Deepak Kodihalli02d53282018-09-18 06:53:31 -05004369
4370 #remote logging
4371 parser_remote_logging = logging_sub.add_parser("remote_logging", help="Remote logging (rsyslog) commands")
4372 parser_remote_logging.add_argument('remote_logging', choices=['view', 'disable'], help='Remote logging (rsyslog) commands')
4373 parser_remote_logging.set_defaults(func=remoteLogging)
4374
4375 #configure remote logging
4376 parser_remote_logging_config = logging_sub.add_parser("remote_logging_config", help="Configure remote logging (rsyslog)")
4377 parser_remote_logging_config.add_argument("-a", "--address", required=True, help="Set IP address of rsyslog server")
4378 parser_remote_logging_config.add_argument("-p", "--port", required=True, type=int, help="Set Port of rsyslog server")
4379 parser_remote_logging_config.set_defaults(func=remoteLoggingConfig)
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05004380
4381 #certificate management
4382 parser_cert = subparsers.add_parser("certificate", help="Certificate management")
4383 certMgmt_subproc = parser_cert.add_subparsers(title='subcommands', description='valid certificate commands', help='sub-command help', dest='command')
4384
4385 certUpdate = certMgmt_subproc.add_parser('update', help="Update the certificate")
4386 certUpdate.add_argument('type', choices=['server', 'client', 'authority'], help="certificate type to update")
4387 certUpdate.add_argument('service', choices=['https', 'ldap'], help="Service to update")
4388 certUpdate.add_argument('-f', '--fileloc', required=True, help="The absolute path to the certificate file")
4389 certUpdate.set_defaults(func=certificateUpdate)
4390
4391 certDelete = certMgmt_subproc.add_parser('delete', help="Delete the certificate")
4392 certDelete.add_argument('type', choices=['server', 'client', 'authority'], help="certificate type to delete")
4393 certDelete.add_argument('service', choices=['https', 'ldap'], help="Service to delete the certificate")
4394 certDelete.set_defaults(func=certificateDelete)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004395
Marri Devender Raodfe81ad2019-07-01 05:38:09 -05004396 certReplace = certMgmt_subproc.add_parser('replace',
4397 help="Replace the certificate")
4398 certReplace.add_argument('type', choices=['server', 'client', 'authority'],
4399 help="certificate type to replace")
4400 certReplace.add_argument('service', choices=['https', 'ldap'],
4401 help="Service to replace the certificate")
4402 certReplace.add_argument('-f', '--fileloc', required=True,
4403 help="The absolute path to the certificate file")
4404 certReplace.set_defaults(func=certificateReplace)
4405
Marri Devender Rao34646402019-07-01 05:46:03 -05004406 certDisplay = certMgmt_subproc.add_parser('display',
4407 help="Print the certificate")
4408 certDisplay.add_argument('type', choices=['server', 'client', 'authority'],
4409 help="certificate type to display")
4410 certDisplay.set_defaults(func=certificateDisplay)
4411
Marri Devender Raoa208ff82019-07-01 05:51:27 -05004412 certList = certMgmt_subproc.add_parser('list',
4413 help="Certificate list")
4414 certList.set_defaults(func=certificateList)
4415
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05004416 certGenerateCSR = certMgmt_subproc.add_parser('generatecsr', help="Generate CSR")
4417 certGenerateCSR.add_argument('type', choices=['server', 'client', 'authority'],
4418 help="Generate CSR")
4419 certGenerateCSR.add_argument('city',
4420 help="The city or locality of the organization making the request")
4421 certGenerateCSR.add_argument('commonName',
4422 help="The fully qualified domain name of the component that is being secured.")
4423 certGenerateCSR.add_argument('country',
4424 help="The country of the organization making the request")
4425 certGenerateCSR.add_argument('organization',
4426 help="The name of the organization making the request.")
4427 certGenerateCSR.add_argument('organizationUnit',
4428 help="The name of the unit or division of the organization making the request.")
4429 certGenerateCSR.add_argument('state',
4430 help="The state, province, or region of the organization making the request.")
4431 certGenerateCSR.add_argument('keyPairAlgorithm', choices=['RSA', 'EC'],
4432 help="The type of key pair for use with signing algorithms.")
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05004433 certGenerateCSR.add_argument('keyCurveId',
4434 help="The curve ID to be used with the key, if needed based on the value of the 'KeyPairAlgorithm' parameter.")
4435 certGenerateCSR.add_argument('contactPerson',
4436 help="The name of the user making the request")
4437 certGenerateCSR.add_argument('email',
4438 help="The email address of the contact within the organization")
4439 certGenerateCSR.add_argument('alternativeNames',
4440 help="Additional hostnames of the component that is being secured")
4441 certGenerateCSR.add_argument('givenname',
4442 help="The given name of the user making the request")
4443 certGenerateCSR.add_argument('surname',
4444 help="The surname of the user making the request")
4445 certGenerateCSR.add_argument('unstructuredname',
4446 help="he unstructured name of the subject")
4447 certGenerateCSR.add_argument('initials',
4448 help="The initials of the user making the request")
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05004449 certGenerateCSR.set_defaults(func=certificateGenerateCSR)
4450
Matt Spinler7d426c22018-09-24 14:42:07 -05004451 # local users
4452 parser_users = subparsers.add_parser("local_users", help="Work with local users")
4453 parser_users.add_argument('local_users', choices=['disableall','enableall', 'queryenabled'], help="Disable, enable or query local user accounts")
4454 parser_users.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
4455 parser_users.set_defaults(func=localUsers)
4456
Ratan Gupta9166cd22018-10-01 18:09:40 +05304457 #LDAP
4458 parser_ldap = subparsers.add_parser("ldap", help="LDAP controls")
4459 ldap_sub = parser_ldap.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
4460
4461 #configure and enable LDAP
4462 parser_ldap_config = ldap_sub.add_parser("enable", help="Configure and enables the LDAP")
4463 parser_ldap_config.add_argument("-a", "--uri", required=True, help="Set LDAP server URI")
4464 parser_ldap_config.add_argument("-B", "--bindDN", required=True, help="Set the bind DN of the LDAP server")
4465 parser_ldap_config.add_argument("-b", "--baseDN", required=True, help="Set the base DN of the LDAP server")
4466 parser_ldap_config.add_argument("-p", "--bindPassword", required=True, help="Set the bind password of the LDAP server")
4467 parser_ldap_config.add_argument("-S", "--scope", choices=['sub','one', 'base'],
4468 help='Specifies the search scope:subtree, one level or base object.')
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004469 parser_ldap_config.add_argument("-t", "--serverType", required=True, choices=['ActiveDirectory','OpenLDAP'],
Ratan Gupta9166cd22018-10-01 18:09:40 +05304470 help='Specifies the configured server is ActiveDirectory(AD) or OpenLdap')
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004471 parser_ldap_config.add_argument("-g","--groupAttrName", required=False, default='', help="Group Attribute Name")
4472 parser_ldap_config.add_argument("-u","--userAttrName", required=False, default='', help="User Attribute Name")
4473 parser_ldap_config.set_defaults(func=enableLDAPConfig)
Ratan Gupta9166cd22018-10-01 18:09:40 +05304474
4475 # disable LDAP
4476 parser_disable_ldap = ldap_sub.add_parser("disable", help="disables the LDAP")
4477 parser_disable_ldap.set_defaults(func=disableLDAP)
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06004478 # view-config
4479 parser_ldap_config = \
4480 ldap_sub.add_parser("view-config", help="prints out a list of all \
4481 LDAPS's configured properties")
4482 parser_ldap_config.set_defaults(func=viewLDAPConfig)
Ratan Gupta9166cd22018-10-01 18:09:40 +05304483
Ratan Guptafeee6372018-10-17 23:25:51 +05304484 #create group privilege mapping
4485 parser_ldap_mapper = ldap_sub.add_parser("privilege-mapper", help="LDAP group privilege controls")
4486 parser_ldap_mapper_sub = parser_ldap_mapper.add_subparsers(title='subcommands', description='valid subcommands',
4487 help="sub-command help", dest='command')
4488
4489 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 -05004490 parser_ldap_mapper_create.add_argument("-t", "--serverType", choices=['ActiveDirectory','OpenLDAP'],
4491 help='Specifies the configured server is ActiveDirectory(AD) or OpenLdap')
Ratan Guptafeee6372018-10-17 23:25:51 +05304492 parser_ldap_mapper_create.add_argument("-g","--groupName",required=True,help="Group Name")
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004493 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 +05304494 parser_ldap_mapper_create.set_defaults(func=createPrivilegeMapping)
4495
4496 #list group privilege mapping
4497 parser_ldap_mapper_list = parser_ldap_mapper_sub.add_parser("list",help="List privilege mapping")
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004498 parser_ldap_mapper_list.add_argument("-t", "--serverType", choices=['ActiveDirectory','OpenLDAP'],
4499 help='Specifies the configured server is ActiveDirectory(AD) or OpenLdap')
Ratan Guptafeee6372018-10-17 23:25:51 +05304500 parser_ldap_mapper_list.set_defaults(func=listPrivilegeMapping)
4501
4502 #delete group privilege mapping
4503 parser_ldap_mapper_delete = parser_ldap_mapper_sub.add_parser("delete",help="Delete privilege mapping")
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004504 parser_ldap_mapper_delete.add_argument("-t", "--serverType", choices=['ActiveDirectory','OpenLDAP'],
4505 help='Specifies the configured server is ActiveDirectory(AD) or OpenLdap')
Ratan Guptafeee6372018-10-17 23:25:51 +05304506 parser_ldap_mapper_delete.add_argument("-g","--groupName",required=True,help="Group Name")
4507 parser_ldap_mapper_delete.set_defaults(func=deletePrivilegeMapping)
4508
Sivas SRR78835272018-11-27 05:27:19 -06004509 #deleteAll group privilege mapping
4510 parser_ldap_mapper_delete = parser_ldap_mapper_sub.add_parser("purge",help="Delete All privilege mapping")
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004511 parser_ldap_mapper_delete.add_argument("-t", "--serverType", choices=['ActiveDirectory','OpenLDAP'],
4512 help='Specifies the configured server is ActiveDirectory(AD) or OpenLdap')
Sivas SRR78835272018-11-27 05:27:19 -06004513 parser_ldap_mapper_delete.set_defaults(func=deleteAllPrivilegeMapping)
4514
Marri Devender Rao2c2a5162018-11-05 08:57:11 -06004515 # set local user password
4516 parser_set_password = subparsers.add_parser("set_password",
4517 help="Set password of local user")
4518 parser_set_password.add_argument( "-p", "--password", required=True,
4519 help="Password of local user")
4520 parser_set_password.set_defaults(func=setPassword)
4521
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004522 # network
4523 parser_nw = subparsers.add_parser("network", help="network controls")
4524 nw_sub = parser_nw.add_subparsers(title='subcommands',
4525 description='valid subcommands',
4526 help="sub-command help",
4527 dest='command')
4528
4529 # enable DHCP
4530 parser_enable_dhcp = nw_sub.add_parser("enableDHCP",
4531 help="enables the DHCP on given "
4532 "Interface")
4533 parser_enable_dhcp.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004534 help="Name of the ethernet interface(it can"
4535 "be obtained by the "
4536 "command:network view-config)"
4537 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004538 parser_enable_dhcp.set_defaults(func=enableDHCP)
4539
4540 # disable DHCP
4541 parser_disable_dhcp = nw_sub.add_parser("disableDHCP",
4542 help="disables the DHCP on given "
4543 "Interface")
4544 parser_disable_dhcp.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004545 help="Name of the ethernet interface(it can"
4546 "be obtained by the "
4547 "command:network view-config)"
4548 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004549 parser_disable_dhcp.set_defaults(func=disableDHCP)
4550
4551 # get HostName
4552 parser_gethostname = nw_sub.add_parser("getHostName",
4553 help="prints out HostName")
4554 parser_gethostname.set_defaults(func=getHostname)
4555
4556 # set HostName
4557 parser_sethostname = nw_sub.add_parser("setHostName", help="sets HostName")
4558 parser_sethostname.add_argument("-H", "--HostName", required=True,
4559 help="A HostName for the BMC")
4560 parser_sethostname.set_defaults(func=setHostname)
4561
4562 # get domainname
4563 parser_getdomainname = nw_sub.add_parser("getDomainName",
4564 help="prints out DomainName of "
4565 "given Interface")
4566 parser_getdomainname.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004567 help="Name of the ethernet interface(it "
4568 "can be obtained by the "
4569 "command:network view-config)"
4570 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004571 parser_getdomainname.set_defaults(func=getDomainName)
4572
4573 # set domainname
4574 parser_setdomainname = nw_sub.add_parser("setDomainName",
4575 help="sets DomainName of given "
4576 "Interface")
4577 parser_setdomainname.add_argument("-D", "--DomainName", required=True,
4578 help="Ex: DomainName=Domain1,Domain2,...")
4579 parser_setdomainname.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004580 help="Name of the ethernet interface(it "
4581 "can be obtained by the "
4582 "command:network view-config)"
4583 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004584 parser_setdomainname.set_defaults(func=setDomainName)
4585
4586 # get MACAddress
4587 parser_getmacaddress = nw_sub.add_parser("getMACAddress",
4588 help="prints out MACAddress the "
4589 "given Interface")
4590 parser_getmacaddress.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004591 help="Name of the ethernet interface(it "
4592 "can be obtained by the "
4593 "command:network view-config)"
4594 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004595 parser_getmacaddress.set_defaults(func=getMACAddress)
4596
4597 # set MACAddress
4598 parser_setmacaddress = nw_sub.add_parser("setMACAddress",
4599 help="sets MACAddress")
4600 parser_setmacaddress.add_argument("-MA", "--MACAddress", required=True,
4601 help="A MACAddress for the given "
4602 "Interface")
4603 parser_setmacaddress.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004604 help="Name of the ethernet interface(it can"
4605 "be obtained by the "
4606 "command:network view-config)"
4607 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004608 parser_setmacaddress.set_defaults(func=setMACAddress)
4609
4610 # get DefaultGW
4611 parser_getdefaultgw = nw_sub.add_parser("getDefaultGW",
4612 help="prints out DefaultGateway "
4613 "the BMC")
4614 parser_getdefaultgw.set_defaults(func=getDefaultGateway)
4615
4616 # set DefaultGW
4617 parser_setdefaultgw = nw_sub.add_parser("setDefaultGW",
4618 help="sets DefaultGW")
4619 parser_setdefaultgw.add_argument("-GW", "--DefaultGW", required=True,
4620 help="A DefaultGateway for the BMC")
4621 parser_setdefaultgw.set_defaults(func=setDefaultGateway)
4622
4623 # view network Config
4624 parser_ldap_config = nw_sub.add_parser("view-config", help="prints out a "
4625 "list of all network's configured "
4626 "properties")
4627 parser_ldap_config.set_defaults(func=viewNWConfig)
4628
4629 # get DNS
4630 parser_getDNS = nw_sub.add_parser("getDNS",
4631 help="prints out DNS servers on the "
4632 "given interface")
4633 parser_getDNS.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004634 help="Name of the ethernet interface(it can"
4635 "be obtained by the "
4636 "command:network view-config)"
4637 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004638 parser_getDNS.set_defaults(func=getDNS)
4639
4640 # set DNS
4641 parser_setDNS = nw_sub.add_parser("setDNS",
4642 help="sets DNS servers on the given "
4643 "interface")
4644 parser_setDNS.add_argument("-d", "--DNSServers", required=True,
4645 help="Ex: DNSSERVERS=DNS1,DNS2,...")
4646 parser_setDNS.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004647 help="Name of the ethernet interface(it can"
4648 "be obtained by the "
4649 "command:network view-config)"
4650 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004651 parser_setDNS.set_defaults(func=setDNS)
4652
4653 # get NTP
4654 parser_getNTP = nw_sub.add_parser("getNTP",
4655 help="prints out NTP servers on the "
4656 "given interface")
4657 parser_getNTP.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004658 help="Name of the ethernet interface(it can"
4659 "be obtained by the "
4660 "command:network view-config)"
4661 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004662 parser_getNTP.set_defaults(func=getNTP)
4663
4664 # set NTP
4665 parser_setNTP = nw_sub.add_parser("setNTP",
4666 help="sets NTP servers on the given "
4667 "interface")
4668 parser_setNTP.add_argument("-N", "--NTPServers", required=True,
4669 help="Ex: NTPSERVERS=NTP1,NTP2,...")
4670 parser_setNTP.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004671 help="Name of the ethernet interface(it can"
4672 "be obtained by the "
4673 "command:network view-config)"
4674 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004675 parser_setNTP.set_defaults(func=setNTP)
4676
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004677 # configure IP
4678 parser_ip_config = nw_sub.add_parser("addIP", help="Sets IP address to"
4679 "given interface")
4680 parser_ip_config.add_argument("-a", "--address", required=True,
4681 help="IP address of given interface")
4682 parser_ip_config.add_argument("-gw", "--gateway", required=False, default='',
4683 help="The gateway for given interface")
4684 parser_ip_config.add_argument("-l", "--prefixLength", required=True,
4685 help="The prefixLength of IP address")
Sunitha Harish0baf6372019-07-31 03:59:03 -05004686 parser_ip_config.add_argument("-p", "--type", required=True,
4687 choices=['ipv4', 'ipv6'],
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004688 help="The protocol type of the given"
4689 "IP address")
4690 parser_ip_config.add_argument("-I", "--Interface", required=True,
4691 help="Name of the ethernet interface(it can"
4692 "be obtained by the "
4693 "command:network view-config)"
4694 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
4695 parser_ip_config.set_defaults(func=addIP)
4696
4697 # getIP
4698 parser_getIP = nw_sub.add_parser("getIP", help="prints out IP address"
4699 "of given interface")
4700 parser_getIP.add_argument("-I", "--Interface", required=True,
4701 help="Name of the ethernet interface(it can"
4702 "be obtained by the command:network view-config)"
4703 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
4704 parser_getIP.set_defaults(func=getIP)
4705
4706 # rmIP
4707 parser_rmIP = nw_sub.add_parser("rmIP", help="deletes IP address"
4708 "of given interface")
4709 parser_rmIP.add_argument("-a", "--address", required=True,
4710 help="IP address to remove form given Interface")
4711 parser_rmIP.add_argument("-I", "--Interface", required=True,
4712 help="Name of the ethernet interface(it can"
4713 "be obtained by the command:network view-config)"
4714 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
4715 parser_rmIP.set_defaults(func=deleteIP)
4716
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004717 # add VLAN
4718 parser_create_vlan = nw_sub.add_parser("addVLAN", help="enables VLAN "
4719 "on given interface with given "
4720 "VLAN Identifier")
4721 parser_create_vlan.add_argument("-I", "--Interface", required=True,
4722 choices=['eth0', 'eth1'],
4723 help="Name of the ethernet interface")
4724 parser_create_vlan.add_argument("-n", "--Identifier", required=True,
4725 help="VLAN Identifier")
4726 parser_create_vlan.set_defaults(func=addVLAN)
4727
4728 # delete VLAN
4729 parser_delete_vlan = nw_sub.add_parser("deleteVLAN", help="disables VLAN "
4730 "on given interface with given "
4731 "VLAN Identifier")
4732 parser_delete_vlan.add_argument("-I", "--Interface", required=True,
4733 help="Name of the ethernet interface(it can"
4734 "be obtained by the "
4735 "command:network view-config)"
4736 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
4737 parser_delete_vlan.set_defaults(func=deleteVLAN)
4738
4739 # viewDHCPConfig
4740 parser_viewDHCPConfig = nw_sub.add_parser("viewDHCPConfig",
4741 help="Shows DHCP configured "
4742 "Properties")
4743 parser_viewDHCPConfig.set_defaults(func=viewDHCPConfig)
4744
4745 # configureDHCP
4746 parser_configDHCP = nw_sub.add_parser("configureDHCP",
4747 help="Configures/updates DHCP "
4748 "Properties")
4749 parser_configDHCP.add_argument("-d", "--DNSEnabled", type=str2bool,
4750 required=True, help="Sets DNSEnabled property")
4751 parser_configDHCP.add_argument("-n", "--HostNameEnabled", type=str2bool,
4752 required=True,
4753 help="Sets HostNameEnabled property")
4754 parser_configDHCP.add_argument("-t", "--NTPEnabled", type=str2bool,
4755 required=True,
4756 help="Sets NTPEnabled property")
4757 parser_configDHCP.add_argument("-s", "--SendHostNameEnabled", type=str2bool,
4758 required=True,
4759 help="Sets SendHostNameEnabled property")
4760 parser_configDHCP.set_defaults(func=configureDHCP)
4761
4762 # network factory reset
4763 parser_nw_reset = nw_sub.add_parser("nwReset",
4764 help="Resets networks setting to "
4765 "factory defaults. "
4766 "note:Reset settings will be applied "
4767 "after BMC reboot")
4768 parser_nw_reset.set_defaults(func=nwReset)
4769
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004770 return parser
4771
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004772def main(argv=None):
Justin Thalere412dc22018-01-12 16:28:24 -06004773 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004774 main function for running the command line utility as a sub application
4775 """
4776 global toolVersion
Matthew Barth0939e822019-09-27 15:47:50 -05004777 toolVersion = "1.17"
Sunitha Harishc99faba2019-07-19 06:55:22 -05004778 global isRedfishSupport
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004779
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004780 parser = createCommandParser()
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004781 args = parser.parse_args(argv)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004782
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004783 totTimeStart = int(round(time.time()*1000))
4784
4785 if(sys.version_info < (3,0)):
4786 urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
4787 if sys.version_info >= (3,0):
4788 requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)
Justin Thalere412dc22018-01-12 16:28:24 -06004789 if (args.version):
Justin Thaler22b1bb52018-03-15 13:31:32 -05004790 print("Version: "+ toolVersion)
Justin Thalere412dc22018-01-12 16:28:24 -06004791 sys.exit(0)
4792 if (hasattr(args, 'fileloc') and args.fileloc is not None and 'print' in args.command):
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004793 mysess = None
Justin Thalere412dc22018-01-12 16:28:24 -06004794 print(selPrint('N/A', args, mysess))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004795 else:
Justin Thalere412dc22018-01-12 16:28:24 -06004796 if(hasattr(args, 'host') and hasattr(args,'user')):
4797 if (args.askpw):
4798 pw = getpass.getpass()
4799 elif(args.PW is not None):
4800 pw = args.PW
Joseph Reynoldsa2d54c52019-06-11 22:02:57 -05004801 elif(args.PWenvvar):
4802 pw = os.environ['OPENBMCTOOL_PASSWORD']
Justin Thalere412dc22018-01-12 16:28:24 -06004803 else:
4804 print("You must specify a password")
4805 sys.exit()
4806 logintimeStart = int(round(time.time()*1000))
4807 mysess = login(args.host, args.user, pw, args.json)
Sunitha Harish336cda22019-07-23 02:02:52 -05004808 if(mysess == None):
4809 print("Login Failed!")
4810 sys.exit()
Justin Thalera9415b42018-05-25 19:40:13 -05004811 if(sys.version_info < (3,0)):
4812 if isinstance(mysess, basestring):
4813 print(mysess)
4814 sys.exit(1)
4815 elif sys.version_info >= (3,0):
4816 if isinstance(mysess, str):
4817 print(mysess)
4818 sys.exit(1)
Justin Thalere412dc22018-01-12 16:28:24 -06004819 logintimeStop = int(round(time.time()*1000))
Sunitha Harishc99faba2019-07-19 06:55:22 -05004820 isRedfishSupport = redfishSupportPresent(args.host,mysess)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004821 commandTimeStart = int(round(time.time()*1000))
Justin Thalere412dc22018-01-12 16:28:24 -06004822 output = args.func(args.host, args, mysess)
4823 commandTimeStop = int(round(time.time()*1000))
Justin Thaler761484a2019-03-26 19:20:23 -05004824 if isinstance(output, dict):
4825 print(json.dumps(output, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False))
4826 else:
4827 print(output)
Justin Thalere412dc22018-01-12 16:28:24 -06004828 if (mysess is not None):
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004829 logout(args.host, args.user, pw, mysess, args.json)
4830 if(args.procTime):
Justin Thalere412dc22018-01-12 16:28:24 -06004831 print("Total time: " + str(int(round(time.time()*1000))- totTimeStart))
4832 print("loginTime: " + str(logintimeStop - logintimeStart))
4833 print("command Time: " + str(commandTimeStop - commandTimeStart))
4834 else:
Joseph Reynoldsa2d54c52019-06-11 22:02:57 -05004835 print("usage:\n"
4836 " OPENBMCTOOL_PASSWORD=secret # if using -E\n"
4837 " openbmctool.py [-h] -H HOST -U USER {-A | -P PW | -E} [-j]\n" +
Justin Thalere412dc22018-01-12 16:28:24 -06004838 "\t[-t POLICYTABLELOC] [-V]\n" +
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05004839 "\t{fru,sensors,sel,chassis,collect_service_data, \
4840 health_check,dump,bmc,mc,gardclear,firmware,logging}\n" +
Justin Thalere412dc22018-01-12 16:28:24 -06004841 "\t...\n" +
4842 "openbmctool.py: error: the following arguments are required: -H/--host, -U/--user")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004843 sys.exit()
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004844
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004845if __name__ == '__main__':
Justin Thalere412dc22018-01-12 16:28:24 -06004846 """
4847 main function when called from the command line
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004848
4849 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004850 import sys
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004851
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004852 isTTY = sys.stdout.isatty()
4853 assert sys.version_info >= (2,7)
4854 main()