blob: 34ed5b5874d29d34e184feb9aeaa347baadc9211 [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("/")
533 senDict['sensorName'] = keyparts[-1]
534 senDict['type'] = keyparts[-2]
Justin Thalere412dc22018-01-12 16:28:24 -0600535 try:
536 senDict['units'] = sensors[key]['Unit'].split('.')[-1]
537 except KeyError:
Justin Thaler22b1bb52018-03-15 13:31:32 -0500538 senDict['units'] = "N/A"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600539 if('Scale' in sensors[key]):
540 scale = 10 ** sensors[key]['Scale']
541 else:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600542 scale = 1
Justin Thaler22b1bb52018-03-15 13:31:32 -0500543 try:
544 senDict['value'] = str(sensors[key]['Value'] * scale)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600545 except KeyError:
Justin Thaler22b1bb52018-03-15 13:31:32 -0500546 if 'value' in sensors[key]:
547 senDict['value'] = sensors[key]['value']
548 else:
549 senDict['value'] = "N/A"
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600550 if 'Target' in sensors[key]:
551 senDict['target'] = str(sensors[key]['Target'])
552 else:
553 senDict['target'] = 'N/A'
554 output[senDict['sensorName']] = senDict
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600555
Justin Thaler3a5771b2019-01-23 14:31:52 -0600556 occstatus = occres.json()["data"]
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600557 if '/org/open_power/control/occ0' in occstatus:
558 occ0 = occstatus["/org/open_power/control/occ0"]['OccActive']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600559 if occ0 == 1:
560 occ0 = 'Active'
561 else:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600562 occ0 = 'Inactive'
563 output['OCC0'] = {'sensorName':'OCC0', 'type': 'Discrete', 'units': 'N/A', 'value': occ0, 'target': 'Active'}
564 occ1 = occstatus["/org/open_power/control/occ1"]['OccActive']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600565 if occ1 == 1:
566 occ1 = 'Active'
567 else:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600568 occ1 = 'Inactive'
569 output['OCC1'] = {'sensorName':'OCC1', 'type': 'Discrete', 'units': 'N/A', 'value': occ0, 'target': 'Active'}
570 else:
571 output['OCC0'] = {'sensorName':'OCC0', 'type': 'Discrete', 'units': 'N/A', 'value': 'Inactive', 'target': 'Inactive'}
572 output['OCC1'] = {'sensorName':'OCC1', 'type': 'Discrete', 'units': 'N/A', 'value': 'Inactive', 'target': 'Inactive'}
573 keylist = ['sensorName', 'type', 'units', 'value', 'target']
Justin Thalere412dc22018-01-12 16:28:24 -0600574
575 return tableDisplay(keylist, colNames, output)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600576 else:
577 return res.text + occres.text
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600578
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600579def sel(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -0600580 """
581 prints out the bmc alerts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600582
Justin Thalere412dc22018-01-12 16:28:24 -0600583 @param host: string, the hostname or IP address of the bmc
584 @param args: contains additional arguments used by the sel sub command
585 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600586 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
587 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600588
589 url="https://"+host+"/xyz/openbmc_project/logging/entry/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600590 try:
Justin Thaler27197622019-01-23 14:42:11 -0600591 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600592 except(requests.exceptions.Timeout):
593 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600594 return res.text
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600595
596
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600597def parseESEL(args, eselRAW):
Justin Thalere412dc22018-01-12 16:28:24 -0600598 """
599 parses the esel data and gets predetermined search terms
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600600
Justin Thalere412dc22018-01-12 16:28:24 -0600601 @param eselRAW: string, the raw esel string from the bmc
602 @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 -0600603 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600604 eselParts = {}
605 esel_bin = binascii.unhexlify(''.join(eselRAW.split()[16:]))
606 #search terms contains the search term as the key and the return dictionary key as it's value
607 searchTerms = { 'Signature Description':'signatureDescription', 'devdesc':'devdesc',
Justin Thaler22b1bb52018-03-15 13:31:32 -0500608 'Callout type': 'calloutType', 'Procedure':'procedure', 'Sensor Type': 'sensorType'}
Justin Thaler24d4efa2018-11-08 22:48:10 -0600609 uniqueID = str(uuid.uuid4())
610 eselBinPath = tempfile.gettempdir() + os.sep + uniqueID + 'esel.bin'
Justin Thalercf1deae2018-05-25 19:35:21 -0500611 with open(eselBinPath, 'wb') as f:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600612 f.write(esel_bin)
613 errlPath = ""
614 #use the right errl file for the machine architecture
615 arch = platform.machine()
616 if(arch =='x86_64' or arch =='AMD64'):
617 if os.path.exists('/opt/ibm/ras/bin/x86_64/errl'):
618 errlPath = '/opt/ibm/ras/bin/x86_64/errl'
619 elif os.path.exists('errl/x86_64/errl'):
620 errlPath = 'errl/x86_64/errl'
621 else:
622 errlPath = 'x86_64/errl'
623 elif (platform.machine()=='ppc64le'):
624 if os.path.exists('/opt/ibm/ras/bin/ppc64le/errl'):
625 errlPath = '/opt/ibm/ras/bin/ppc64le/errl'
626 elif os.path.exists('errl/ppc64le/errl'):
627 errlPath = 'errl/ppc64le/errl'
628 else:
629 errlPath = 'ppc64le/errl'
630 else:
631 print("machine architecture not supported for parsing eSELs")
632 return eselParts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600633
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600634 if(os.path.exists(errlPath)):
Justin Thalercf1deae2018-05-25 19:35:21 -0500635 output= subprocess.check_output([errlPath, '-d', '--file='+eselBinPath]).decode('utf-8')
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600636# output = proc.communicate()[0]
637 lines = output.split('\n')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600638
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600639 if(hasattr(args, 'fullEsel')):
640 return output
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600641
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600642 for i in range(0, len(lines)):
643 lineParts = lines[i].split(':')
644 if(len(lineParts)>1): #ignore multi lines, output formatting lines, and other information
645 for term in searchTerms:
646 if(term in lineParts[0]):
647 temp = lines[i][lines[i].find(':')+1:].strip()[:-1].strip()
648 if lines[i+1].find(':') != -1:
649 if (len(lines[i+1].split(':')[0][1:].strip())==0):
650 while(len(lines[i][:lines[i].find(':')].strip())>2):
Justin Thaler43030422018-11-08 22:50:21 -0600651 #has multiple lines, process and update line counter
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600652 if((i+1) <= len(lines)):
653 i+=1
654 else:
655 i=i-1
656 break
Justin Thaler43030422018-11-08 22:50:21 -0600657 #Append the content from the next line removing the pretty display characters
658 #Finds the first colon then starts 2 characters after, then removes all whitespace
659 temp = temp + lines[i][lines[i].find(':')+2:].strip()[:-1].strip()[:-1].strip()
Justin Thaler22b1bb52018-03-15 13:31:32 -0500660 if(searchTerms[term] in eselParts):
661 eselParts[searchTerms[term]] = eselParts[searchTerms[term]] + ", " + temp
662 else:
663 eselParts[searchTerms[term]] = temp
Justin Thalercf1deae2018-05-25 19:35:21 -0500664 os.remove(eselBinPath)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600665 else:
666 print("errl file cannot be found")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600667
668 return eselParts
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600669
Justin Thalere412dc22018-01-12 16:28:24 -0600670
Matt Spinler02d0dff2018-08-29 13:19:25 -0500671def getESELSeverity(esel):
672 """
673 Finds the severity type in an eSEL from the User Header section.
674 @param esel - the eSEL data
675 @return severity - e.g. 'Critical'
676 """
677
678 # everything but 1 and 2 are Critical
679 # '1': 'recovered',
680 # '2': 'predictive',
681 # '4': 'unrecoverable',
682 # '5': 'critical',
683 # '6': 'diagnostic',
684 # '7': 'symptom'
685 severities = {
686 '1': 'Informational',
687 '2': 'Warning'
688 }
689
690 try:
691 headerPosition = esel.index('55 48') # 'UH'
692 # The severity is the last byte in the 8 byte section (a byte is ' bb')
693 severity = esel[headerPosition:headerPosition+32].split(' ')[-1]
694 type = severity[0]
695 except ValueError:
696 print("Could not find severity value in UH section in eSEL")
697 type = 'x';
698
699 return severities.get(type, 'Critical')
700
701
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600702def sortSELs(events):
Justin Thalere412dc22018-01-12 16:28:24 -0600703 """
704 sorts the sels by timestamp, then log entry number
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600705
Justin Thalere412dc22018-01-12 16:28:24 -0600706 @param events: Dictionary containing events
707 @return: list containing a list of the ordered log entries, and dictionary of keys
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600708 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600709 logNumList = []
710 timestampList = []
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600711 eventKeyDict = {}
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600712 eventsWithTimestamp = {}
713 logNum2events = {}
714 for key in events:
715 if key == 'numAlerts': continue
716 if 'callout' in key: continue
717 timestamp = (events[key]['timestamp'])
718 if timestamp not in timestampList:
719 eventsWithTimestamp[timestamp] = [events[key]['logNum']]
720 else:
721 eventsWithTimestamp[timestamp].append(events[key]['logNum'])
722 #map logNumbers to the event dictionary keys
723 eventKeyDict[str(events[key]['logNum'])] = key
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600724
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600725 timestampList = list(eventsWithTimestamp.keys())
726 timestampList.sort()
727 for ts in timestampList:
728 if len(eventsWithTimestamp[ts]) > 1:
729 tmplist = eventsWithTimestamp[ts]
730 tmplist.sort()
731 logNumList = logNumList + tmplist
732 else:
733 logNumList = logNumList + eventsWithTimestamp[ts]
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600734
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600735 return [logNumList, eventKeyDict]
736
Justin Thalere412dc22018-01-12 16:28:24 -0600737
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600738def parseAlerts(policyTable, selEntries, args):
Justin Thalere412dc22018-01-12 16:28:24 -0600739 """
740 parses alerts in the IBM CER format, using an IBM policy Table
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600741
Justin Thalere412dc22018-01-12 16:28:24 -0600742 @param policyTable: dictionary, the policy table entries
743 @param selEntries: dictionary, the alerts retrieved from the bmc
744 @return: A dictionary of the parsed entries, in chronological order
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600745 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600746 eventDict = {}
747 eventNum =""
748 count = 0
749 esel = ""
750 eselParts = {}
751 i2cdevice= ""
Matt Spinler02d0dff2018-08-29 13:19:25 -0500752 eselSeverity = None
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600753
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600754 'prepare and sort the event entries'
755 for key in selEntries:
756 if 'callout' not in key:
757 selEntries[key]['logNum'] = key.split('/')[-1]
758 selEntries[key]['timestamp'] = selEntries[key]['Timestamp']
759 sortedEntries = sortSELs(selEntries)
760 logNumList = sortedEntries[0]
761 eventKeyDict = sortedEntries[1]
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600762
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600763 for logNum in logNumList:
764 key = eventKeyDict[logNum]
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600765 hasEsel=False
766 i2creadFail = False
767 if 'callout' in key:
768 continue
769 else:
770 messageID = str(selEntries[key]['Message'])
771 addDataPiece = selEntries[key]['AdditionalData']
772 calloutIndex = 0
773 calloutFound = False
774 for i in range(len(addDataPiece)):
775 if("CALLOUT_INVENTORY_PATH" in addDataPiece[i]):
776 calloutIndex = i
777 calloutFound = True
778 fruCallout = str(addDataPiece[calloutIndex]).split('=')[1]
779 if("CALLOUT_DEVICE_PATH" in addDataPiece[i]):
780 i2creadFail = True
Matt Spinlerd178a472018-08-31 09:48:52 -0500781
782 fruCallout = str(addDataPiece[calloutIndex]).split('=')[1]
783
784 # Fall back to "I2C"/"FSI" if dev path isn't in policy table
785 if (messageID + '||' + fruCallout) not in policyTable:
786 i2cdevice = str(addDataPiece[i]).strip().split('=')[1]
787 i2cdevice = '/'.join(i2cdevice.split('/')[-4:])
788 if 'fsi' in str(addDataPiece[calloutIndex]).split('=')[1]:
789 fruCallout = 'FSI'
790 else:
791 fruCallout = 'I2C'
Justin Thalere34c43a2018-05-25 19:37:55 -0500792 calloutFound = True
793 if("CALLOUT_GPIO_NUM" in addDataPiece[i]):
794 if not calloutFound:
795 fruCallout = 'GPIO'
796 calloutFound = True
797 if("CALLOUT_IIC_BUS" in addDataPiece[i]):
798 if not calloutFound:
799 fruCallout = "I2C"
800 calloutFound = True
801 if("CALLOUT_IPMI_SENSOR_NUM" in addDataPiece[i]):
802 if not calloutFound:
803 fruCallout = "IPMI"
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600804 calloutFound = True
805 if("ESEL" in addDataPiece[i]):
806 esel = str(addDataPiece[i]).strip().split('=')[1]
Matt Spinler02d0dff2018-08-29 13:19:25 -0500807 eselSeverity = getESELSeverity(esel)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600808 if args.devdebug:
809 eselParts = parseESEL(args, esel)
810 hasEsel=True
811 if("GPU" in addDataPiece[i]):
812 fruCallout = '/xyz/openbmc_project/inventory/system/chassis/motherboard/gpu' + str(addDataPiece[i]).strip()[-1]
813 calloutFound = True
814 if("PROCEDURE" in addDataPiece[i]):
815 fruCallout = str(hex(int(str(addDataPiece[i]).split('=')[1])))[2:]
816 calloutFound = True
Justin Thalere412dc22018-01-12 16:28:24 -0600817 if("RAIL_NAME" in addDataPiece[i]):
818 calloutFound=True
819 fruCallout = str(addDataPiece[i]).split('=')[1].strip()
820 if("INPUT_NAME" in addDataPiece[i]):
821 calloutFound=True
822 fruCallout = str(addDataPiece[i]).split('=')[1].strip()
823 if("SENSOR_TYPE" in addDataPiece[i]):
824 calloutFound=True
825 fruCallout = str(addDataPiece[i]).split('=')[1].strip()
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600826
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600827 if(calloutFound):
Justin Thaler22b1bb52018-03-15 13:31:32 -0500828 if fruCallout != "":
829 policyKey = messageID +"||" + fruCallout
Matt Spinler02d0dff2018-08-29 13:19:25 -0500830
831 # Also use the severity for hostboot errors
832 if eselSeverity and messageID == 'org.open_power.Host.Error.Event':
833 policyKey += '||' + eselSeverity
834
835 # if not in the table, fall back to the original key
836 if policyKey not in policyTable:
837 policyKey = policyKey.replace('||'+eselSeverity, '')
838
Justin Thalere34c43a2018-05-25 19:37:55 -0500839 if policyKey not in policyTable:
840 policyKey = messageID
Justin Thaler22b1bb52018-03-15 13:31:32 -0500841 else:
842 policyKey = messageID
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600843 else:
844 policyKey = messageID
845 event = {}
846 eventNum = str(count)
847 if policyKey in policyTable:
848 for pkey in policyTable[policyKey]:
849 if(type(policyTable[policyKey][pkey])== bool):
850 event[pkey] = boolToString(policyTable[policyKey][pkey])
851 else:
852 if (i2creadFail and pkey == 'Message'):
853 event[pkey] = policyTable[policyKey][pkey] + ' ' +i2cdevice
854 else:
855 event[pkey] = policyTable[policyKey][pkey]
856 event['timestamp'] = selEntries[key]['Timestamp']
857 event['resolved'] = bool(selEntries[key]['Resolved'])
858 if(hasEsel):
859 if args.devdebug:
860 event['eselParts'] = eselParts
861 event['raweSEL'] = esel
862 event['logNum'] = key.split('/')[-1]
863 eventDict['event' + eventNum] = event
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600864
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600865 else:
866 severity = str(selEntries[key]['Severity']).split('.')[-1]
867 if severity == 'Error':
868 severity = 'Critical'
869 eventDict['event'+eventNum] = {}
870 eventDict['event' + eventNum]['error'] = "error: Not found in policy table: " + policyKey
871 eventDict['event' + eventNum]['timestamp'] = selEntries[key]['Timestamp']
872 eventDict['event' + eventNum]['Severity'] = severity
873 if(hasEsel):
874 if args.devdebug:
875 eventDict['event' +eventNum]['eselParts'] = eselParts
876 eventDict['event' +eventNum]['raweSEL'] = esel
877 eventDict['event' +eventNum]['logNum'] = key.split('/')[-1]
878 eventDict['event' +eventNum]['resolved'] = bool(selEntries[key]['Resolved'])
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600879 count += 1
880 return eventDict
881
882
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600883def selDisplay(events, args):
Justin Thalere412dc22018-01-12 16:28:24 -0600884 """
885 displays alerts in human readable format
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600886
Justin Thalere412dc22018-01-12 16:28:24 -0600887 @param events: Dictionary containing events
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600888 @return:
889 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600890 activeAlerts = []
891 historyAlerts = []
892 sortedEntries = sortSELs(events)
893 logNumList = sortedEntries[0]
894 eventKeyDict = sortedEntries[1]
895 keylist = ['Entry', 'ID', 'Timestamp', 'Serviceable', 'Severity','Message']
896 if(args.devdebug):
897 colNames = ['Entry', 'ID', 'Timestamp', 'Serviceable', 'Severity','Message', 'eSEL contents']
898 keylist.append('eSEL')
899 else:
900 colNames = ['Entry', 'ID', 'Timestamp', 'Serviceable', 'Severity', 'Message']
901 for log in logNumList:
902 selDict = {}
903 alert = events[eventKeyDict[str(log)]]
904 if('error' in alert):
905 selDict['Entry'] = alert['logNum']
906 selDict['ID'] = 'Unknown'
907 selDict['Timestamp'] = datetime.datetime.fromtimestamp(int(alert['timestamp']/1000)).strftime("%Y-%m-%d %H:%M:%S")
908 msg = alert['error']
909 polMsg = msg.split("policy table:")[0]
910 msg = msg.split("policy table:")[1]
911 msgPieces = msg.split("||")
912 err = msgPieces[0]
913 if(err.find("org.open_power.")!=-1):
914 err = err.split("org.open_power.")[1]
915 elif(err.find("xyz.openbmc_project.")!=-1):
916 err = err.split("xyz.openbmc_project.")[1]
917 else:
918 err = msgPieces[0]
919 callout = ""
920 if len(msgPieces) >1:
921 callout = msgPieces[1]
922 if(callout.find("/org/open_power/")!=-1):
923 callout = callout.split("/org/open_power/")[1]
924 elif(callout.find("/xyz/openbmc_project/")!=-1):
925 callout = callout.split("/xyz/openbmc_project/")[1]
926 else:
927 callout = msgPieces[1]
928 selDict['Message'] = polMsg +"policy table: "+ err + "||" + callout
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600929 selDict['Serviceable'] = 'Unknown'
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600930 selDict['Severity'] = alert['Severity']
931 else:
932 selDict['Entry'] = alert['logNum']
933 selDict['ID'] = alert['CommonEventID']
934 selDict['Timestamp'] = datetime.datetime.fromtimestamp(int(alert['timestamp']/1000)).strftime("%Y-%m-%d %H:%M:%S")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600935 selDict['Message'] = alert['Message']
936 selDict['Serviceable'] = alert['Serviceable']
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600937 selDict['Severity'] = alert['Severity']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600938
939
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600940 eselOrder = ['refCode','signatureDescription', 'eselType', 'devdesc', 'calloutType', 'procedure']
941 if ('eselParts' in alert and args.devdebug):
942 eselOutput = ""
943 for item in eselOrder:
944 if item in alert['eselParts']:
945 eselOutput = eselOutput + item + ": " + alert['eselParts'][item] + " | "
946 selDict['eSEL'] = eselOutput
947 else:
948 if args.devdebug:
949 selDict['eSEL'] = "None"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600950
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600951 if not alert['resolved']:
952 activeAlerts.append(selDict)
953 else:
954 historyAlerts.append(selDict)
955 mergedOutput = activeAlerts + historyAlerts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600956 colWidth = setColWidth(keylist, len(colNames), dict(enumerate(mergedOutput)), colNames)
957
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600958 output = ""
959 if(len(activeAlerts)>0):
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600960 row = ""
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600961 output +="----Active Alerts----\n"
962 for i in range(0, len(colNames)):
963 if i!=0: row =row + "| "
964 row = row + colNames[i].ljust(colWidth[i])
965 output += row + "\n"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600966
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600967 for i in range(0,len(activeAlerts)):
968 row = ""
969 for j in range(len(activeAlerts[i])):
970 if (j != 0): row = row + "| "
971 row = row + activeAlerts[i][keylist[j]].ljust(colWidth[j])
972 output += row + "\n"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600973
974 if(len(historyAlerts)>0):
975 row = ""
976 output+= "----Historical Alerts----\n"
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600977 for i in range(len(colNames)):
978 if i!=0: row =row + "| "
979 row = row + colNames[i].ljust(colWidth[i])
980 output += row + "\n"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600981
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600982 for i in range(0, len(historyAlerts)):
983 row = ""
984 for j in range(len(historyAlerts[i])):
985 if (j != 0): row = row + "| "
986 row = row + historyAlerts[i][keylist[j]].ljust(colWidth[j])
987 output += row + "\n"
988# print(events[eventKeyDict[str(log)]])
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600989 return output
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600990
Justin Thalere412dc22018-01-12 16:28:24 -0600991
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600992def selPrint(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -0600993 """
994 prints out all bmc alerts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600995
Justin Thalere412dc22018-01-12 16:28:24 -0600996 @param host: string, the hostname or IP address of the bmc
997 @param args: contains additional arguments used by the fru sub command
998 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600999 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1000 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001001 if(args.policyTableLoc is None):
1002 if os.path.exists('policyTable.json'):
1003 ptableLoc = "policyTable.json"
1004 elif os.path.exists('/opt/ibm/ras/lib/policyTable.json'):
1005 ptableLoc = '/opt/ibm/ras/lib/policyTable.json'
1006 else:
1007 ptableLoc = 'lib/policyTable.json'
1008 else:
1009 ptableLoc = args.policyTableLoc
1010 policyTable = loadPolicyTable(ptableLoc)
1011 rawselEntries = ""
1012 if(hasattr(args, 'fileloc') and args.fileloc is not None):
1013 if os.path.exists(args.fileloc):
1014 with open(args.fileloc, 'r') as selFile:
1015 selLines = selFile.readlines()
1016 rawselEntries = ''.join(selLines)
1017 else:
1018 print("Error: File not found")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001019 sys.exit(1)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001020 else:
1021 rawselEntries = sel(host, args, session)
1022 loadFailed = False
1023 try:
1024 selEntries = json.loads(rawselEntries)
1025 except ValueError:
1026 loadFailed = True
1027 if loadFailed:
1028 cleanSels = json.dumps(rawselEntries).replace('\\n', '')
1029 #need to load json twice as original content was string escaped a second time
1030 selEntries = json.loads(json.loads(cleanSels))
1031 selEntries = selEntries['data']
Justin Thalere412dc22018-01-12 16:28:24 -06001032
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001033 if 'description' in selEntries:
1034 if(args.json):
1035 return("{\n\t\"numAlerts\": 0\n}")
1036 else:
1037 return("No log entries found")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001038
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001039 else:
1040 if(len(policyTable)>0):
1041 events = parseAlerts(policyTable, selEntries, args)
1042 if(args.json):
1043 events["numAlerts"] = len(events)
1044 retValue = str(json.dumps(events, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False))
1045 return retValue
1046 elif(hasattr(args, 'fullSel')):
1047 return events
1048 else:
1049 #get log numbers to order event entries sequentially
1050 return selDisplay(events, args)
1051 else:
1052 if(args.json):
1053 return selEntries
1054 else:
1055 print("error: Policy Table not found.")
1056 return selEntries
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001057
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001058def selList(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001059 """
1060 prints out all all bmc alerts, or only prints out the specified alerts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001061
Justin Thalere412dc22018-01-12 16:28:24 -06001062 @param host: string, the hostname or IP address of the bmc
1063 @param args: contains additional arguments used by the fru sub command
1064 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001065 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1066 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001067 return(sel(host, args, session))
1068
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001069
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001070def selClear(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001071 """
1072 clears all alerts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001073
Justin Thalere412dc22018-01-12 16:28:24 -06001074 @param host: string, the hostname or IP address of the bmc
1075 @param args: contains additional arguments used by the fru sub command
1076 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001077 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1078 """
Matt Spinler47b13e92019-01-04 14:58:53 -06001079 url="https://"+host+"/xyz/openbmc_project/logging/action/DeleteAll"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001080 data = "{\"data\": [] }"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001081
Justin Thalere412dc22018-01-12 16:28:24 -06001082 try:
Justin Thaler27197622019-01-23 14:42:11 -06001083 res = session.post(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001084 except(requests.exceptions.Timeout):
1085 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001086 if res.status_code == 200:
1087 return "The Alert Log has been cleared. Please allow a few minutes for the action to complete."
1088 else:
1089 print("Unable to clear the logs, trying to clear 1 at a time")
1090 sels = json.loads(sel(host, args, session))['data']
1091 for key in sels:
1092 if 'callout' not in key:
1093 logNum = key.split('/')[-1]
1094 url = "https://"+ host+ "/xyz/openbmc_project/logging/entry/"+logNum+"/action/Delete"
1095 try:
Justin Thaler27197622019-01-23 14:42:11 -06001096 session.post(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001097 except(requests.exceptions.Timeout):
1098 return connectionErrHandler(args.json, "Timeout", None)
1099 sys.exit(1)
1100 except(requests.exceptions.ConnectionError) as err:
1101 return connectionErrHandler(args.json, "ConnectionError", err)
1102 sys.exit(1)
1103 return ('Sel clearing complete')
1104
1105def selSetResolved(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001106 """
1107 sets a sel entry to resolved
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001108
Justin Thalere412dc22018-01-12 16:28:24 -06001109 @param host: string, the hostname or IP address of the bmc
1110 @param args: contains additional arguments used by the fru sub command
1111 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001112 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1113 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001114 url="https://"+host+"/xyz/openbmc_project/logging/entry/" + str(args.selNum) + "/attr/Resolved"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001115 data = "{\"data\": 1 }"
Justin Thalere412dc22018-01-12 16:28:24 -06001116 try:
Justin Thaler27197622019-01-23 14:42:11 -06001117 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001118 except(requests.exceptions.Timeout):
1119 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001120 if res.status_code == 200:
1121 return "Sel entry "+ str(args.selNum) +" is now set to resolved"
1122 else:
1123 return "Unable to set the alert to resolved"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001124
Justin Thalere412dc22018-01-12 16:28:24 -06001125def selResolveAll(host, args, session):
1126 """
1127 sets a sel entry to resolved
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001128
Justin Thalere412dc22018-01-12 16:28:24 -06001129 @param host: string, the hostname or IP address of the bmc
1130 @param args: contains additional arguments used by the fru sub command
1131 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001132 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1133 """
Justin Thalere412dc22018-01-12 16:28:24 -06001134 rawselEntries = sel(host, args, session)
1135 loadFailed = False
1136 try:
1137 selEntries = json.loads(rawselEntries)
1138 except ValueError:
1139 loadFailed = True
1140 if loadFailed:
1141 cleanSels = json.dumps(rawselEntries).replace('\\n', '')
1142 #need to load json twice as original content was string escaped a second time
1143 selEntries = json.loads(json.loads(cleanSels))
1144 selEntries = selEntries['data']
1145
1146 if 'description' in selEntries:
1147 if(args.json):
1148 return("{\n\t\"selsResolved\": 0\n}")
1149 else:
1150 return("No log entries found")
1151 else:
1152 d = vars(args)
1153 successlist = []
1154 failedlist = []
1155 for key in selEntries:
1156 if 'callout' not in key:
1157 d['selNum'] = key.split('/')[-1]
1158 resolved = selSetResolved(host,args,session)
1159 if 'Sel entry' in resolved:
1160 successlist.append(d['selNum'])
1161 else:
1162 failedlist.append(d['selNum'])
1163 output = ""
1164 successlist.sort()
1165 failedlist.sort()
1166 if len(successlist)>0:
1167 output = "Successfully resolved: " +', '.join(successlist) +"\n"
1168 if len(failedlist)>0:
1169 output += "Failed to resolve: " + ', '.join(failedlist) + "\n"
1170 return output
1171
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001172def chassisPower(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001173 """
1174 called by the chassis function. Controls the power state of the chassis, or gets the status
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001175
Justin Thalere412dc22018-01-12 16:28:24 -06001176 @param host: string, the hostname or IP address of the bmc
1177 @param args: contains additional arguments used by the fru sub command
1178 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001179 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1180 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001181 if(args.powcmd == 'on'):
Justin Thaler22b1bb52018-03-15 13:31:32 -05001182 if checkFWactivation(host, args, session):
1183 return ("Chassis Power control disabled during firmware activation")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001184 print("Attempting to Power on...:")
1185 url="https://"+host+"/xyz/openbmc_project/state/host0/attr/RequestedHostTransition"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001186 data = '{"data":"xyz.openbmc_project.State.Host.Transition.On"}'
Justin Thalere412dc22018-01-12 16:28:24 -06001187 try:
Justin Thaler27197622019-01-23 14:42:11 -06001188 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001189 except(requests.exceptions.Timeout):
1190 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001191 return res.text
Justin Thalere412dc22018-01-12 16:28:24 -06001192 elif(args.powcmd == 'softoff'):
Justin Thaler22b1bb52018-03-15 13:31:32 -05001193 if checkFWactivation(host, args, session):
1194 return ("Chassis Power control disabled during firmware activation")
Justin Thalere412dc22018-01-12 16:28:24 -06001195 print("Attempting to Power off gracefully...:")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001196 url="https://"+host+"/xyz/openbmc_project/state/host0/attr/RequestedHostTransition"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001197 data = '{"data":"xyz.openbmc_project.State.Host.Transition.Off"}'
Justin Thalere412dc22018-01-12 16:28:24 -06001198 try:
Justin Thaler27197622019-01-23 14:42:11 -06001199 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001200 except(requests.exceptions.Timeout):
1201 return(connectionErrHandler(args.json, "Timeout", None))
1202 return res.text
1203 elif(args.powcmd == 'hardoff'):
Justin Thaler22b1bb52018-03-15 13:31:32 -05001204 if checkFWactivation(host, args, session):
1205 return ("Chassis Power control disabled during firmware activation")
Justin Thalere412dc22018-01-12 16:28:24 -06001206 print("Attempting to Power off immediately...:")
1207 url="https://"+host+"/xyz/openbmc_project/state/chassis0/attr/RequestedPowerTransition"
Justin Thalere412dc22018-01-12 16:28:24 -06001208 data = '{"data":"xyz.openbmc_project.State.Chassis.Transition.Off"}'
1209 try:
Justin Thaler27197622019-01-23 14:42:11 -06001210 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001211 except(requests.exceptions.Timeout):
1212 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001213 return res.text
1214 elif(args.powcmd == 'status'):
1215 url="https://"+host+"/xyz/openbmc_project/state/chassis0/attr/CurrentPowerState"
Justin Thalere412dc22018-01-12 16:28:24 -06001216 try:
Justin Thaler27197622019-01-23 14:42:11 -06001217 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001218 except(requests.exceptions.Timeout):
1219 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001220 chassisState = json.loads(res.text)['data'].split('.')[-1]
1221 url="https://"+host+"/xyz/openbmc_project/state/host0/attr/CurrentHostState"
Justin Thalere412dc22018-01-12 16:28:24 -06001222 try:
Justin Thaler27197622019-01-23 14:42:11 -06001223 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001224 except(requests.exceptions.Timeout):
1225 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001226 hostState = json.loads(res.text)['data'].split('.')[-1]
1227 url="https://"+host+"/xyz/openbmc_project/state/bmc0/attr/CurrentBMCState"
Justin Thalere412dc22018-01-12 16:28:24 -06001228 try:
Justin Thaler27197622019-01-23 14:42:11 -06001229 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001230 except(requests.exceptions.Timeout):
1231 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001232 bmcState = json.loads(res.text)['data'].split('.')[-1]
1233 if(args.json):
1234 outDict = {"Chassis Power State" : chassisState, "Host Power State" : hostState, "BMC Power State":bmcState}
1235 return json.dumps(outDict, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False)
1236 else:
1237 return "Chassis Power State: " +chassisState + "\nHost Power State: " + hostState + "\nBMC Power State: " + bmcState
1238 else:
1239 return "Invalid chassis power command"
1240
Justin Thalere412dc22018-01-12 16:28:24 -06001241
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001242def chassisIdent(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001243 """
1244 called by the chassis function. Controls the identify led of the chassis. Sets or gets the state
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001245
Justin Thalere412dc22018-01-12 16:28:24 -06001246 @param host: string, the hostname or IP address of the bmc
1247 @param args: contains additional arguments used by the fru sub command
1248 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001249 @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 -06001250 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001251 if(args.identcmd == 'on'):
1252 print("Attempting to turn identify light on...:")
1253 url="https://"+host+"/xyz/openbmc_project/led/groups/enclosure_identify/attr/Asserted"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001254 data = '{"data":true}'
Justin Thalere412dc22018-01-12 16:28:24 -06001255 try:
Justin Thaler27197622019-01-23 14:42:11 -06001256 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001257 except(requests.exceptions.Timeout):
1258 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001259 return res.text
1260 elif(args.identcmd == 'off'):
1261 print("Attempting to turn identify light off...:")
1262 url="https://"+host+"/xyz/openbmc_project/led/groups/enclosure_identify/attr/Asserted"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001263 data = '{"data":false}'
Justin Thalere412dc22018-01-12 16:28:24 -06001264 try:
Justin Thaler27197622019-01-23 14:42:11 -06001265 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001266 except(requests.exceptions.Timeout):
1267 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001268 return res.text
1269 elif(args.identcmd == 'status'):
1270 url="https://"+host+"/xyz/openbmc_project/led/groups/enclosure_identify"
Justin Thalere412dc22018-01-12 16:28:24 -06001271 try:
Justin Thaler27197622019-01-23 14:42:11 -06001272 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001273 except(requests.exceptions.Timeout):
1274 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001275 status = json.loads(res.text)['data']
1276 if(args.json):
1277 return status
1278 else:
1279 if status['Asserted'] == 0:
1280 return "Identify light is off"
1281 else:
1282 return "Identify light is blinking"
1283 else:
1284 return "Invalid chassis identify command"
1285
Justin Thalere412dc22018-01-12 16:28:24 -06001286
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001287def chassis(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001288 """
1289 controls the different chassis commands
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001290
Justin Thalere412dc22018-01-12 16:28:24 -06001291 @param host: string, the hostname or IP address of the bmc
1292 @param args: contains additional arguments used by the fru sub command
1293 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001294 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1295 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001296 if(hasattr(args, 'powcmd')):
1297 result = chassisPower(host,args,session)
1298 elif(hasattr(args, 'identcmd')):
1299 result = chassisIdent(host, args, session)
1300 else:
Justin Thaler22b1bb52018-03-15 13:31:32 -05001301 return "This feature is not yet implemented"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001302 return result
Justin Thalere412dc22018-01-12 16:28:24 -06001303
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001304def bmcDumpRetrieve(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001305 """
1306 Downloads a dump file from the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001307
Justin Thalere412dc22018-01-12 16:28:24 -06001308 @param host: string, the hostname or IP address of the bmc
1309 @param args: contains additional arguments used by the collectServiceData sub command
1310 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001311 @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 -06001312 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001313 dumpNum = args.dumpNum
1314 if (args.dumpSaveLoc is not None):
1315 saveLoc = args.dumpSaveLoc
1316 else:
Justin Thalercf1deae2018-05-25 19:35:21 -05001317 saveLoc = tempfile.gettempdir()
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001318 url ='https://'+host+'/download/dump/' + str(dumpNum)
1319 try:
Justin Thaler27197622019-01-23 14:42:11 -06001320 r = session.get(url, headers=jsonHeader, stream=True, verify=False, timeout=baseTimeout)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001321 if (args.dumpSaveLoc is not None):
1322 if os.path.exists(saveLoc):
1323 if saveLoc[-1] != os.path.sep:
1324 saveLoc = saveLoc + os.path.sep
1325 filename = saveLoc + host+'-dump' + str(dumpNum) + '.tar.xz'
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001326
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001327 else:
1328 return 'Invalid save location specified'
1329 else:
Justin Thalercf1deae2018-05-25 19:35:21 -05001330 filename = tempfile.gettempdir()+os.sep + host+'-dump' + str(dumpNum) + '.tar.xz'
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001331
1332 with open(filename, 'wb') as f:
1333 for chunk in r.iter_content(chunk_size =1024):
1334 if chunk:
1335 f.write(chunk)
1336 return 'Saved as ' + filename
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001337
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001338 except(requests.exceptions.Timeout):
1339 return connectionErrHandler(args.json, "Timeout", None)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001340
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001341 except(requests.exceptions.ConnectionError) as err:
1342 return connectionErrHandler(args.json, "ConnectionError", err)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001343
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001344def bmcDumpList(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001345 """
1346 Lists the number of dump files on the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001347
Justin Thalere412dc22018-01-12 16:28:24 -06001348 @param host: string, the hostname or IP address of the bmc
1349 @param args: contains additional arguments used by the collectServiceData sub command
1350 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001351 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1352 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001353 url ='https://'+host+'/xyz/openbmc_project/dump/list'
1354 try:
Justin Thaler27197622019-01-23 14:42:11 -06001355 r = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thaler3a5771b2019-01-23 14:31:52 -06001356 dumpList = r.json()
1357 return dumpList
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001358 except(requests.exceptions.Timeout):
1359 return connectionErrHandler(args.json, "Timeout", None)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001360
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001361 except(requests.exceptions.ConnectionError) as err:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001362 return connectionErrHandler(args.json, "ConnectionError", err)
1363
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001364def bmcDumpDelete(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001365 """
1366 Deletes BMC dump files from the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001367
Justin Thalere412dc22018-01-12 16:28:24 -06001368 @param host: string, the hostname or IP address of the bmc
1369 @param args: contains additional arguments used by the collectServiceData sub command
1370 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001371 @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 -06001372 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001373 dumpList = []
1374 successList = []
1375 failedList = []
1376 if args.dumpNum is not None:
1377 if isinstance(args.dumpNum, list):
1378 dumpList = args.dumpNum
1379 else:
1380 dumpList.append(args.dumpNum)
1381 for dumpNum in dumpList:
1382 url ='https://'+host+'/xyz/openbmc_project/dump/entry/'+str(dumpNum)+'/action/Delete'
1383 try:
Justin Thaler27197622019-01-23 14:42:11 -06001384 r = session.post(url, headers=jsonHeader, json = {"data": []}, verify=False, timeout=baseTimeout)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001385 if r.status_code == 200:
1386 successList.append(str(dumpNum))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001387 else:
1388 failedList.append(str(dumpNum))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001389 except(requests.exceptions.Timeout):
1390 return connectionErrHandler(args.json, "Timeout", None)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001391 except(requests.exceptions.ConnectionError) as err:
1392 return connectionErrHandler(args.json, "ConnectionError", err)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001393 output = "Successfully deleted dumps: " + ', '.join(successList)
1394 if(len(failedList)>0):
1395 output+= '\nFailed to delete dumps: ' + ', '.join(failedList)
1396 return output
1397 else:
1398 return 'You must specify an entry number to delete'
1399
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001400def bmcDumpDeleteAll(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001401 """
1402 Deletes All BMC dump files from the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001403
Justin Thalere412dc22018-01-12 16:28:24 -06001404 @param host: string, the hostname or IP address of the bmc
1405 @param args: contains additional arguments used by the collectServiceData sub command
1406 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001407 @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 -06001408 """
1409 dumpResp = bmcDumpList(host, args, session)
1410 if 'FQPSPIN0000M' in dumpResp or 'FQPSPIN0001M'in dumpResp:
1411 return dumpResp
Justin Thaler3a5771b2019-01-23 14:31:52 -06001412 dumpList = dumpResp['data']
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001413 d = vars(args)
1414 dumpNums = []
1415 for dump in dumpList:
1416 if '/xyz/openbmc_project/dump/internal/manager' not in dump:
1417 dumpNums.append(int(dump.strip().split('/')[-1]))
1418 d['dumpNum'] = dumpNums
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001419
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001420 return bmcDumpDelete(host, args, session)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001421
Justin Thalere412dc22018-01-12 16:28:24 -06001422
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001423def bmcDumpCreate(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001424 """
1425 Creates a bmc dump file
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001426
Justin Thalere412dc22018-01-12 16:28:24 -06001427 @param host: string, the hostname or IP address of the bmc
1428 @param args: contains additional arguments used by the collectServiceData sub command
1429 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001430 @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 -06001431 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001432 url = 'https://'+host+'/xyz/openbmc_project/dump/action/CreateDump'
1433 try:
Justin Thaler27197622019-01-23 14:42:11 -06001434 r = session.post(url, headers=jsonHeader, json = {"data": []}, verify=False, timeout=baseTimeout)
Matt Spinlereae05b02019-01-24 12:59:34 -06001435 if(r.status_code == 200 and not args.json):
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001436 return ('Dump successfully created')
Justin Thaler3a5771b2019-01-23 14:31:52 -06001437 elif(args.json):
1438 return r.json()
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001439 else:
1440 return ('Failed to create dump')
1441 except(requests.exceptions.Timeout):
1442 return connectionErrHandler(args.json, "Timeout", None)
1443 except(requests.exceptions.ConnectionError) as err:
1444 return connectionErrHandler(args.json, "ConnectionError", err)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001445
1446
Justin Thaler666cf342019-01-23 14:44:27 -06001447def csdDumpInitiate(host, args, session):
1448 """
1449 Starts the process of getting the current list of dumps then initiates the creation of one.
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001450
Justin Thaler666cf342019-01-23 14:44:27 -06001451 @param host: string, the hostname or IP address of the bmc
1452 @param args: contains additional arguments used by the collectServiceData sub command
1453 @param session: the active session to use
1454 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1455 """
1456 errorInfo = ""
1457 dumpcount = 0
1458 try:
1459 d = vars(args)
1460 d['json'] = True
1461 except Exception as e:
1462 errorInfo += "Failed to set the json flag to True \n Exception: {eInfo}\n".format(eInfo=e)
1463
1464 try:
1465 for i in range(3):
1466 dumpInfo = bmcDumpList(host, args, session)
1467 if 'data' in dumpInfo:
1468 dumpcount = len(dumpInfo['data'])
1469 break
1470 else:
1471 errorInfo+= "Dump List Message returned: " + json.dumps(dumpInfo,indent=0, separators=(',', ':')).replace('\n','') +"\n"
1472 except Exception as e:
1473 errorInfo+= "Failed to collect the list of dumps.\nException: {eInfo}\n".format(eInfo=e)
1474
1475 #Create a user initiated dump
1476 try:
1477 for i in range(3):
1478 dumpcreated = bmcDumpCreate(host, args, session)
1479 if 'message' in dumpcreated:
1480 if 'ok' in dumpcreated['message'].lower():
1481 break
1482 else:
1483 errorInfo+= "Dump create message returned: " + json.dumps(dumpInfo,indent=0, separators=(',', ':')).replace('\n','') +"\n"
1484 else:
1485 errorInfo+= "Dump create message returned: " + json.dumps(dumpInfo,indent=0, separators=(',', ':')).replace('\n','') +"\n"
1486 except Exception as e:
1487 errorInfo+= "Dump create exception encountered: {eInfo}\n".format(eInfo=e)
1488
1489 output = {}
1490 output['errors'] = errorInfo
1491 output['dumpcount'] = dumpcount
1492 return output
1493
1494def csdInventory(host, args,session, fileDir):
1495 """
1496 Collects the BMC inventory, retrying if necessary
1497
1498 @param host: string, the hostname or IP address of the bmc
1499 @param args: contains additional arguments used by the collectServiceData sub command
1500 @param session: the active session to use
1501 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1502 @param fileDir: string representation of the path to use for putting files created
1503 """
1504 errorInfo = "===========Inventory =============\n"
1505 output={}
1506 inventoryCollected = False
1507 try:
1508 for i in range(3):
1509 frulist = fruPrint(host, args, session)
1510 if 'Hardware' in frulist:
1511 inventoryCollected = True
1512 break
1513 else:
1514 errorInfo += json.dumps(frulist, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n'
1515 except Exception as e:
1516 errorInfo += "Inventory collection exception: {eInfo}\n".format(eInfo=e)
1517 if inventoryCollected:
1518 try:
1519 with open(fileDir +os.sep+'inventory.txt', 'w') as f:
1520 f.write(json.dumps(frulist, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n')
1521 print("Inventory collected and stored in " + fileDir + os.sep + "inventory.txt")
1522 output['fileLoc'] = fileDir+os.sep+'inventory.txt'
1523 except Exception as e:
1524 print("Failed to write inventory to file.")
1525 errorInfo += "Error writing inventory to the file. Exception: {eInfo}\n".format(eInfo=e)
1526
1527 output['errors'] = errorInfo
1528
1529 return output
1530
1531def csdSensors(host, args,session, fileDir):
1532 """
1533 Collects the BMC sensor readings, retrying if necessary
1534
1535 @param host: string, the hostname or IP address of the bmc
1536 @param args: contains additional arguments used by the collectServiceData sub command
1537 @param session: the active session to use
1538 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1539 @param fileDir: string representation of the path to use for putting files created
1540 """
1541 errorInfo = "===========Sensors =============\n"
1542 sensorsCollected = False
1543 output={}
1544 try:
1545 d = vars(args)
1546 d['json'] = False
1547 except Exception as e:
1548 errorInfo += "Failed to set the json flag to False \n Exception: {eInfo}\n".format(eInfo=e)
1549
1550 try:
1551 for i in range(3):
1552 sensorReadings = sensor(host, args, session)
1553 if 'OCC0' in sensorReadings:
1554 sensorsCollected = True
1555 break
1556 else:
1557 errorInfo += sensorReadings
1558 except Exception as e:
1559 errorInfo += "Sensor reading collection exception: {eInfo}\n".format(eInfo=e)
1560 if sensorsCollected:
1561 try:
1562 with open(fileDir +os.sep+'sensorReadings.txt', 'w') as f:
1563 f.write(sensorReadings)
1564 print("Sensor readings collected and stored in " + fileDir + os.sep+ "sensorReadings.txt")
1565 output['fileLoc'] = fileDir+os.sep+'sensorReadings.txt'
1566 except Exception as e:
1567 print("Failed to write sensor readings to file system.")
1568 errorInfo += "Error writing sensor readings to the file. Exception: {eInfo}\n".format(eInfo=e)
1569
1570 output['errors'] = errorInfo
1571 return output
1572
1573def csdLEDs(host,args, session, fileDir):
1574 """
1575 Collects the BMC LED status, retrying if necessary
1576
1577 @param host: string, the hostname or IP address of the bmc
1578 @param args: contains additional arguments used by the collectServiceData sub command
1579 @param session: the active session to use
1580 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1581 @param fileDir: string representation of the path to use for putting files created
1582 """
1583 errorInfo = "===========LEDs =============\n"
1584 ledsCollected = False
1585 output={}
1586 try:
1587 d = vars(args)
1588 d['json'] = True
1589 except Exception as e:
1590 errorInfo += "Failed to set the json flag to False \n Exception: {eInfo}\n".format(eInfo=e)
1591 try:
1592 url="https://"+host+"/xyz/openbmc_project/led/enumerate"
1593 httpHeader = {'Content-Type':'application/json'}
1594 for i in range(3):
1595 try:
1596 ledRes = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
1597 if ledRes.status_code == 200:
1598 ledsCollected = True
1599 leds = ledRes.json()['data']
1600 break
1601 else:
1602 errorInfo += ledRes.text
1603 except(requests.exceptions.Timeout):
1604 errorInfo+=json.dumps( connectionErrHandler(args.json, "Timeout", None), sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n'
1605 except(requests.exceptions.ConnectionError) as err:
1606 errorInfo += json.dumps(connectionErrHandler(args.json, "ConnectionError", err), sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n'
1607 except Exception as e:
1608 errorInfo += "LED status collection exception: {eInfo}\n".format(eInfo=e)
1609
1610 if ledsCollected:
1611 try:
1612 with open(fileDir +os.sep+'ledStatus.txt', 'w') as f:
1613 f.write(json.dumps(leds, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n')
1614 print("LED status collected and stored in " + fileDir + os.sep+ "ledStatus.txt")
1615 output['fileLoc'] = fileDir+os.sep+'ledStatus.txt'
1616 except Exception as e:
1617 print("Failed to write LED status to file system.")
1618 errorInfo += "Error writing LED status to the file. Exception: {eInfo}\n".format(eInfo=e)
1619
1620 output['errors'] = errorInfo
1621 return output
1622
1623def csdSelShortList(host, args, session, fileDir):
1624 """
1625 Collects the BMC log entries, retrying if necessary
1626
1627 @param host: string, the hostname or IP address of the bmc
1628 @param args: contains additional arguments used by the collectServiceData sub command
1629 @param session: the active session to use
1630 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1631 @param fileDir: string representation of the path to use for putting files created
1632 """
1633 errorInfo = "===========SEL Short List =============\n"
1634 selsCollected = False
1635 output={}
1636 try:
1637 d = vars(args)
1638 d['json'] = False
1639 except Exception as e:
1640 errorInfo += "Failed to set the json flag to False \n Exception: {eInfo}\n".format(eInfo=e)
1641
1642 try:
1643 for i in range(3):
1644 sels = selPrint(host,args,session)
1645 if '----Active Alerts----' in sels or 'No log entries found' in sels or '----Historical Alerts----' in sels:
1646 selsCollected = True
1647 break
1648 else:
1649 errorInfo += sels + '\n'
1650 except Exception as e:
1651 errorInfo += "SEL short list collection exception: {eInfo}\n".format(eInfo=e)
1652
1653 if selsCollected:
1654 try:
1655 with open(fileDir +os.sep+'SELshortlist.txt', 'w') as f:
1656 f.write(sels)
1657 print("SEL short list collected and stored in " + fileDir + os.sep+ "SELshortlist.txt")
1658 output['fileLoc'] = fileDir+os.sep+'SELshortlist.txt'
1659 except Exception as e:
1660 print("Failed to write SEL short list to file system.")
1661 errorInfo += "Error writing SEL short list to the file. Exception: {eInfo}\n".format(eInfo=e)
1662
1663 output['errors'] = errorInfo
1664 return output
1665
1666def csdParsedSels(host, args, session, fileDir):
1667 """
1668 Collects the BMC log entries, retrying if necessary
1669
1670 @param host: string, the hostname or IP address of the bmc
1671 @param args: contains additional arguments used by the collectServiceData sub command
1672 @param session: the active session to use
1673 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1674 @param fileDir: string representation of the path to use for putting files created
1675 """
1676 errorInfo = "===========SEL Parsed List =============\n"
1677 selsCollected = False
1678 output={}
1679 try:
1680 d = vars(args)
1681 d['json'] = True
1682 d['fullEsel'] = True
1683 except Exception as e:
1684 errorInfo += "Failed to set the json flag to True \n Exception: {eInfo}\n".format(eInfo=e)
1685
1686 try:
1687 for i in range(3):
1688 parsedfullsels = json.loads(selPrint(host,args,session))
1689 if 'numAlerts' in parsedfullsels:
1690 selsCollected = True
1691 break
1692 else:
1693 errorInfo += parsedfullsels + '\n'
1694 except Exception as e:
1695 errorInfo += "Parsed full SELs collection exception: {eInfo}\n".format(eInfo=e)
1696
1697 if selsCollected:
1698 try:
1699 sortedSELs = sortSELs(parsedfullsels)
1700 with open(fileDir +os.sep+'parsedSELs.txt', 'w') as f:
1701 for log in sortedSELs[0]:
1702 esel = ""
1703 parsedfullsels[sortedSELs[1][str(log)]]['timestamp'] = datetime.datetime.fromtimestamp(int(parsedfullsels[sortedSELs[1][str(log)]]['timestamp']/1000)).strftime("%Y-%m-%d %H:%M:%S")
1704 if ('raweSEL' in parsedfullsels[sortedSELs[1][str(log)]] and args.devdebug):
1705 esel = parsedfullsels[sortedSELs[1][str(log)]]['raweSEL']
1706 del parsedfullsels[sortedSELs[1][str(log)]]['raweSEL']
1707 f.write(json.dumps(parsedfullsels[sortedSELs[1][str(log)]],sort_keys=True, indent=4, separators=(',', ': ')))
1708 if(args.devdebug and esel != ""):
1709 f.write(parseESEL(args, esel))
1710 print("Parsed SELs collected and stored in " + fileDir + os.sep+ "parsedSELs.txt")
1711 output['fileLoc'] = fileDir+os.sep+'parsedSELs.txt'
1712 except Exception as e:
1713 print("Failed to write fully parsed SELs to file system.")
1714 errorInfo += "Error writing fully parsed SELs to the file. Exception: {eInfo}\n".format(eInfo=e)
1715
1716 output['errors'] = errorInfo
1717 return output
1718
1719def csdFullEnumeration(host, args, session, fileDir):
1720 """
1721 Collects a full enumeration of /xyz/openbmc_project/, retrying if necessary
1722
1723 @param host: string, the hostname or IP address of the bmc
1724 @param args: contains additional arguments used by the collectServiceData sub command
1725 @param session: the active session to use
1726 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1727 @param fileDir: string representation of the path to use for putting files created
1728 """
1729 errorInfo = "===========BMC Full Enumeration =============\n"
1730 bmcFullCollected = False
1731 output={}
1732 try:
1733 d = vars(args)
1734 d['json'] = True
1735 except Exception as e:
1736 errorInfo += "Failed to set the json flag to False \n Exception: {eInfo}\n".format(eInfo=e)
1737 try:
1738 print("Attempting to get a full BMC enumeration")
1739 url="https://"+host+"/xyz/openbmc_project/enumerate"
1740 httpHeader = {'Content-Type':'application/json'}
1741 for i in range(3):
1742 try:
1743 bmcRes = session.get(url, headers=jsonHeader, verify=False, timeout=180)
1744 if bmcRes.status_code == 200:
1745 bmcFullCollected = True
1746 fullEnumeration = bmcRes.json()
1747 break
1748 else:
1749 errorInfo += bmcRes.text
1750 except(requests.exceptions.Timeout):
1751 errorInfo+=json.dumps( connectionErrHandler(args.json, "Timeout", None), sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n'
1752 except(requests.exceptions.ConnectionError) as err:
1753 errorInfo += json.dumps(connectionErrHandler(args.json, "ConnectionError", err), sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n'
1754 except Exception as e:
1755 errorInfo += "RAW BMC data collection exception: {eInfo}\n".format(eInfo=e)
1756
1757 if bmcFullCollected:
1758 try:
1759 with open(fileDir +os.sep+'bmcFullRaw.txt', 'w') as f:
1760 f.write(json.dumps(fullEnumeration, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n')
1761 print("RAW BMC data collected and saved into " + fileDir + os.sep+ "bmcFullRaw.txt")
1762 output['fileLoc'] = fileDir+os.sep+'bmcFullRaw.txt'
1763 except Exception as e:
1764 print("Failed to write RAW BMC data to file system.")
1765 errorInfo += "Error writing RAW BMC data collection to the file. Exception: {eInfo}\n".format(eInfo=e)
1766
1767 output['errors'] = errorInfo
1768 return output
1769
1770def csdCollectAllDumps(host, args, session, fileDir):
1771 """
1772 Collects all of the bmc dump files and stores them in fileDir
1773
1774 @param host: string, the hostname or IP address of the bmc
1775 @param args: contains additional arguments used by the collectServiceData sub command
1776 @param session: the active session to use
1777 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1778 @param fileDir: string representation of the path to use for putting files created
1779 """
1780
1781 errorInfo = "===========BMC Dump Collection =============\n"
1782 dumpListCollected = False
1783 output={}
1784 dumpList = {}
1785 try:
1786 d = vars(args)
1787 d['json'] = True
1788 d['dumpSaveLoc'] = fileDir
1789 except Exception as e:
1790 errorInfo += "Failed to set the json flag to True, or failed to set the dumpSave Location \n Exception: {eInfo}\n".format(eInfo=e)
1791
1792 print('Collecting bmc dump files')
1793
1794 try:
1795 for i in range(3):
1796 dumpResp = bmcDumpList(host, args, session)
1797 if 'message' in dumpResp:
1798 if 'ok' in dumpResp['message'].lower():
1799 dumpList = dumpResp['data']
1800 dumpListCollected = True
1801 break
1802 else:
1803 errorInfo += "Status was not OK when retrieving the list of dumps available. \n Response: \n{resp}\n".format(resp=dumpResp)
1804 else:
1805 errorInfo += "Invalid response received from the BMC while retrieving the list of dumps available.\n {resp}\n".format(resp=dumpResp)
1806 except Exception as e:
1807 errorInfo += "BMC dump list exception: {eInfo}\n".format(eInfo=e)
1808
1809 if dumpListCollected:
1810 output['fileList'] = []
1811 for dump in dumpList:
1812 try:
1813 if '/xyz/openbmc_project/dump/internal/manager' not in dump:
1814 d['dumpNum'] = int(dump.strip().split('/')[-1])
1815 print('retrieving dump file ' + str(d['dumpNum']))
1816 filename = bmcDumpRetrieve(host, args, session).split('Saved as ')[-1]
1817 output['fileList'].append(filename)
1818 except Exception as e:
1819 print("Unable to collect dump: {dumpInfo}".format(dumpInfo=dump))
1820 errorInfo += "Exception collecting a bmc dump {dumpInfo}\n {eInfo}\n".format(dumpInfo=dump, eInfo=e)
1821 output['errors'] = errorInfo
1822 return output
Justin Thalere412dc22018-01-12 16:28:24 -06001823
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001824def collectServiceData(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001825 """
1826 Collects all data needed for service from the BMC
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001827
Justin Thalere412dc22018-01-12 16:28:24 -06001828 @param host: string, the hostname or IP address of the bmc
1829 @param args: contains additional arguments used by the collectServiceData sub command
1830 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001831 @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 -06001832 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001833
Justin Thaler22b1bb52018-03-15 13:31:32 -05001834 global toolVersion
Justin Thaler666cf342019-01-23 14:44:27 -06001835 filelist = []
1836 errorInfo = ""
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001837
Justin Thaler666cf342019-01-23 14:44:27 -06001838 #get current number of bmc dumps and create a new bmc dump
1839 dumpInitdata = csdDumpInitiate(host, args, session)
1840 dumpcount = dumpInitdata['dumpcount']
1841 errorInfo += dumpInitdata['errors']
1842 #create the directory to put files
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001843 try:
1844 args.silent = True
Justin Thalercf1deae2018-05-25 19:35:21 -05001845 myDir = tempfile.gettempdir()+os.sep + host + "--" + datetime.datetime.now().strftime("%Y-%m-%d_%H.%M.%S")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001846 os.makedirs(myDir)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001847
Justin Thaler666cf342019-01-23 14:44:27 -06001848 except Exception as e:
1849 print('Unable to create the temporary directory for data collection. Ensure sufficient privileges to create temporary directory. Aborting.')
1850 return("Python exception: {eInfo}".format(eInfo = e))
1851
1852 #Collect Inventory
1853 inventoryData = csdInventory(host, args, session, myDir)
1854 if 'fileLoc' in inventoryData:
1855 filelist.append(inventoryData['fileLoc'])
1856 errorInfo += inventoryData['errors']
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001857 #Read all the sensor and OCC status
Justin Thaler666cf342019-01-23 14:44:27 -06001858 sensorData = csdSensors(host,args,session,myDir)
1859 if 'fileLoc' in sensorData:
1860 filelist.append(sensorData['fileLoc'])
1861 errorInfo += sensorData['errors']
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001862 #Collect all of the LEDs status
Justin Thaler666cf342019-01-23 14:44:27 -06001863 ledStatus = csdLEDs(host, args, session, myDir)
1864 if 'fileLoc' in ledStatus:
1865 filelist.append(ledStatus['fileLoc'])
1866 errorInfo += ledStatus['errors']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001867
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001868 #Collect the bmc logs
Justin Thaler666cf342019-01-23 14:44:27 -06001869 selShort = csdSelShortList(host, args, session, myDir)
1870 if 'fileLoc' in selShort:
1871 filelist.append(selShort['fileLoc'])
1872 errorInfo += selShort['errors']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001873
Justin Thaler666cf342019-01-23 14:44:27 -06001874 parsedSELs = csdParsedSels(host, args, session, myDir)
1875 if 'fileLoc' in parsedSELs:
1876 filelist.append(parsedSELs['fileLoc'])
1877 errorInfo += parsedSELs['errors']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001878
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001879 #collect RAW bmc enumeration
Justin Thaler666cf342019-01-23 14:44:27 -06001880 bmcRaw = csdFullEnumeration(host, args, session, myDir)
1881 if 'fileLoc' in bmcRaw:
1882 filelist.append(bmcRaw['fileLoc'])
1883 errorInfo += bmcRaw['errors']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001884
Justin Thaler666cf342019-01-23 14:44:27 -06001885 #wait for new dump to finish being created
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001886 waitingForNewDump = True
1887 count = 0;
Justin Thaler666cf342019-01-23 14:44:27 -06001888 print("Waiting for new BMC dump to finish being created.")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001889 while(waitingForNewDump):
Justin Thaler666cf342019-01-23 14:44:27 -06001890 dumpList = bmcDumpList(host, args, session)['data']
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001891 if len(dumpList) > dumpcount:
1892 waitingForNewDump = False
1893 break;
1894 elif(count>30):
1895 print("Timed out waiting for bmc to make a new dump file. Dump space may be full.")
1896 break;
1897 else:
1898 time.sleep(2)
1899 count += 1
Justin Thaler666cf342019-01-23 14:44:27 -06001900
1901 #collect all of the dump files
1902 getBMCDumps = csdCollectAllDumps(host, args, session, myDir)
1903 if 'fileList' in getBMCDumps:
1904 filelist+= getBMCDumps['fileList']
1905 errorInfo += getBMCDumps['errors']
1906
1907 #write the runtime errors to a file
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001908 try:
Justin Thaler666cf342019-01-23 14:44:27 -06001909 with open(myDir +os.sep+'openbmctoolRuntimeErrors.txt', 'w') as f:
1910 f.write(errorInfo)
1911 print("OpenBMC tool runtime errors collected and stored in " + myDir + os.sep+ "openbmctoolRuntimeErrors.txt")
1912 filelist.append(myDir+os.sep+'openbmctoolRuntimeErrors.txt')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001913 except Exception as e:
Justin Thaler666cf342019-01-23 14:44:27 -06001914 print("Failed to write OpenBMC tool runtime errors to file system.")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001915
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001916 #create the zip file
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001917 try:
Justin Thalercf1deae2018-05-25 19:35:21 -05001918 filename = myDir.split(tempfile.gettempdir()+os.sep)[-1] + "_" + toolVersion + '_openbmc.zip'
Justin Thaler666cf342019-01-23 14:44:27 -06001919 zf = zipfile.ZipFile(myDir+os.sep + filename, 'w')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001920 for myfile in filelist:
1921 zf.write(myfile, os.path.basename(myfile))
1922 zf.close()
Justin Thaler666cf342019-01-23 14:44:27 -06001923 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 -06001924 except Exception as e:
1925 print("Failed to create zip file with collected information")
Justin Thaler666cf342019-01-23 14:44:27 -06001926 return "data collection finished"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001927
Justin Thalere412dc22018-01-12 16:28:24 -06001928
1929def healthCheck(host, args, session):
1930 """
1931 runs a health check on the platform
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001932
Justin Thalere412dc22018-01-12 16:28:24 -06001933 @param host: string, the hostname or IP address of the bmc
1934 @param args: contains additional arguments used by the bmc sub command
1935 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001936 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1937 """
Justin Thalere412dc22018-01-12 16:28:24 -06001938 #check fru status and get as json to easily work through
1939 d = vars(args)
1940 useJson = d['json']
1941 d['json'] = True
1942 d['verbose']= False
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001943
Justin Thalere412dc22018-01-12 16:28:24 -06001944 frus = json.loads(fruStatus(host, args, session))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001945
Justin Thalere412dc22018-01-12 16:28:24 -06001946 hwStatus= "OK"
1947 performanceStatus = "OK"
1948 for key in frus:
1949 if frus[key]["Functional"] == "No" and frus[key]["Present"] == "Yes":
1950 hwStatus= "Degraded"
Justin Thalerfb9c81c2018-07-16 11:14:37 -05001951 if("power_supply" in key or "powersupply" in key):
1952 gpuCount =0
1953 for comp in frus:
Justin Thalere412dc22018-01-12 16:28:24 -06001954 if "gv100card" in comp:
1955 gpuCount +=1
1956 if gpuCount > 4:
1957 hwStatus = "Critical"
1958 performanceStatus="Degraded"
1959 break;
1960 elif("fan" in key):
1961 hwStatus = "Degraded"
1962 else:
1963 performanceStatus = "Degraded"
1964 if useJson:
1965 output = {"Hardware Status": hwStatus, "Performance": performanceStatus}
1966 output = json.dumps(output, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False)
1967 else:
1968 output = ("Hardware Status: " + hwStatus +
1969 "\nPerformance: " +performanceStatus )
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001970
1971
Justin Thalere412dc22018-01-12 16:28:24 -06001972 #SW407886: Clear the duplicate entries
1973 #collect the dups
1974 d['devdebug'] = False
1975 sels = json.loads(selPrint(host, args, session))
1976 logNums2Clr = []
1977 oldestLogNum={"logNum": "bogus" ,"key" : ""}
1978 count = 0
1979 if sels['numAlerts'] > 0:
1980 for key in sels:
1981 if "numAlerts" in key:
1982 continue
1983 try:
1984 if "slave@00:00/00:00:00:06/sbefifo1-dev0/occ1-dev0" in sels[key]['Message']:
1985 count += 1
1986 if count > 1:
1987 #preserve first occurrence
1988 if sels[key]['timestamp'] < sels[oldestLogNum['key']]['timestamp']:
1989 oldestLogNum['key']=key
1990 oldestLogNum['logNum'] = sels[key]['logNum']
1991 else:
1992 oldestLogNum['key']=key
1993 oldestLogNum['logNum'] = sels[key]['logNum']
1994 logNums2Clr.append(sels[key]['logNum'])
1995 except KeyError:
1996 continue
1997 if(count >0):
1998 logNums2Clr.remove(oldestLogNum['logNum'])
1999 #delete the dups
2000 if count >1:
Justin Thalere412dc22018-01-12 16:28:24 -06002001 data = "{\"data\": [] }"
2002 for logNum in logNums2Clr:
2003 url = "https://"+ host+ "/xyz/openbmc_project/logging/entry/"+logNum+"/action/Delete"
2004 try:
Justin Thaler27197622019-01-23 14:42:11 -06002005 session.post(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002006 except(requests.exceptions.Timeout):
2007 deleteFailed = True
2008 except(requests.exceptions.ConnectionError) as err:
2009 deleteFailed = True
2010 #End of defect resolve code
2011 d['json'] = useJson
2012 return output
2013
2014
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002015
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002016def bmc(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06002017 """
2018 handles various bmc level commands, currently bmc rebooting
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002019
Justin Thalere412dc22018-01-12 16:28:24 -06002020 @param host: string, the hostname or IP address of the bmc
2021 @param args: contains additional arguments used by the bmc sub command
2022 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002023 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
2024 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002025 if(args.type is not None):
2026 return bmcReset(host, args, session)
Justin Thalere412dc22018-01-12 16:28:24 -06002027 if(args.info):
2028 return "Not implemented at this time"
2029
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002030
Justin Thalere412dc22018-01-12 16:28:24 -06002031
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002032def bmcReset(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06002033 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002034 controls resetting the bmc. warm reset reboots the bmc, cold reset removes the configuration and reboots.
2035
Justin Thalere412dc22018-01-12 16:28:24 -06002036 @param host: string, the hostname or IP address of the bmc
2037 @param args: contains additional arguments used by the bmcReset sub command
2038 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002039 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
2040 """
Justin Thaler22b1bb52018-03-15 13:31:32 -05002041 if checkFWactivation(host, args, session):
2042 return ("BMC reset control disabled during firmware activation")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002043 if(args.type == "warm"):
2044 print("\nAttempting to reboot the BMC...:")
2045 url="https://"+host+"/xyz/openbmc_project/state/bmc0/attr/RequestedBMCTransition"
Justin Thalere412dc22018-01-12 16:28:24 -06002046 data = '{"data":"xyz.openbmc_project.State.BMC.Transition.Reboot"}'
Justin Thaler27197622019-01-23 14:42:11 -06002047 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002048 return res.text
2049 elif(args.type =="cold"):
Justin Thalere412dc22018-01-12 16:28:24 -06002050 print("\nAttempting to reboot the BMC...:")
2051 url="https://"+host+"/xyz/openbmc_project/state/bmc0/attr/RequestedBMCTransition"
Justin Thalere412dc22018-01-12 16:28:24 -06002052 data = '{"data":"xyz.openbmc_project.State.BMC.Transition.Reboot"}'
Justin Thaler27197622019-01-23 14:42:11 -06002053 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002054 return res.text
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002055 else:
2056 return "invalid command"
Justin Thalere412dc22018-01-12 16:28:24 -06002057
2058def gardClear(host, args, session):
2059 """
2060 clears the gard records from the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002061
Justin Thalere412dc22018-01-12 16:28:24 -06002062 @param host: string, the hostname or IP address of the bmc
2063 @param args: contains additional arguments used by the gardClear sub command
2064 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002065 """
Justin Thalere412dc22018-01-12 16:28:24 -06002066 url="https://"+host+"/org/open_power/control/gard/action/Reset"
Justin Thalere412dc22018-01-12 16:28:24 -06002067 data = '{"data":[]}'
2068 try:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002069
Justin Thaler27197622019-01-23 14:42:11 -06002070 res = session.post(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002071 if res.status_code == 404:
2072 return "Command not supported by this firmware version"
2073 else:
2074 return res.text
2075 except(requests.exceptions.Timeout):
2076 return connectionErrHandler(args.json, "Timeout", None)
2077 except(requests.exceptions.ConnectionError) as err:
2078 return connectionErrHandler(args.json, "ConnectionError", err)
2079
2080def activateFWImage(host, args, session):
2081 """
2082 activates a firmware image on the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002083
Justin Thalere412dc22018-01-12 16:28:24 -06002084 @param host: string, the hostname or IP address of the bmc
2085 @param args: contains additional arguments used by the fwflash sub command
2086 @param session: the active session to use
2087 @param fwID: the unique ID of the fw image to activate
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002088 """
Justin Thalere412dc22018-01-12 16:28:24 -06002089 fwID = args.imageID
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002090
Justin Thalere412dc22018-01-12 16:28:24 -06002091 #determine the existing versions
Justin Thalere412dc22018-01-12 16:28:24 -06002092 url="https://"+host+"/xyz/openbmc_project/software/enumerate"
2093 try:
Justin Thaler27197622019-01-23 14:42:11 -06002094 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002095 except(requests.exceptions.Timeout):
2096 return connectionErrHandler(args.json, "Timeout", None)
2097 except(requests.exceptions.ConnectionError) as err:
2098 return connectionErrHandler(args.json, "ConnectionError", err)
2099 existingSoftware = json.loads(resp.text)['data']
2100 altVersionID = ''
2101 versionType = ''
2102 imageKey = '/xyz/openbmc_project/software/'+fwID
2103 if imageKey in existingSoftware:
2104 versionType = existingSoftware[imageKey]['Purpose']
2105 for key in existingSoftware:
2106 if imageKey == key:
2107 continue
2108 if 'Purpose' in existingSoftware[key]:
2109 if versionType == existingSoftware[key]['Purpose']:
2110 altVersionID = key.split('/')[-1]
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002111
2112
2113
2114
Justin Thalere412dc22018-01-12 16:28:24 -06002115 url="https://"+host+"/xyz/openbmc_project/software/"+ fwID + "/attr/Priority"
2116 url1="https://"+host+"/xyz/openbmc_project/software/"+ altVersionID + "/attr/Priority"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002117 data = "{\"data\": 0}"
Justin Thalere412dc22018-01-12 16:28:24 -06002118 data1 = "{\"data\": 1 }"
2119 try:
Justin Thaler27197622019-01-23 14:42:11 -06002120 resp = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
2121 resp1 = session.put(url1, headers=jsonHeader, data=data1, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002122 except(requests.exceptions.Timeout):
2123 return connectionErrHandler(args.json, "Timeout", None)
2124 except(requests.exceptions.ConnectionError) as err:
2125 return connectionErrHandler(args.json, "ConnectionError", err)
2126 if(not args.json):
2127 if resp.status_code == 200 and resp1.status_code == 200:
Justin Thaler22b1bb52018-03-15 13:31:32 -05002128 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 -06002129 else:
2130 return "Firmware activation failed."
2131 else:
2132 return resp.text + resp1.text
Justin Thaler22b1bb52018-03-15 13:31:32 -05002133
2134def activateStatus(host, args, session):
2135 if checkFWactivation(host, args, session):
2136 return("Firmware is currently being activated. Do not reboot the BMC or start the Host OS")
2137 else:
2138 return("No firmware activations are pending")
2139
2140def extractFWimage(path, imageType):
2141 """
2142 extracts the bmc image and returns information about the package
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002143
Justin Thaler22b1bb52018-03-15 13:31:32 -05002144 @param path: the path and file name of the firmware image
2145 @param imageType: The type of image the user is trying to flash. Host or BMC
2146 @return: the image id associated with the package. returns an empty string on error.
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002147 """
Justin Thaler22b1bb52018-03-15 13:31:32 -05002148 f = tempfile.TemporaryFile()
2149 tmpDir = tempfile.gettempdir()
2150 newImageID = ""
2151 if os.path.exists(path):
2152 try:
2153 imageFile = tarfile.open(path,'r')
2154 contents = imageFile.getmembers()
2155 for tf in contents:
2156 if 'MANIFEST' in tf.name:
2157 imageFile.extract(tf.name, path=tmpDir)
2158 with open(tempfile.gettempdir() +os.sep+ tf.name, 'r') as imageInfo:
2159 for line in imageInfo:
2160 if 'purpose' in line:
2161 purpose = line.split('=')[1]
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002162 if imageType not in purpose.split('.')[-1]:
Justin Thaler22b1bb52018-03-15 13:31:32 -05002163 print('The specified image is not for ' + imageType)
2164 print('Please try again with the image for ' + imageType)
2165 return ""
2166 if 'version' == line.split('=')[0]:
2167 version = line.split('=')[1].strip().encode('utf-8')
2168 m = hashlib.sha512()
2169 m.update(version)
2170 newImageID = m.hexdigest()[:8]
2171 break
2172 try:
2173 os.remove(tempfile.gettempdir() +os.sep+ tf.name)
2174 except OSError:
2175 pass
2176 return newImageID
2177 except tarfile.ExtractError as e:
2178 print('Unable to extract information from the firmware file.')
2179 print('Ensure you have write access to the directory: ' + tmpDir)
2180 return newImageID
2181 except tarfile.TarError as e:
2182 print('This is not a valid firmware file.')
2183 return newImageID
2184 print("This is not a valid firmware file.")
2185 return newImageID
2186 else:
2187 print('The filename and path provided are not valid.')
2188 return newImageID
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002189
Justin Thaler22b1bb52018-03-15 13:31:32 -05002190def getAllFWImageIDs(fwInvDict):
2191 """
2192 gets a list of all the firmware image IDs
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002193
Justin Thaler22b1bb52018-03-15 13:31:32 -05002194 @param fwInvDict: the dictionary to search for FW image IDs
2195 @return: list containing string representation of the found image ids
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002196 """
Justin Thaler22b1bb52018-03-15 13:31:32 -05002197 idList = []
2198 for key in fwInvDict:
2199 if 'Version' in fwInvDict[key]:
2200 idList.append(key.split('/')[-1])
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002201 return idList
2202
Justin Thalere412dc22018-01-12 16:28:24 -06002203def fwFlash(host, args, session):
2204 """
2205 updates the bmc firmware and pnor firmware
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002206
Justin Thalere412dc22018-01-12 16:28:24 -06002207 @param host: string, the hostname or IP address of the bmc
2208 @param args: contains additional arguments used by the fwflash sub command
2209 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002210 """
Justin Thaler22b1bb52018-03-15 13:31:32 -05002211 d = vars(args)
Justin Thalere412dc22018-01-12 16:28:24 -06002212 if(args.type == 'bmc'):
2213 purp = 'BMC'
2214 else:
2215 purp = 'Host'
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002216
2217 #check power state of the machine. No concurrent FW updates allowed
Justin Thaler22b1bb52018-03-15 13:31:32 -05002218 d['powcmd'] = 'status'
2219 powerstate = chassisPower(host, args, session)
2220 if 'Chassis Power State: On' in powerstate:
2221 return("Aborting firmware update. Host is powered on. Please turn off the host and try again.")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002222
Justin Thaler22b1bb52018-03-15 13:31:32 -05002223 #determine the existing images on the bmc
Justin Thalere412dc22018-01-12 16:28:24 -06002224 url="https://"+host+"/xyz/openbmc_project/software/enumerate"
2225 try:
Justin Thaler27197622019-01-23 14:42:11 -06002226 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002227 except(requests.exceptions.Timeout):
2228 return connectionErrHandler(args.json, "Timeout", None)
2229 except(requests.exceptions.ConnectionError) as err:
2230 return connectionErrHandler(args.json, "ConnectionError", err)
2231 oldsoftware = json.loads(resp.text)['data']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002232
Justin Thaler22b1bb52018-03-15 13:31:32 -05002233 #Extract the tar and get information from the manifest file
2234 newversionID = extractFWimage(args.fileloc, purp)
2235 if newversionID == "":
2236 return "Unable to verify FW image."
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002237
2238
Justin Thaler22b1bb52018-03-15 13:31:32 -05002239 #check if the new image is already on the bmc
2240 if newversionID not in getAllFWImageIDs(oldsoftware):
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002241
Justin Thaler22b1bb52018-03-15 13:31:32 -05002242 #upload the file
2243 httpHeader = {'Content-Type':'application/octet-stream'}
Matt Spinler220c3c42019-01-04 15:09:29 -06002244 httpHeader.update(xAuthHeader)
Justin Thaler22b1bb52018-03-15 13:31:32 -05002245 url="https://"+host+"/upload/image"
2246 data=open(args.fileloc,'rb').read()
2247 print("Uploading file to BMC")
Justin Thalere412dc22018-01-12 16:28:24 -06002248 try:
Justin Thaler22b1bb52018-03-15 13:31:32 -05002249 resp = session.post(url, headers=httpHeader, data=data, verify=False)
Justin Thalere412dc22018-01-12 16:28:24 -06002250 except(requests.exceptions.Timeout):
2251 return connectionErrHandler(args.json, "Timeout", None)
2252 except(requests.exceptions.ConnectionError) as err:
2253 return connectionErrHandler(args.json, "ConnectionError", err)
Justin Thaler22b1bb52018-03-15 13:31:32 -05002254 if resp.status_code != 200:
2255 return "Failed to upload the file to the bmc"
Justin Thalere412dc22018-01-12 16:28:24 -06002256 else:
Justin Thaler22b1bb52018-03-15 13:31:32 -05002257 print("Upload complete.")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002258
Justin Thaler22b1bb52018-03-15 13:31:32 -05002259 #verify bmc processed the image
2260 software ={}
2261 for i in range(0, 5):
Justin Thaler22b1bb52018-03-15 13:31:32 -05002262 url="https://"+host+"/xyz/openbmc_project/software/enumerate"
2263 try:
Justin Thaler27197622019-01-23 14:42:11 -06002264 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thaler22b1bb52018-03-15 13:31:32 -05002265 except(requests.exceptions.Timeout):
2266 return connectionErrHandler(args.json, "Timeout", None)
2267 except(requests.exceptions.ConnectionError) as err:
2268 return connectionErrHandler(args.json, "ConnectionError", err)
2269 software = json.loads(resp.text)['data']
2270 #check if bmc is done processing the new image
2271 if (newversionID in getAllFWImageIDs(software)):
Justin Thalere412dc22018-01-12 16:28:24 -06002272 break
Justin Thaler22b1bb52018-03-15 13:31:32 -05002273 else:
2274 time.sleep(15)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002275
Justin Thaler22b1bb52018-03-15 13:31:32 -05002276 #activate the new image
2277 print("Activating new image: "+newversionID)
2278 url="https://"+host+"/xyz/openbmc_project/software/"+ newversionID + "/attr/RequestedActivation"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002279 data = '{"data":"xyz.openbmc_project.Software.Activation.RequestedActivations.Active"}'
Justin Thaler22b1bb52018-03-15 13:31:32 -05002280 try:
Justin Thaler27197622019-01-23 14:42:11 -06002281 resp = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thaler22b1bb52018-03-15 13:31:32 -05002282 except(requests.exceptions.Timeout):
2283 return connectionErrHandler(args.json, "Timeout", None)
2284 except(requests.exceptions.ConnectionError) as err:
2285 return connectionErrHandler(args.json, "ConnectionError", err)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002286
Justin Thaler22b1bb52018-03-15 13:31:32 -05002287 #wait for the activation to complete, timeout after ~1 hour
2288 i=0
2289 while i < 360:
2290 url="https://"+host+"/xyz/openbmc_project/software/"+ newversionID
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002291 data = '{"data":"xyz.openbmc_project.Software.Activation.RequestedActivations.Active"}'
Justin Thaler22b1bb52018-03-15 13:31:32 -05002292 try:
Justin Thaler27197622019-01-23 14:42:11 -06002293 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thaler22b1bb52018-03-15 13:31:32 -05002294 except(requests.exceptions.Timeout):
2295 return connectionErrHandler(args.json, "Timeout", None)
2296 except(requests.exceptions.ConnectionError) as err:
2297 return connectionErrHandler(args.json, "ConnectionError", err)
2298 fwInfo = json.loads(resp.text)['data']
2299 if 'Activating' not in fwInfo['Activation'] and 'Activating' not in fwInfo['RequestedActivation']:
2300 print('')
2301 break
2302 else:
2303 sys.stdout.write('.')
2304 sys.stdout.flush()
2305 time.sleep(10) #check every 10 seconds
2306 return "Firmware flash and activation completed. Please reboot the bmc and then boot the host OS for the changes to take effect. "
2307 else:
2308 print("This image has been found on the bmc. Activating image: " + newversionID)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002309
Justin Thaler22b1bb52018-03-15 13:31:32 -05002310 d['imageID'] = newversionID
2311 return activateFWImage(host, args, session)
Justin Thalere412dc22018-01-12 16:28:24 -06002312
Justin Thaler3d71d402018-07-24 14:35:39 -05002313def getFWInventoryAttributes(rawFWInvItem, ID):
2314 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002315 gets and lists all of the firmware in the system.
2316
Justin Thaler3d71d402018-07-24 14:35:39 -05002317 @return: returns a dictionary containing the image attributes
2318 """
2319 reqActivation = rawFWInvItem["RequestedActivation"].split('.')[-1]
2320 pendingActivation = ""
2321 if reqActivation == "None":
2322 pendingActivation = "No"
2323 else:
2324 pendingActivation = "Yes"
2325 firmwareAttr = {ID: {
2326 "Purpose": rawFWInvItem["Purpose"].split('.')[-1],
2327 "Version": rawFWInvItem["Version"],
2328 "RequestedActivation": pendingActivation,
2329 "ID": ID}}
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002330
Justin Thaler3d71d402018-07-24 14:35:39 -05002331 if "ExtendedVersion" in rawFWInvItem:
2332 firmwareAttr[ID]['ExtendedVersion'] = rawFWInvItem['ExtendedVersion'].split(',')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002333 else:
Justin Thaler3d71d402018-07-24 14:35:39 -05002334 firmwareAttr[ID]['ExtendedVersion'] = ""
2335 return firmwareAttr
2336
2337def parseFWdata(firmwareDict):
2338 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002339 creates a dictionary with parsed firmware data
2340
Justin Thaler3d71d402018-07-24 14:35:39 -05002341 @return: returns a dictionary containing the image attributes
2342 """
2343 firmwareInfoDict = {"Functional": {}, "Activated":{}, "NeedsActivated":{}}
2344 for key in firmwareDict['data']:
2345 #check for valid endpoint
2346 if "Purpose" in firmwareDict['data'][key]:
2347 id = key.split('/')[-1]
2348 if firmwareDict['data'][key]['Activation'].split('.')[-1] == "Active":
2349 fwActivated = True
2350 else:
2351 fwActivated = False
Justin Thalercb68e062019-03-26 19:04:52 -05002352 if 'Priority' in firmwareDict['data'][key]:
2353 if firmwareDict['data'][key]['Priority'] == 0:
2354 firmwareInfoDict['Functional'].update(getFWInventoryAttributes(firmwareDict['data'][key], id))
2355 elif firmwareDict['data'][key]['Priority'] >= 0 and fwActivated:
2356 firmwareInfoDict['Activated'].update(getFWInventoryAttributes(firmwareDict['data'][key], id))
2357 else:
2358 firmwareInfoDict['NeedsActivated'].update(getFWInventoryAttributes(firmwareDict['data'][key], id))
Justin Thaler3d71d402018-07-24 14:35:39 -05002359 else:
Justin Thalercb68e062019-03-26 19:04:52 -05002360 firmwareInfoDict['NeedsActivated'].update(getFWInventoryAttributes(firmwareDict['data'][key], id))
Justin Thaler3d71d402018-07-24 14:35:39 -05002361 emptySections = []
2362 for key in firmwareInfoDict:
2363 if len(firmwareInfoDict[key])<=0:
2364 emptySections.append(key)
2365 for key in emptySections:
2366 del firmwareInfoDict[key]
2367 return firmwareInfoDict
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002368
Justin Thaler3d71d402018-07-24 14:35:39 -05002369def displayFWInvenory(firmwareInfoDict, args):
2370 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002371 gets and lists all of the firmware in the system.
2372
Justin Thaler3d71d402018-07-24 14:35:39 -05002373 @return: returns a string containing all of the firmware information
2374 """
2375 output = ""
2376 if not args.json:
2377 for key in firmwareInfoDict:
2378 for subkey in firmwareInfoDict[key]:
2379 firmwareInfoDict[key][subkey]['ExtendedVersion'] = str(firmwareInfoDict[key][subkey]['ExtendedVersion'])
2380 if not args.verbose:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002381 output = "---Running Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002382 colNames = ["Purpose", "Version", "ID"]
2383 keylist = ["Purpose", "Version", "ID"]
2384 output += tableDisplay(keylist, colNames, firmwareInfoDict["Functional"])
2385 if "Activated" in firmwareInfoDict:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002386 output += "\n---Available Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002387 output += tableDisplay(keylist, colNames, firmwareInfoDict["Activated"])
2388 if "NeedsActivated" in firmwareInfoDict:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002389 output += "\n---Needs Activated Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002390 output += tableDisplay(keylist, colNames, firmwareInfoDict["NeedsActivated"])
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002391
Justin Thaler3d71d402018-07-24 14:35:39 -05002392 else:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002393 output = "---Running Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002394 colNames = ["Purpose", "Version", "ID", "Pending Activation", "Extended Version"]
2395 keylist = ["Purpose", "Version", "ID", "RequestedActivation", "ExtendedVersion"]
2396 output += tableDisplay(keylist, colNames, firmwareInfoDict["Functional"])
2397 if "Activated" in firmwareInfoDict:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002398 output += "\n---Available Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002399 output += tableDisplay(keylist, colNames, firmwareInfoDict["Activated"])
2400 if "NeedsActivated" in firmwareInfoDict:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002401 output += "\n---Needs Activated Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002402 output += tableDisplay(keylist, colNames, firmwareInfoDict["NeedsActivated"])
2403 return output
2404 else:
2405 return str(json.dumps(firmwareInfoDict, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False))
2406
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002407def firmwareList(host, args, session):
Justin Thaler3d71d402018-07-24 14:35:39 -05002408 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002409 gets and lists all of the firmware in the system.
2410
Justin Thaler3d71d402018-07-24 14:35:39 -05002411 @return: returns a string containing all of the firmware information
2412 """
Justin Thaler3d71d402018-07-24 14:35:39 -05002413 url="https://{hostname}/xyz/openbmc_project/software/enumerate".format(hostname=host)
2414 try:
Justin Thaler27197622019-01-23 14:42:11 -06002415 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thaler3d71d402018-07-24 14:35:39 -05002416 except(requests.exceptions.Timeout):
2417 return(connectionErrHandler(args.json, "Timeout", None))
2418 firmwareDict = json.loads(res.text)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002419
Justin Thaler3d71d402018-07-24 14:35:39 -05002420 #sort the received information
2421 firmwareInfoDict = parseFWdata(firmwareDict)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002422
Justin Thaler3d71d402018-07-24 14:35:39 -05002423 #display the information
2424 return displayFWInvenory(firmwareInfoDict, args)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002425
2426
Adriana Kobylak5af2fad2018-11-08 12:33:43 -06002427def deleteFWVersion(host, args, session):
2428 """
2429 deletes a firmware version on the BMC
2430
2431 @param host: string, the hostname or IP address of the BMC
2432 @param args: contains additional arguments used by the fwflash sub command
2433 @param session: the active session to use
2434 @param fwID: the unique ID of the fw version to delete
2435 """
2436 fwID = args.versionID
2437
2438 print("Deleting version: "+fwID)
2439 url="https://"+host+"/xyz/openbmc_project/software/"+ fwID + "/action/Delete"
Adriana Kobylak5af2fad2018-11-08 12:33:43 -06002440 data = "{\"data\": [] }"
2441
2442 try:
Justin Thaler27197622019-01-23 14:42:11 -06002443 res = session.post(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Adriana Kobylak5af2fad2018-11-08 12:33:43 -06002444 except(requests.exceptions.Timeout):
2445 return(connectionErrHandler(args.json, "Timeout", None))
2446 if res.status_code == 200:
2447 return ('The firmware version has been deleted')
2448 else:
2449 return ('Unable to delete the specified firmware version')
2450
2451
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05002452def restLogging(host, args, session):
2453 """
2454 Called by the logging function. Turns REST API logging on/off.
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002455
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05002456 @param host: string, the hostname or IP address of the bmc
2457 @param args: contains additional arguments used by the logging sub command
2458 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002459 @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 -05002460 """
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05002461 url="https://"+host+"/xyz/openbmc_project/logging/rest_api_logs/attr/Enabled"
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05002462
2463 if(args.rest_logging == 'on'):
2464 data = '{"data": 1}'
2465 elif(args.rest_logging == 'off'):
2466 data = '{"data": 0}'
2467 else:
2468 return "Invalid logging rest_api command"
2469
2470 try:
Justin Thaler27197622019-01-23 14:42:11 -06002471 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05002472 except(requests.exceptions.Timeout):
2473 return(connectionErrHandler(args.json, "Timeout", None))
2474 return res.text
2475
2476
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002477def remoteLogging(host, args, session):
2478 """
2479 Called by the logging function. View config information for/disable remote logging (rsyslog).
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002480
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002481 @param host: string, the hostname or IP address of the bmc
2482 @param args: contains additional arguments used by the logging sub command
2483 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002484 @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 -05002485 """
2486
2487 url="https://"+host+"/xyz/openbmc_project/logging/config/remote"
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002488
2489 try:
2490 if(args.remote_logging == 'view'):
Justin Thaler27197622019-01-23 14:42:11 -06002491 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002492 elif(args.remote_logging == 'disable'):
Justin Thaler27197622019-01-23 14:42:11 -06002493 res = session.put(url + '/attr/Port', headers=jsonHeader, json = {"data": 0}, verify=False, timeout=baseTimeout)
2494 res = session.put(url + '/attr/Address', headers=jsonHeader, json = {"data": ""}, verify=False, timeout=baseTimeout)
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002495 else:
2496 return "Invalid logging remote_logging command"
2497 except(requests.exceptions.Timeout):
2498 return(connectionErrHandler(args.json, "Timeout", None))
2499 return res.text
2500
2501
2502def remoteLoggingConfig(host, args, session):
2503 """
2504 Called by the logging function. Configures remote logging (rsyslog).
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002505
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002506 @param host: string, the hostname or IP address of the bmc
2507 @param args: contains additional arguments used by the logging sub command
2508 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002509 @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 -05002510 """
2511
2512 url="https://"+host+"/xyz/openbmc_project/logging/config/remote"
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002513
2514 try:
Justin Thaler27197622019-01-23 14:42:11 -06002515 res = session.put(url + '/attr/Port', headers=jsonHeader, json = {"data": args.port}, verify=False, timeout=baseTimeout)
2516 res = session.put(url + '/attr/Address', headers=jsonHeader, json = {"data": args.address}, verify=False, timeout=baseTimeout)
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002517 except(requests.exceptions.Timeout):
2518 return(connectionErrHandler(args.json, "Timeout", None))
2519 return res.text
2520
Marri Devender Rao82590dc2019-06-06 04:54:22 -05002521def redfishSupportPresent(host, session):
2522 url = "https://" + host + "/redfish/v1"
2523 try:
2524 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
2525 except(requests.exceptions.Timeout):
2526 return False
2527 except(requests.exceptions.ConnectionError) as err:
2528 return False
2529 if resp.status_code != 200:
2530 return False
2531 else:
2532 return True
Ratan Gupta9166cd22018-10-01 18:09:40 +05302533
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002534def certificateUpdate(host, args, session):
2535 """
2536 Called by certificate management function. update server/client/authority certificates
2537 Example:
2538 certificate update server https -f cert.pem
2539 certificate update authority ldap -f Root-CA.pem
2540 certificate update client ldap -f cert.pem
2541 @param host: string, the hostname or IP address of the bmc
2542 @param args: contains additional arguments used by the certificate update sub command
2543 @param session: the active session to use
2544 """
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002545 httpHeader = {'Content-Type': 'application/octet-stream'}
Matt Spinler220c3c42019-01-04 15:09:29 -06002546 httpHeader.update(xAuthHeader)
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002547 data = open(args.fileloc, 'rb').read()
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002548 try:
Marri Devender Rao82590dc2019-06-06 04:54:22 -05002549 if redfishSupportPresent(host, session):
Marri Devender Rao62db08a2019-08-22 03:16:02 -05002550 if(args.type.lower() == 'server' and args.service.lower() != "https"):
2551 return "Invalid service type"
2552 if(args.type.lower() == 'client' and args.service.lower() != "ldap"):
2553 return "Invalid service type"
2554 if(args.type.lower() == 'authority' and args.service.lower() != "ldap"):
2555 return "Invalid service type"
Marri Devender Rao82590dc2019-06-06 04:54:22 -05002556 url = "";
2557 if(args.type.lower() == 'server'):
2558 url = "https://" + host + \
2559 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"
2560 elif(args.type.lower() == 'client'):
2561 url = "https://" + host + \
2562 "/redfish/v1/AccountService/LDAP/Certificates"
2563 elif(args.type.lower() == 'authority'):
2564 url = "https://" + host + \
2565 "/redfish/v1/Managers/bmc/Truststore/Certificates"
2566 else:
2567 return "Unsupported certificate type"
2568 resp = session.post(url, headers=httpHeader, data=data,
2569 verify=False)
2570 else:
2571 url = "https://" + host + "/xyz/openbmc_project/certs/" + \
2572 args.type.lower() + "/" + args.service.lower()
2573 resp = session.put(url, headers=httpHeader, data=data, verify=False)
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002574 except(requests.exceptions.Timeout):
2575 return(connectionErrHandler(args.json, "Timeout", None))
2576 except(requests.exceptions.ConnectionError) as err:
2577 return connectionErrHandler(args.json, "ConnectionError", err)
2578 if resp.status_code != 200:
2579 print(resp.text)
2580 return "Failed to update the certificate"
2581 else:
Marri Devender Rao82590dc2019-06-06 04:54:22 -05002582 print("Update complete.")
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002583
2584def certificateDelete(host, args, session):
2585 """
2586 Called by certificate management function to delete certificate
2587 Example:
2588 certificate delete server https
2589 certificate delete authority ldap
2590 certificate delete client ldap
2591 @param host: string, the hostname or IP address of the bmc
2592 @param args: contains additional arguments used by the certificate delete sub command
2593 @param session: the active session to use
2594 """
Marri Devender Rao77e78682019-07-17 03:18:35 -05002595 if redfishSupportPresent(host, session):
2596 return "Not supported, please use certificate replace instead";
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002597 httpHeader = {'Content-Type': 'multipart/form-data'}
Matt Spinler220c3c42019-01-04 15:09:29 -06002598 httpHeader.update(xAuthHeader)
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002599 url = "https://" + host + "/xyz/openbmc_project/certs/" + args.type.lower() + "/" + args.service.lower()
2600 print("Deleting certificate url=" + url)
2601 try:
2602 resp = session.delete(url, headers=httpHeader)
2603 except(requests.exceptions.Timeout):
2604 return(connectionErrHandler(args.json, "Timeout", None))
2605 except(requests.exceptions.ConnectionError) as err:
2606 return connectionErrHandler(args.json, "ConnectionError", err)
2607 if resp.status_code != 200:
2608 print(resp.text)
2609 return "Failed to delete the certificate"
2610 else:
Marri Devender Rao77e78682019-07-17 03:18:35 -05002611 print("Delete complete.")
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002612
Marri Devender Raodfe81ad2019-07-01 05:38:09 -05002613def certificateReplace(host, args, session):
2614 """
2615 Called by certificate management function. replace server/client/
2616 authority certificates
2617 Example:
2618 certificate replace server https -f cert.pem
2619 certificate replace authority ldap -f Root-CA.pem
2620 certificate replace client ldap -f cert.pem
2621 @param host: string, the hostname or IP address of the bmc
2622 @param args: contains additional arguments used by the certificate
2623 replace sub command
2624 @param session: the active session to use
2625 """
2626 cert = open(args.fileloc, 'rb').read()
2627 try:
2628 if redfishSupportPresent(host, session):
2629 httpHeader = {'Content-Type': 'application/json'}
2630 httpHeader.update(xAuthHeader)
2631 url = "";
Marri Devender Rao62db08a2019-08-22 03:16:02 -05002632 if(args.type.lower() == 'server' and args.service.lower() != "https"):
2633 return "Invalid service type"
2634 if(args.type.lower() == 'client' and args.service.lower() != "ldap"):
2635 return "Invalid service type"
2636 if(args.type.lower() == 'authority' and args.service.lower() != "ldap"):
2637 return "Invalid service type"
Marri Devender Raodfe81ad2019-07-01 05:38:09 -05002638 if(args.type.lower() == 'server'):
2639 url = "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/1"
2640 elif(args.type.lower() == 'client'):
2641 url = "/redfish/v1/AccountService/LDAP/Certificates/1"
2642 elif(args.type.lower() == 'authority'):
2643 url = "/redfish/v1/Managers/bmc/Truststore/Certificates/1"
2644 replaceUrl = "https://" + host + \
2645 "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate"
2646 data ={"CertificateUri":{"@odata.id":url}, "CertificateType":"PEM",
2647 "CertificateString":cert}
2648 resp = session.post(replaceUrl, headers=httpHeader, json=data, verify=False)
2649 else:
2650 httpHeader = {'Content-Type': 'application/octet-stream'}
2651 httpHeader.update(xAuthHeader)
2652 url = "https://" + host + "/xyz/openbmc_project/certs/" + \
2653 args.type.lower() + "/" + args.service.lower()
2654 resp = session.delete(url, headers=httpHeader)
2655 resp = session.put(url, headers=httpHeader, data=cert, verify=False)
2656 except(requests.exceptions.Timeout):
2657 return(connectionErrHandler(args.json, "Timeout", None))
2658 except(requests.exceptions.ConnectionError) as err:
2659 return connectionErrHandler(args.json, "ConnectionError", err)
2660 if resp.status_code != 200:
2661 print(resp.text)
2662 return "Failed to replace the certificate"
2663 else:
2664 print("Replace complete.")
2665 return resp.text
2666
Marri Devender Rao34646402019-07-01 05:46:03 -05002667def certificateDisplay(host, args, session):
2668 """
2669 Called by certificate management function. display server/client/
2670 authority certificates
2671 Example:
2672 certificate display server
2673 certificate display authority
2674 certificate display client
2675 @param host: string, the hostname or IP address of the bmc
2676 @param args: contains additional arguments used by the certificate
2677 display sub command
2678 @param session: the active session to use
2679 """
2680 if not redfishSupportPresent(host, session):
2681 return "Not supported";
2682
2683 httpHeader = {'Content-Type': 'application/octet-stream'}
2684 httpHeader.update(xAuthHeader)
2685 if(args.type.lower() == 'server'):
2686 url = "https://" + host + \
2687 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/1"
2688 elif(args.type.lower() == 'client'):
2689 url = "https://" + host + \
2690 "/redfish/v1/AccountService/LDAP/Certificates/1"
2691 elif(args.type.lower() == 'authority'):
2692 url = "https://" + host + \
2693 "/redfish/v1/Managers/bmc/Truststore/Certificates/1"
2694 try:
2695 resp = session.get(url, headers=httpHeader, verify=False)
2696 except(requests.exceptions.Timeout):
2697 return(connectionErrHandler(args.json, "Timeout", None))
2698 except(requests.exceptions.ConnectionError) as err:
2699 return connectionErrHandler(args.json, "ConnectionError", err)
2700 if resp.status_code != 200:
2701 print(resp.text)
2702 return "Failed to display the certificate"
2703 else:
2704 print("Display complete.")
2705 return resp.text
2706
Marri Devender Raoa208ff82019-07-01 05:51:27 -05002707def certificateList(host, args, session):
2708 """
2709 Called by certificate management function.
2710 Example:
2711 certificate list
2712 @param host: string, the hostname or IP address of the bmc
2713 @param args: contains additional arguments used by the certificate
2714 list sub command
2715 @param session: the active session to use
2716 """
2717 if not redfishSupportPresent(host, session):
2718 return "Not supported";
2719
2720 httpHeader = {'Content-Type': 'application/octet-stream'}
2721 httpHeader.update(xAuthHeader)
2722 url = "https://" + host + \
2723 "/redfish/v1/CertificateService/CertificateLocations/"
2724 try:
2725 resp = session.get(url, headers=httpHeader, verify=False)
2726 except(requests.exceptions.Timeout):
2727 return(connectionErrHandler(args.json, "Timeout", None))
2728 except(requests.exceptions.ConnectionError) as err:
2729 return connectionErrHandler(args.json, "ConnectionError", err)
2730 if resp.status_code != 200:
2731 print(resp.text)
2732 return "Failed to list certificates"
2733 else:
2734 print("List certificates complete.")
2735 return resp.text
2736
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05002737def certificateGenerateCSR(host, args, session):
2738 """
2739 Called by certificate management function. Generate CSR for server/
2740 client certificates
2741 Example:
Marri Devender Raodf0e1a42019-09-09 08:18:27 -05002742 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
2743 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 -05002744 @param host: string, the hostname or IP address of the bmc
2745 @param args: contains additional arguments used by the certificate replace sub command
2746 @param session: the active session to use
2747 """
2748 if not redfishSupportPresent(host, session):
2749 return "Not supported";
2750
2751 httpHeader = {'Content-Type': 'application/octet-stream'}
2752 httpHeader.update(xAuthHeader)
2753 url = "";
2754 if(args.type.lower() == 'server'):
2755 url = "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/"
Marri Devender Rao88064f02019-08-19 09:00:30 -05002756 usage_list = ["ServerAuthentication"]
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05002757 elif(args.type.lower() == 'client'):
2758 url = "/redfish/v1/AccountService/LDAP/Certificates/"
Marri Devender Rao88064f02019-08-19 09:00:30 -05002759 usage_list = ["ClientAuthentication"]
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05002760 elif(args.type.lower() == 'authority'):
2761 url = "/redfish/v1/Managers/bmc/Truststore/Certificates/"
2762 print("Generating CSR url=" + url)
2763 generateCSRUrl = "https://" + host + \
2764 "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR"
2765 try:
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05002766 alt_name_list = args.alternativeNames.split(",")
2767 data ={"CertificateCollection":{"@odata.id":url},
2768 "CommonName":args.commonName, "City":args.city,
2769 "Country":args.country, "Organization":args.organization,
2770 "OrganizationalUnit":args.organizationUnit, "State":args.state,
Marri Devender Raodf0e1a42019-09-09 08:18:27 -05002771 "KeyPairAlgorithm":args.keyPairAlgorithm, "KeyCurveId":args.keyCurveId,
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05002772 "AlternativeNames":alt_name_list, "ContactPerson":args.contactPerson,
2773 "Email":args.email, "GivenName":args.givenname, "Initials":args.initials,
2774 "KeyUsage":usage_list, "Surname":args.surname,
2775 "UnstructuredName":args.unstructuredname}
2776 resp = session.post(generateCSRUrl, headers=httpHeader,
2777 json=data, verify=False)
2778 except(requests.exceptions.Timeout):
2779 return(connectionErrHandler(args.json, "Timeout", None))
2780 except(requests.exceptions.ConnectionError) as err:
2781 return connectionErrHandler(args.json, "ConnectionError", err)
2782 if resp.status_code != 200:
2783 print(resp.text)
2784 return "Failed to generate CSR"
2785 else:
2786 print("GenerateCSR complete.")
2787 return resp.text
2788
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05002789def enableLDAPConfig(host, args, session):
Ratan Gupta9166cd22018-10-01 18:09:40 +05302790 """
2791 Called by the ldap function. Configures LDAP.
2792
2793 @param host: string, the hostname or IP address of the bmc
2794 @param args: contains additional arguments used by the ldap subcommand
2795 @param session: the active session to use
2796 @param args.json: boolean, if this flag is set to true, the output will
2797 be provided in json format for programmatic consumption
2798 """
2799
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05002800 if(isRedfishSupport):
2801 return enableLDAP(host, args, session)
2802 else:
2803 return enableLegacyLDAP(host, args, session)
2804
2805def enableLegacyLDAP(host, args, session):
2806 """
2807 Called by the ldap function. Configures LDAP on Lagecy systems.
2808
2809 @param host: string, the hostname or IP address of the bmc
2810 @param args: contains additional arguments used by the ldap subcommand
2811 @param session: the active session to use
2812 @param args.json: boolean, if this flag is set to true, the output will
2813 be provided in json format for programmatic consumption
2814 """
2815
Ratan Gupta9166cd22018-10-01 18:09:40 +05302816 url='https://'+host+'/xyz/openbmc_project/user/ldap/action/CreateConfig'
Ratan Gupta9166cd22018-10-01 18:09:40 +05302817 scope = {
2818 'sub' : 'xyz.openbmc_project.User.Ldap.Create.SearchScope.sub',
2819 'one' : 'xyz.openbmc_project.User.Ldap.Create.SearchScope.one',
2820 'base': 'xyz.openbmc_project.User.Ldap.Create.SearchScope.base'
2821 }
2822
2823 serverType = {
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05002824 'ActiveDirectory' : 'xyz.openbmc_project.User.Ldap.Create.Type.ActiveDirectory',
2825 'OpenLDAP' : 'xyz.openbmc_project.User.Ldap.Create.Type.OpenLdap'
Ratan Gupta9166cd22018-10-01 18:09:40 +05302826 }
2827
2828 data = {"data": [args.uri, args.bindDN, args.baseDN, args.bindPassword, scope[args.scope], serverType[args.serverType]]}
2829
2830 try:
Justin Thaler27197622019-01-23 14:42:11 -06002831 res = session.post(url, headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
Ratan Gupta9166cd22018-10-01 18:09:40 +05302832 except(requests.exceptions.Timeout):
2833 return(connectionErrHandler(args.json, "Timeout", None))
2834 except(requests.exceptions.ConnectionError) as err:
2835 return connectionErrHandler(args.json, "ConnectionError", err)
2836
2837 return res.text
2838
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05002839def enableLDAP(host, args, session):
2840 """
2841 Called by the ldap function. Configures LDAP for systems with latest user-manager design changes
2842
2843 @param host: string, the hostname or IP address of the bmc
2844 @param args: contains additional arguments used by the ldap subcommand
2845 @param session: the active session to use
2846 @param args.json: boolean, if this flag is set to true, the output will
2847 be provided in json format for programmatic consumption
2848 """
2849
2850 scope = {
2851 'sub' : 'xyz.openbmc_project.User.Ldap.Config.SearchScope.sub',
2852 'one' : 'xyz.openbmc_project.User.Ldap.Config.SearchScope.one',
2853 'base': 'xyz.openbmc_project.User.Ldap.Config.SearchScope.base'
2854 }
2855
2856 serverType = {
2857 'ActiveDirectory' : 'xyz.openbmc_project.User.Ldap.Config.Type.ActiveDirectory',
2858 'OpenLDAP' : 'xyz.openbmc_project.User.Ldap.Config.Type.OpenLdap'
2859 }
2860
2861 url = "https://"+host+"/xyz/openbmc_project/user/ldap/"
2862
2863 serverTypeEnabled = getLDAPTypeEnabled(host,session)
2864 serverTypeToBeEnabled = args.serverType
2865
2866 #If the given LDAP type is already enabled, then return
2867 if (serverTypeToBeEnabled == serverTypeEnabled):
2868 return("Server type " + serverTypeToBeEnabled + " is already enabled...")
2869
2870 try:
2871
2872 # Copy the role map from the currently enabled LDAP server type
2873 # to the newly enabled server type
2874 # Disable the currently enabled LDAP server type. Unless
2875 # it is disabled, we cannot enable a new LDAP server type
2876 if (serverTypeEnabled is not None):
2877
2878 if (serverTypeToBeEnabled != serverTypeEnabled):
2879 res = syncRoleMap(host,args,session,serverTypeEnabled,serverTypeToBeEnabled)
2880
2881 data = "{\"data\": 0 }"
2882 res = session.put(url + serverTypeMap[serverTypeEnabled] + '/attr/Enabled', headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
2883
2884 data = {"data": args.baseDN}
2885 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/LDAPBaseDN', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
2886 if (res.status_code != requests.codes.ok):
2887 print("Updates to the property LDAPBaseDN failed...")
2888 return(res.text)
2889
2890 data = {"data": args.bindDN}
2891 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/LDAPBindDN', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
2892 if (res.status_code != requests.codes.ok):
2893 print("Updates to the property LDAPBindDN failed...")
2894 return(res.text)
2895
2896 data = {"data": args.bindPassword}
2897 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/LDAPBindDNPassword', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
2898 if (res.status_code != requests.codes.ok):
2899 print("Updates to the property LDAPBindDNPassword failed...")
2900 return(res.text)
2901
2902 data = {"data": scope[args.scope]}
2903 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/LDAPSearchScope', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
2904 if (res.status_code != requests.codes.ok):
2905 print("Updates to the property LDAPSearchScope failed...")
2906 return(res.text)
2907
2908 data = {"data": args.uri}
2909 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/LDAPServerURI', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
2910 if (res.status_code != requests.codes.ok):
2911 print("Updates to the property LDAPServerURI failed...")
2912 return(res.text)
2913
2914 data = {"data": args.groupAttrName}
2915 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/GroupNameAttribute', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
2916 if (res.status_code != requests.codes.ok):
2917 print("Updates to the property GroupNameAttribute failed...")
2918 return(res.text)
2919
2920 data = {"data": args.userAttrName}
2921 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/UserNameAttribute', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
2922 if (res.status_code != requests.codes.ok):
2923 print("Updates to the property UserNameAttribute failed...")
2924 return(res.text)
2925
2926 #After updating the properties, enable the new server type
2927 data = "{\"data\": 1 }"
2928 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/Enabled', headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
2929
2930 except(requests.exceptions.Timeout):
2931 return(connectionErrHandler(args.json, "Timeout", None))
2932 except(requests.exceptions.ConnectionError) as err:
2933 return connectionErrHandler(args.json, "ConnectionError", err)
2934 return res.text
Ratan Gupta9166cd22018-10-01 18:09:40 +05302935
2936def disableLDAP(host, args, session):
2937 """
2938 Called by the ldap function. Deletes the LDAP Configuration.
2939
2940 @param host: string, the hostname or IP address of the bmc
2941 @param args: contains additional arguments used by the ldap subcommand
2942 @param session: the active session to use
2943 @param args.json: boolean, if this flag is set to true, the output
2944 will be provided in json format for programmatic consumption
2945 """
2946
Ratan Gupta9166cd22018-10-01 18:09:40 +05302947 try:
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05002948 if (isRedfishSupport) :
2949
2950 url = "https://"+host+"/xyz/openbmc_project/user/ldap/"
2951
2952 serverTypeEnabled = getLDAPTypeEnabled(host,session)
2953
2954 if (serverTypeEnabled is not None):
2955 #To keep the role map in sync,
2956 #If the server type being disabled has role map, then
2957 # - copy the role map to the other server type(s)
2958 for serverType in serverTypeMap.keys():
2959 if (serverType != serverTypeEnabled):
2960 res = syncRoleMap(host,args,session,serverTypeEnabled,serverType)
2961
2962 #Disable the currently enabled LDAP server type
2963 data = "{\"data\": 0 }"
2964 res = session.put(url + serverTypeMap[serverTypeEnabled] + '/attr/Enabled', headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
2965
2966 else:
2967 return("LDAP server has not been enabled...")
2968
2969 else :
2970 url='https://'+host+'/xyz/openbmc_project/user/ldap/config/action/delete'
2971 data = {"data": []}
2972 res = session.post(url, headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
2973
Ratan Gupta9166cd22018-10-01 18:09:40 +05302974 except(requests.exceptions.Timeout):
2975 return(connectionErrHandler(args.json, "Timeout", None))
2976 except(requests.exceptions.ConnectionError) as err:
2977 return connectionErrHandler(args.json, "ConnectionError", err)
2978
2979 return res.text
2980
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06002981def enableDHCP(host, args, session):
2982
2983 """
2984 Called by the network function. Enables DHCP.
2985
2986 @param host: string, the hostname or IP address of the bmc
2987 @param args: contains additional arguments used by the ldap subcommand
2988 args.json: boolean, if this flag is set to true, the output
2989 will be provided in json format for programmatic consumption
2990 @param session: the active session to use
2991 """
2992
2993 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
2994 "/attr/DHCPEnabled"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06002995 data = "{\"data\": 1 }"
2996 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06002997 res = session.put(url, headers=jsonHeader, data=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06002998 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06002999
3000 except(requests.exceptions.Timeout):
3001 return(connectionErrHandler(args.json, "Timeout", None))
3002 except(requests.exceptions.ConnectionError) as err:
3003 return connectionErrHandler(args.json, "ConnectionError", err)
3004 if res.status_code == 403:
3005 return "The specified Interface"+"("+args.Interface+")"+\
3006 " doesn't exist"
3007
3008 return res.text
3009
3010
3011def disableDHCP(host, args, session):
3012 """
3013 Called by the network function. Disables DHCP.
3014
3015 @param host: string, the hostname or IP address of the bmc
3016 @param args: contains additional arguments used by the ldap subcommand
3017 args.json: boolean, if this flag is set to true, the output
3018 will be provided in json format for programmatic consumption
3019 @param session: the active session to use
3020 """
3021
3022 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3023 "/attr/DHCPEnabled"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003024 data = "{\"data\": 0 }"
3025 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003026 res = session.put(url, headers=jsonHeader, data=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003027 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003028 except(requests.exceptions.Timeout):
3029 return(connectionErrHandler(args.json, "Timeout", None))
3030 except(requests.exceptions.ConnectionError) as err:
3031 return connectionErrHandler(args.json, "ConnectionError", err)
3032 if res.status_code == 403:
3033 return "The specified Interface"+"("+args.Interface+")"+\
3034 " doesn't exist"
3035 return res.text
3036
3037
3038def getHostname(host, args, session):
3039
3040 """
3041 Called by the network function. Prints out the Hostname.
3042
3043 @param host: string, the hostname or IP address of the bmc
3044 @param args: contains additional arguments used by the ldap subcommand
3045 args.json: boolean, if this flag is set to true, the output
3046 will be provided in json format for programmatic consumption
3047 @param session: the active session to use
3048 """
3049
3050 url = "https://"+host+"/xyz/openbmc_project/network/config/attr/HostName"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003051
3052 try:
Justin Thaler27197622019-01-23 14:42:11 -06003053 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003054 except(requests.exceptions.Timeout):
3055 return(connectionErrHandler(args.json, "Timeout", None))
3056 except(requests.exceptions.ConnectionError) as err:
3057 return connectionErrHandler(args.json, "ConnectionError", err)
3058
3059 return res.text
3060
3061
3062def setHostname(host, args, session):
3063 """
3064 Called by the network function. Sets the Hostname.
3065
3066 @param host: string, the hostname or IP address of the bmc
3067 @param args: contains additional arguments used by the ldap subcommand
3068 args.json: boolean, if this flag is set to true, the output
3069 will be provided in json format for programmatic consumption
3070 @param session: the active session to use
3071 """
3072
3073 url = "https://"+host+"/xyz/openbmc_project/network/config/attr/HostName"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003074
3075 data = {"data": args.HostName}
3076
3077 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003078 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003079 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003080 except(requests.exceptions.Timeout):
3081 return(connectionErrHandler(args.json, "Timeout", None))
3082 except(requests.exceptions.ConnectionError) as err:
3083 return connectionErrHandler(args.json, "ConnectionError", err)
3084
3085 return res.text
3086
3087
3088def getDomainName(host, args, session):
3089
3090 """
3091 Called by the network function. Prints out the DomainName.
3092
3093 @param host: string, the hostname or IP address of the bmc
3094 @param args: contains additional arguments used by the ldap subcommand
3095 args.json: boolean, if this flag is set to true, the output
3096 will be provided in json format for programmatic consumption
3097 @param session: the active session to use
3098 """
3099
3100 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3101 "/attr/DomainName"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003102
3103 try:
Justin Thaler27197622019-01-23 14:42:11 -06003104 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003105 except(requests.exceptions.Timeout):
3106 return(connectionErrHandler(args.json, "Timeout", None))
3107 except(requests.exceptions.ConnectionError) as err:
3108 return connectionErrHandler(args.json, "ConnectionError", err)
3109 if res.status_code == 404:
3110 return "The specified Interface"+"("+args.Interface+")"+\
3111 " doesn't exist"
3112
3113 return res.text
3114
3115
3116def setDomainName(host, args, session):
3117 """
3118 Called by the network function. Sets the DomainName.
3119
3120 @param host: string, the hostname or IP address of the bmc
3121 @param args: contains additional arguments used by the ldap subcommand
3122 args.json: boolean, if this flag is set to true, the output
3123 will be provided in json format for programmatic consumption
3124 @param session: the active session to use
3125 """
3126
3127 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3128 "/attr/DomainName"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003129
3130 data = {"data": args.DomainName.split(",")}
3131
3132 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003133 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003134 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003135 except(requests.exceptions.Timeout):
3136 return(connectionErrHandler(args.json, "Timeout", None))
3137 except(requests.exceptions.ConnectionError) as err:
3138 return connectionErrHandler(args.json, "ConnectionError", err)
3139 if res.status_code == 403:
3140 return "The specified Interface"+"("+args.Interface+")"+\
3141 " doesn't exist"
3142
3143 return res.text
3144
3145
3146def getMACAddress(host, args, session):
3147
3148 """
3149 Called by the network function. Prints out the MACAddress.
3150
3151 @param host: string, the hostname or IP address of the bmc
3152 @param args: contains additional arguments used by the ldap subcommand
3153 args.json: boolean, if this flag is set to true, the output
3154 will be provided in json format for programmatic consumption
3155 @param session: the active session to use
3156 """
3157
3158 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3159 "/attr/MACAddress"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003160
3161 try:
Justin Thaler27197622019-01-23 14:42:11 -06003162 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003163 except(requests.exceptions.Timeout):
3164 return(connectionErrHandler(args.json, "Timeout", None))
3165 except(requests.exceptions.ConnectionError) as err:
3166 return connectionErrHandler(args.json, "ConnectionError", err)
3167 if res.status_code == 404:
3168 return "The specified Interface"+"("+args.Interface+")"+\
3169 " doesn't exist"
3170
3171 return res.text
3172
3173
3174def setMACAddress(host, args, session):
3175 """
3176 Called by the network function. Sets the MACAddress.
3177
3178 @param host: string, the hostname or IP address of the bmc
3179 @param args: contains additional arguments used by the ldap subcommand
3180 args.json: boolean, if this flag is set to true, the output
3181 will be provided in json format for programmatic consumption
3182 @param session: the active session to use
3183 """
3184
3185 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3186 "/attr/MACAddress"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003187
3188 data = {"data": args.MACAddress}
3189
3190 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003191 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003192 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003193 except(requests.exceptions.Timeout):
3194 return(connectionErrHandler(args.json, "Timeout", None))
3195 except(requests.exceptions.ConnectionError) as err:
3196 return connectionErrHandler(args.json, "ConnectionError", err)
3197 if res.status_code == 403:
3198 return "The specified Interface"+"("+args.Interface+")"+\
3199 " doesn't exist"
3200
3201 return res.text
3202
3203
3204def getDefaultGateway(host, args, session):
3205
3206 """
3207 Called by the network function. Prints out the DefaultGateway.
3208
3209 @param host: string, the hostname or IP address of the bmc
3210 @param args: contains additional arguments used by the ldap subcommand
3211 args.json: boolean, if this flag is set to true, the output
3212 will be provided in json format for programmatic consumption
3213 @param session: the active session to use
3214 """
3215
3216 url = "https://"+host+"/xyz/openbmc_project/network/config/attr/DefaultGateway"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003217
3218 try:
Justin Thaler27197622019-01-23 14:42:11 -06003219 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003220 except(requests.exceptions.Timeout):
3221 return(connectionErrHandler(args.json, "Timeout", None))
3222 except(requests.exceptions.ConnectionError) as err:
3223 return connectionErrHandler(args.json, "ConnectionError", err)
3224 if res.status_code == 404:
3225 return "Failed to get Default Gateway info!!"
3226
3227 return res.text
3228
3229
3230def setDefaultGateway(host, args, session):
3231 """
3232 Called by the network function. Sets the DefaultGateway.
3233
3234 @param host: string, the hostname or IP address of the bmc
3235 @param args: contains additional arguments used by the ldap subcommand
3236 args.json: boolean, if this flag is set to true, the output
3237 will be provided in json format for programmatic consumption
3238 @param session: the active session to use
3239 """
3240
3241 url = "https://"+host+"/xyz/openbmc_project/network/config/attr/DefaultGateway"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003242
3243 data = {"data": args.DefaultGW}
3244
3245 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003246 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003247 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003248 except(requests.exceptions.Timeout):
3249 return(connectionErrHandler(args.json, "Timeout", None))
3250 except(requests.exceptions.ConnectionError) as err:
3251 return connectionErrHandler(args.json, "ConnectionError", err)
3252 if res.status_code == 403:
3253 return "Failed to set Default Gateway!!"
3254
3255 return res.text
3256
3257
3258def viewNWConfig(host, args, session):
3259 """
3260 Called by the ldap function. Prints out network configured properties
3261
3262 @param host: string, the hostname or IP address of the bmc
3263 @param args: contains additional arguments used by the ldap subcommand
3264 args.json: boolean, if this flag is set to true, the output
3265 will be provided in json format for programmatic consumption
3266 @param session: the active session to use
3267 @return returns LDAP's configured properties.
3268 """
3269 url = "https://"+host+"/xyz/openbmc_project/network/enumerate"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003270 try:
Justin Thaler27197622019-01-23 14:42:11 -06003271 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003272 except(requests.exceptions.Timeout):
3273 return(connectionErrHandler(args.json, "Timeout", None))
3274 except(requests.exceptions.ConnectionError) as err:
3275 return connectionErrHandler(args.json, "ConnectionError", err)
3276 except(requests.exceptions.RequestException) as err:
3277 return connectionErrHandler(args.json, "RequestException", err)
3278 if res.status_code == 404:
3279 return "LDAP server config has not been created"
3280 return res.text
3281
3282
3283def getDNS(host, args, session):
3284
3285 """
3286 Called by the network function. Prints out DNS servers on the interface
3287
3288 @param host: string, the hostname or IP address of the bmc
3289 @param args: contains additional arguments used by the ldap subcommand
3290 args.json: boolean, if this flag is set to true, the output
3291 will be provided in json format for programmatic consumption
3292 @param session: the active session to use
3293 """
3294
3295 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
3296 + "/attr/Nameservers"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003297
3298 try:
Justin Thaler27197622019-01-23 14:42:11 -06003299 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003300 except(requests.exceptions.Timeout):
3301 return(connectionErrHandler(args.json, "Timeout", None))
3302 except(requests.exceptions.ConnectionError) as err:
3303 return connectionErrHandler(args.json, "ConnectionError", err)
3304 if res.status_code == 404:
3305 return "The specified Interface"+"("+args.Interface+")" + \
3306 " doesn't exist"
3307
3308 return res.text
3309
3310
3311def setDNS(host, args, session):
3312 """
3313 Called by the network function. Sets DNS servers on the interface.
3314
3315 @param host: string, the hostname or IP address of the bmc
3316 @param args: contains additional arguments used by the ldap subcommand
3317 args.json: boolean, if this flag is set to true, the output
3318 will be provided in json format for programmatic consumption
3319 @param session: the active session to use
3320 """
3321
3322 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
3323 + "/attr/Nameservers"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003324
3325 data = {"data": args.DNSServers.split(",")}
3326
3327 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003328 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003329 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003330 except(requests.exceptions.Timeout):
3331 return(connectionErrHandler(args.json, "Timeout", None))
3332 except(requests.exceptions.ConnectionError) as err:
3333 return connectionErrHandler(args.json, "ConnectionError", err)
3334 if res.status_code == 403:
3335 return "The specified Interface"+"("+args.Interface+")" +\
3336 " doesn't exist"
3337
3338 return res.text
3339
3340
3341def getNTP(host, args, session):
3342
3343 """
3344 Called by the network function. Prints out NTP servers on the interface
3345
3346 @param host: string, the hostname or IP address of the bmc
3347 @param args: contains additional arguments used by the ldap subcommand
3348 args.json: boolean, if this flag is set to true, the output
3349 will be provided in json format for programmatic consumption
3350 @param session: the active session to use
3351 """
3352
3353 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
3354 + "/attr/NTPServers"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003355
3356 try:
Justin Thaler27197622019-01-23 14:42:11 -06003357 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003358 except(requests.exceptions.Timeout):
3359 return(connectionErrHandler(args.json, "Timeout", None))
3360 except(requests.exceptions.ConnectionError) as err:
3361 return connectionErrHandler(args.json, "ConnectionError", err)
3362 if res.status_code == 404:
3363 return "The specified Interface"+"("+args.Interface+")" + \
3364 " doesn't exist"
3365
3366 return res.text
3367
3368
3369def setNTP(host, args, session):
3370 """
3371 Called by the network function. Sets NTP servers on the interface.
3372
3373 @param host: string, the hostname or IP address of the bmc
3374 @param args: contains additional arguments used by the ldap subcommand
3375 args.json: boolean, if this flag is set to true, the output
3376 will be provided in json format for programmatic consumption
3377 @param session: the active session to use
3378 """
3379
3380 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
3381 + "/attr/NTPServers"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003382
3383 data = {"data": args.NTPServers.split(",")}
3384
3385 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003386 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003387 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003388 except(requests.exceptions.Timeout):
3389 return(connectionErrHandler(args.json, "Timeout", None))
3390 except(requests.exceptions.ConnectionError) as err:
3391 return connectionErrHandler(args.json, "ConnectionError", err)
3392 if res.status_code == 403:
3393 return "The specified Interface"+"("+args.Interface+")" +\
3394 " doesn't exist"
3395
3396 return res.text
3397
3398
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003399def addIP(host, args, session):
3400 """
3401 Called by the network function. Configures IP address on given interface
3402
3403 @param host: string, the hostname or IP address of the bmc
3404 @param args: contains additional arguments used by the ldap subcommand
3405 args.json: boolean, if this flag is set to true, the output
3406 will be provided in json format for programmatic consumption
3407 @param session: the active session to use
3408 """
3409
3410 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
3411 + "/action/IP"
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003412 protocol = {
3413 'ipv4': 'xyz.openbmc_project.Network.IP.Protocol.IPv4',
3414 'ipv6': 'xyz.openbmc_project.Network.IP.Protocol.IPv6'
3415 }
3416
3417 data = {"data": [protocol[args.type], args.address, int(args.prefixLength),
3418 args.gateway]}
3419
3420 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003421 res = session.post(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003422 timeout=baseTimeout)
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003423 except(requests.exceptions.Timeout):
3424 return(connectionErrHandler(args.json, "Timeout", None))
3425 except(requests.exceptions.ConnectionError) as err:
3426 return connectionErrHandler(args.json, "ConnectionError", err)
3427 if res.status_code == 404:
3428 return "The specified Interface" + "(" + args.Interface + ")" +\
3429 " doesn't exist"
3430
3431 return res.text
3432
3433
3434def getIP(host, args, session):
3435 """
3436 Called by the network function. Prints out IP address of given interface
3437
3438 @param host: string, the hostname or IP address of the bmc
3439 @param args: contains additional arguments used by the ldap subcommand
3440 args.json: boolean, if this flag is set to true, the output
3441 will be provided in json format for programmatic consumption
3442 @param session: the active session to use
3443 """
3444
3445 url = "https://" + host+"/xyz/openbmc_project/network/" + args.Interface +\
3446 "/enumerate"
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003447 try:
Justin Thaler27197622019-01-23 14:42:11 -06003448 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003449 except(requests.exceptions.Timeout):
3450 return(connectionErrHandler(args.json, "Timeout", None))
3451 except(requests.exceptions.ConnectionError) as err:
3452 return connectionErrHandler(args.json, "ConnectionError", err)
3453 if res.status_code == 404:
3454 return "The specified Interface" + "(" + args.Interface + ")" +\
3455 " doesn't exist"
3456
3457 return res.text
3458
3459
3460def deleteIP(host, args, session):
3461 """
3462 Called by the network function. Deletes the IP address from given Interface
3463
3464 @param host: string, the hostname or IP address of the bmc
3465 @param args: contains additional arguments used by the ldap subcommand
3466 @param session: the active session to use
3467 @param args.json: boolean, if this flag is set to true, the output
3468 will be provided in json format for programmatic consumption
3469 """
3470
3471 url = "https://"+host+"/xyz/openbmc_project/network/" + args.Interface+\
3472 "/enumerate"
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003473 data = {"data": []}
3474 try:
Justin Thaler27197622019-01-23 14:42:11 -06003475 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003476 except(requests.exceptions.Timeout):
3477 return(connectionErrHandler(args.json, "Timeout", None))
3478 except(requests.exceptions.ConnectionError) as err:
3479 return connectionErrHandler(args.json, "ConnectionError", err)
3480 if res.status_code == 404:
3481 return "The specified Interface" + "(" + args.Interface + ")" +\
3482 " doesn't exist"
3483 objDict = json.loads(res.text)
3484 if not objDict['data']:
3485 return "No object found for given address on given Interface"
3486
3487 for obj in objDict['data']:
Sunitha Harish0baf6372019-07-31 03:59:03 -05003488 try:
3489 if args.address in objDict['data'][obj]['Address']:
3490 url = "https://"+host+obj+"/action/Delete"
3491 try:
3492 res = session.post(url, headers=jsonHeader, json=data,
3493 verify=False, timeout=baseTimeout)
3494 except(requests.exceptions.Timeout):
3495 return(connectionErrHandler(args.json, "Timeout", None))
3496 except(requests.exceptions.ConnectionError) as err:
3497 return connectionErrHandler(args.json, "ConnectionError", err)
3498 return res.text
3499 else:
3500 continue
3501 except KeyError:
3502 return "No object found for address " + args.address + \
3503 " on Interface(" + args.Interface + ")"
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003504
3505
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003506def addVLAN(host, args, session):
3507 """
3508 Called by the network function. Creates VLAN on given interface.
3509
3510 @param host: string, the hostname or IP address of the bmc
3511 @param args: contains additional arguments used by the ldap subcommand
3512 args.json: boolean, if this flag is set to true, the output
3513 will be provided in json format for programmatic consumption
3514 @param session: the active session to use
3515 """
3516
3517 url = "https://" + host+"/xyz/openbmc_project/network/action/VLAN"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003518
Sunitha Harish0baf6372019-07-31 03:59:03 -05003519 data = {"data": [args.Interface,int(args.Identifier)]}
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003520 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003521 res = session.post(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003522 timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003523 except(requests.exceptions.Timeout):
3524 return(connectionErrHandler(args.json, "Timeout", None))
3525 except(requests.exceptions.ConnectionError) as err:
3526 return connectionErrHandler(args.json, "ConnectionError", err)
3527 if res.status_code == 400:
Sunitha Harish0baf6372019-07-31 03:59:03 -05003528 return "Adding VLAN to interface" + "(" + args.Interface + ")" +\
3529 " failed"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003530
3531 return res.text
3532
3533
3534def deleteVLAN(host, args, session):
3535 """
3536 Called by the network function. Creates VLAN on given interface.
3537
3538 @param host: string, the hostname or IP address of the bmc
3539 @param args: contains additional arguments used by the ldap subcommand
3540 args.json: boolean, if this flag is set to true, the output
3541 will be provided in json format for programmatic consumption
3542 @param session: the active session to use
3543 """
3544
Sunitha Harish577a5032019-08-08 06:27:40 -05003545 url = "https://" + host+"/xyz/openbmc_project/network/"+args.Interface+"/action/Delete"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003546 data = {"data": []}
3547
3548 try:
Justin Thaler27197622019-01-23 14:42:11 -06003549 res = session.post(url, headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003550 except(requests.exceptions.Timeout):
3551 return(connectionErrHandler(args.json, "Timeout", None))
3552 except(requests.exceptions.ConnectionError) as err:
3553 return connectionErrHandler(args.json, "ConnectionError", err)
3554 if res.status_code == 404:
Sunitha Harish577a5032019-08-08 06:27:40 -05003555 return "The specified VLAN"+"("+args.Interface+")" +" doesn't exist"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003556
3557 return res.text
3558
3559
3560def viewDHCPConfig(host, args, session):
3561 """
3562 Called by the network function. Shows DHCP configured Properties.
3563
3564 @param host: string, the hostname or IP address of the bmc
3565 @param args: contains additional arguments used by the ldap subcommand
3566 args.json: boolean, if this flag is set to true, the output
3567 will be provided in json format for programmatic consumption
3568 @param session: the active session to use
3569 """
3570
3571 url="https://"+host+"/xyz/openbmc_project/network/config/dhcp"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003572
3573 try:
Justin Thaler27197622019-01-23 14:42:11 -06003574 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003575 except(requests.exceptions.Timeout):
3576 return(connectionErrHandler(args.json, "Timeout", None))
3577 except(requests.exceptions.ConnectionError) as err:
3578 return connectionErrHandler(args.json, "ConnectionError", err)
3579
3580 return res.text
3581
3582
3583def configureDHCP(host, args, session):
3584 """
3585 Called by the network function. Configures/updates DHCP Properties.
3586
3587 @param host: string, the hostname or IP address of the bmc
3588 @param args: contains additional arguments used by the ldap subcommand
3589 args.json: boolean, if this flag is set to true, the output
3590 will be provided in json format for programmatic consumption
3591 @param session: the active session to use
3592 """
3593
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003594
3595 try:
3596 url="https://"+host+"/xyz/openbmc_project/network/config/dhcp"
3597 if(args.DNSEnabled == True):
3598 data = '{"data": 1}'
3599 else:
3600 data = '{"data": 0}'
Matt Spinler220c3c42019-01-04 15:09:29 -06003601 res = session.put(url + '/attr/DNSEnabled', headers=jsonHeader,
Justin Thaler27197622019-01-23 14:42:11 -06003602 data=data, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003603 if(args.HostNameEnabled == True):
3604 data = '{"data": 1}'
3605 else:
3606 data = '{"data": 0}'
Matt Spinler220c3c42019-01-04 15:09:29 -06003607 res = session.put(url + '/attr/HostNameEnabled', headers=jsonHeader,
Justin Thaler27197622019-01-23 14:42:11 -06003608 data=data, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003609 if(args.NTPEnabled == True):
3610 data = '{"data": 1}'
3611 else:
3612 data = '{"data": 0}'
Matt Spinler220c3c42019-01-04 15:09:29 -06003613 res = session.put(url + '/attr/NTPEnabled', headers=jsonHeader,
Justin Thaler27197622019-01-23 14:42:11 -06003614 data=data, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003615 if(args.SendHostNameEnabled == True):
3616 data = '{"data": 1}'
3617 else:
3618 data = '{"data": 0}'
Matt Spinler220c3c42019-01-04 15:09:29 -06003619 res = session.put(url + '/attr/SendHostNameEnabled', headers=jsonHeader,
Justin Thaler27197622019-01-23 14:42:11 -06003620 data=data, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003621 except(requests.exceptions.Timeout):
3622 return(connectionErrHandler(args.json, "Timeout", None))
3623 except(requests.exceptions.ConnectionError) as err:
3624 return connectionErrHandler(args.json, "ConnectionError", err)
3625
3626 return res.text
3627
3628
3629def nwReset(host, args, session):
3630
3631 """
3632 Called by the network function. Resets networks setting to factory defaults.
3633
3634 @param host: string, the hostname or IP address of the bmc
3635 @param args: contains additional arguments used by the ldap subcommand
3636 args.json: boolean, if this flag is set to true, the output
3637 will be provided in json format for programmatic consumption
3638 @param session: the active session to use
3639 """
3640
3641 url = "https://"+host+"/xyz/openbmc_project/network/action/Reset"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003642 data = '{"data":[] }'
3643 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003644 res = session.post(url, headers=jsonHeader, data=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003645 timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003646
3647 except(requests.exceptions.Timeout):
3648 return(connectionErrHandler(args.json, "Timeout", None))
3649 except(requests.exceptions.ConnectionError) as err:
3650 return connectionErrHandler(args.json, "ConnectionError", err)
3651
3652 return res.text
3653
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003654def getLDAPTypeEnabled(host,session):
3655
3656 """
3657 Called by LDAP related functions to find the LDAP server type that has been enabled.
3658 Returns None if LDAP has not been configured.
3659
3660 @param host: string, the hostname or IP address of the bmc
3661 @param session: the active session to use
3662 """
3663
3664 enabled = False
3665 url = 'https://'+host+'/xyz/openbmc_project/user/ldap/'
3666 for key,value in serverTypeMap.items():
3667 data = {"data": []}
3668 try:
3669 res = session.get(url + value + '/attr/Enabled', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
3670 except(requests.exceptions.Timeout):
3671 print(connectionErrHandler(args.json, "Timeout", None))
3672 return
3673 except(requests.exceptions.ConnectionError) as err:
3674 print(connectionErrHandler(args.json, "ConnectionError", err))
3675 return
3676
3677 enabled = res.json()['data']
3678 if (enabled):
3679 return key
3680
3681def syncRoleMap(host,args,session,fromServerType,toServerType):
3682
3683 """
3684 Called by LDAP related functions to sync the role maps
3685 Returns False if LDAP has not been configured.
3686
3687 @param host: string, the hostname or IP address of the bmc
3688 @param session: the active session to use
3689 @param fromServerType : Server type whose role map has to be copied
3690 @param toServerType : Server type to which role map has to be copied
3691 """
3692
3693 url = "https://"+host+"/xyz/openbmc_project/user/ldap/"
3694
3695 try:
3696 #Note: If the fromServerType has no role map, then
3697 #the toServerType will not have any role map.
3698
3699 #delete the privilege mapping from the toServerType and
3700 #then copy the privilege mapping from fromServerType to
3701 #toServerType.
3702 args.serverType = toServerType
3703 res = deleteAllPrivilegeMapping(host, args, session)
3704
3705 data = {"data": []}
3706 res = session.get(url + serverTypeMap[fromServerType] + '/role_map/enumerate', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
3707 #Previously enabled server type has no role map
3708 if (res.status_code != requests.codes.ok):
3709
3710 #fromServerType has no role map; So, no need to copy
3711 #role map to toServerType.
3712 return
3713
3714 objDict = json.loads(res.text)
3715 dataDict = objDict['data']
3716 for key,value in dataDict.items():
3717 data = {"data": [value["GroupName"], value["Privilege"]]}
3718 res = session.post(url + serverTypeMap[toServerType] + '/action/Create', headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
3719
3720 except(requests.exceptions.Timeout):
3721 return(connectionErrHandler(args.json, "Timeout", None))
3722 except(requests.exceptions.ConnectionError) as err:
3723 return connectionErrHandler(args.json, "ConnectionError", err)
3724 return res.text
3725
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003726
Ratan Guptafeee6372018-10-17 23:25:51 +05303727def createPrivilegeMapping(host, args, session):
3728 """
3729 Called by the ldap function. Creates the group and the privilege mapping.
3730
3731 @param host: string, the hostname or IP address of the bmc
3732 @param args: contains additional arguments used by the ldap subcommand
3733 @param session: the active session to use
3734 @param args.json: boolean, if this flag is set to true, the output
3735 will be provided in json format for programmatic consumption
3736 """
3737
Ratan Guptafeee6372018-10-17 23:25:51 +05303738 try:
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003739 if (isRedfishSupport):
3740 url = 'https://'+host+'/xyz/openbmc_project/user/ldap/'
3741
3742 #To maintain the interface compatibility between op930 and op940, the server type has been made
3743 #optional. If the server type is not specified, then create the role-mapper for the currently
3744 #enabled server type.
3745 serverType = args.serverType
3746 if (serverType is None):
3747 serverType = getLDAPTypeEnabled(host,session)
3748 if (serverType is None):
3749 return("LDAP server has not been enabled. Please specify LDAP serverType to proceed further...")
3750
3751 data = {"data": [args.groupName,args.privilege]}
3752 res = session.post(url + serverTypeMap[serverType] + '/action/Create', headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
3753
3754 else:
3755 url = 'https://'+host+'/xyz/openbmc_project/user/ldap/action/Create'
3756 data = {"data": [args.groupName,args.privilege]}
3757 res = session.post(url, headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
3758
Ratan Guptafeee6372018-10-17 23:25:51 +05303759 except(requests.exceptions.Timeout):
3760 return(connectionErrHandler(args.json, "Timeout", None))
3761 except(requests.exceptions.ConnectionError) as err:
3762 return connectionErrHandler(args.json, "ConnectionError", err)
3763 return res.text
3764
3765def listPrivilegeMapping(host, args, session):
3766 """
3767 Called by the ldap function. Lists the group and the privilege mapping.
3768
3769 @param host: string, the hostname or IP address of the bmc
3770 @param args: contains additional arguments used by the ldap subcommand
3771 @param session: the active session to use
3772 @param args.json: boolean, if this flag is set to true, the output
3773 will be provided in json format for programmatic consumption
3774 """
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003775
3776 if (isRedfishSupport):
3777 serverType = args.serverType
3778 if (serverType is None):
3779 serverType = getLDAPTypeEnabled(host,session)
3780 if (serverType is None):
3781 return("LDAP has not been enabled. Please specify LDAP serverType to proceed further...")
3782
3783 url = 'https://'+host+'/xyz/openbmc_project/user/ldap/'+serverTypeMap[serverType]+'/role_map/enumerate'
3784
3785 else:
3786 url = 'https://'+host+'/xyz/openbmc_project/user/ldap/enumerate'
3787
Ratan Guptafeee6372018-10-17 23:25:51 +05303788 data = {"data": []}
3789
3790 try:
Justin Thaler27197622019-01-23 14:42:11 -06003791 res = session.get(url, headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
Ratan Guptafeee6372018-10-17 23:25:51 +05303792 except(requests.exceptions.Timeout):
3793 return(connectionErrHandler(args.json, "Timeout", None))
3794 except(requests.exceptions.ConnectionError) as err:
3795 return connectionErrHandler(args.json, "ConnectionError", err)
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003796
Ratan Guptafeee6372018-10-17 23:25:51 +05303797 return res.text
3798
3799def deletePrivilegeMapping(host, args, session):
3800 """
3801 Called by the ldap function. Deletes the mapping associated with the group.
3802
3803 @param host: string, the hostname or IP address of the bmc
3804 @param args: contains additional arguments used by the ldap subcommand
3805 @param session: the active session to use
3806 @param args.json: boolean, if this flag is set to true, the output
3807 will be provided in json format for programmatic consumption
3808 """
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003809
3810 ldapNameSpaceObjects = listPrivilegeMapping(host, args, session)
Ratan Guptafeee6372018-10-17 23:25:51 +05303811 ldapNameSpaceObjects = json.loads(ldapNameSpaceObjects)["data"]
3812 path = ''
Ratan Guptafeee6372018-10-17 23:25:51 +05303813 data = {"data": []}
3814
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003815 if (isRedfishSupport):
3816 if (args.serverType is None):
3817 serverType = getLDAPTypeEnabled(host,session)
3818 if (serverType is None):
3819 return("LDAP has not been enabled. Please specify LDAP serverType to proceed further...")
3820 # search for the object having the mapping for the given group
3821 for key,value in ldapNameSpaceObjects.items():
3822 if value['GroupName'] == args.groupName:
3823 path = key
3824 break
3825
3826 if path == '':
3827 return "No privilege mapping found for this group."
3828
3829 # delete the object
3830 url = 'https://'+host+path+'/action/Delete'
3831
3832 else:
3833 # not interested in the config objet
3834 ldapNameSpaceObjects.pop('/xyz/openbmc_project/user/ldap/config', None)
3835
3836 # search for the object having the mapping for the given group
3837 for key,value in ldapNameSpaceObjects.items():
3838 if value['GroupName'] == args.groupName:
3839 path = key
3840 break
3841
3842 if path == '':
3843 return "No privilege mapping found for this group."
3844
3845 # delete the object
3846 url = 'https://'+host+path+'/action/delete'
3847
Ratan Guptafeee6372018-10-17 23:25:51 +05303848 try:
Justin Thaler27197622019-01-23 14:42:11 -06003849 res = session.post(url, headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
Ratan Guptafeee6372018-10-17 23:25:51 +05303850 except(requests.exceptions.Timeout):
3851 return(connectionErrHandler(args.json, "Timeout", None))
3852 except(requests.exceptions.ConnectionError) as err:
3853 return connectionErrHandler(args.json, "ConnectionError", err)
3854 return res.text
Ratan Gupta9166cd22018-10-01 18:09:40 +05303855
Sivas SRR78835272018-11-27 05:27:19 -06003856def deleteAllPrivilegeMapping(host, args, session):
3857 """
3858 Called by the ldap function. Deletes all the privilege mapping and group defined.
3859 @param host: string, the hostname or IP address of the bmc
3860 @param args: contains additional arguments used by the ldap subcommand
3861 @param session: the active session to use
3862 @param args.json: boolean, if this flag is set to true, the output
3863 will be provided in json format for programmatic consumption
3864 """
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003865
Sivas SRR78835272018-11-27 05:27:19 -06003866 ldapNameSpaceObjects = listPrivilegeMapping(host, args, session)
3867 ldapNameSpaceObjects = json.loads(ldapNameSpaceObjects)["data"]
3868 path = ''
Sivas SRR78835272018-11-27 05:27:19 -06003869 data = {"data": []}
3870
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003871 if (isRedfishSupport):
3872 if (args.serverType is None):
3873 serverType = getLDAPTypeEnabled(host,session)
3874 if (serverType is None):
3875 return("LDAP has not been enabled. Please specify LDAP serverType to proceed further...")
3876
3877 else:
3878 # Remove the config object.
3879 ldapNameSpaceObjects.pop('/xyz/openbmc_project/user/ldap/config', None)
3880
Sivas SRR78835272018-11-27 05:27:19 -06003881 try:
3882 # search for GroupName property and delete if it is available.
3883 for path in ldapNameSpaceObjects.keys():
3884 # delete the object
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003885 url = 'https://'+host+path+'/action/Delete'
Justin Thaler27197622019-01-23 14:42:11 -06003886 res = session.post(url, headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003887
Sivas SRR78835272018-11-27 05:27:19 -06003888 except(requests.exceptions.Timeout):
3889 return(connectionErrHandler(args.json, "Timeout", None))
3890 except(requests.exceptions.ConnectionError) as err:
3891 return connectionErrHandler(args.json, "ConnectionError", err)
3892 return res.text
3893
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06003894def viewLDAPConfig(host, args, session):
3895 """
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003896 Called by the ldap function. Prints out active LDAP configuration properties
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06003897
3898 @param host: string, the hostname or IP address of the bmc
3899 @param args: contains additional arguments used by the ldap subcommand
3900 args.json: boolean, if this flag is set to true, the output
3901 will be provided in json format for programmatic consumption
3902 @param session: the active session to use
3903 @return returns LDAP's configured properties.
3904 """
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003905
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06003906 try:
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003907 if (isRedfishSupport):
3908
3909 url = "https://"+host+"/xyz/openbmc_project/user/ldap/"
3910
3911 serverTypeEnabled = getLDAPTypeEnabled(host,session)
3912
3913 if (serverTypeEnabled is not None):
3914 data = {"data": []}
3915 res = session.get(url + serverTypeMap[serverTypeEnabled], headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
3916 else:
3917 return("LDAP server has not been enabled...")
3918
3919 else :
3920 url = "https://"+host+"/xyz/openbmc_project/user/ldap/config"
3921 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
3922
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06003923 except(requests.exceptions.Timeout):
3924 return(connectionErrHandler(args.json, "Timeout", None))
3925 except(requests.exceptions.ConnectionError) as err:
3926 return connectionErrHandler(args.json, "ConnectionError", err)
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06003927 if res.status_code == 404:
3928 return "LDAP server config has not been created"
3929 return res.text
3930
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003931def str2bool(v):
3932 if v.lower() in ('yes', 'true', 't', 'y', '1'):
3933 return True
3934 elif v.lower() in ('no', 'false', 'f', 'n', '0'):
3935 return False
3936 else:
3937 raise argparse.ArgumentTypeError('Boolean value expected.')
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06003938
Matt Spinler7d426c22018-09-24 14:42:07 -05003939def localUsers(host, args, session):
3940 """
3941 Enables and disables local BMC users.
3942
3943 @param host: string, the hostname or IP address of the bmc
3944 @param args: contains additional arguments used by the logging sub command
3945 @param session: the active session to use
3946 """
3947
Matt Spinler7d426c22018-09-24 14:42:07 -05003948 url="https://{hostname}/xyz/openbmc_project/user/enumerate".format(hostname=host)
3949 try:
Justin Thaler27197622019-01-23 14:42:11 -06003950 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Matt Spinler7d426c22018-09-24 14:42:07 -05003951 except(requests.exceptions.Timeout):
3952 return(connectionErrHandler(args.json, "Timeout", None))
3953 usersDict = json.loads(res.text)
3954
3955 if not usersDict['data']:
3956 return "No users found"
3957
3958 output = ""
3959 for user in usersDict['data']:
Matt Spinler015adc22018-10-23 14:30:19 -05003960
3961 # Skip LDAP and another non-local users
3962 if 'UserEnabled' not in usersDict['data'][user]:
3963 continue
3964
Matt Spinler7d426c22018-09-24 14:42:07 -05003965 name = user.split('/')[-1]
3966 url = "https://{hostname}{user}/attr/UserEnabled".format(hostname=host, user=user)
3967
3968 if args.local_users == "queryenabled":
3969 try:
Justin Thaler27197622019-01-23 14:42:11 -06003970 res = session.get(url, headers=jsonHeader,verify=False, timeout=baseTimeout)
Matt Spinler7d426c22018-09-24 14:42:07 -05003971 except(requests.exceptions.Timeout):
3972 return(connectionErrHandler(args.json, "Timeout", None))
3973
3974 result = json.loads(res.text)
3975 output += ("User: {name} Enabled: {result}\n").format(name=name, result=result['data'])
3976
3977 elif args.local_users in ["enableall", "disableall"]:
3978 action = ""
3979 if args.local_users == "enableall":
3980 data = '{"data": true}'
3981 action = "Enabling"
3982 else:
3983 data = '{"data": false}'
3984 action = "Disabling"
3985
3986 output += "{action} {name}\n".format(action=action, name=name)
3987
3988 try:
Justin Thaler27197622019-01-23 14:42:11 -06003989 resp = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Matt Spinler7d426c22018-09-24 14:42:07 -05003990 except(requests.exceptions.Timeout):
3991 return connectionErrHandler(args.json, "Timeout", None)
3992 except(requests.exceptions.ConnectionError) as err:
3993 return connectionErrHandler(args.json, "ConnectionError", err)
3994 else:
3995 return "Invalid local users argument"
3996
3997 return output
3998
Marri Devender Rao2c2a5162018-11-05 08:57:11 -06003999def setPassword(host, args, session):
4000 """
4001 Set local user password
4002 @param host: string, the hostname or IP address of the bmc
4003 @param args: contains additional arguments used by the logging sub
4004 command
4005 @param session: the active session to use
4006 @param args.json: boolean, if this flag is set to true, the output
4007 will be provided in json format for programmatic consumption
4008 @return: Session object
4009 """
Marri Devender Rao2c2a5162018-11-05 08:57:11 -06004010 try:
Sunitha Harishc99faba2019-07-19 06:55:22 -05004011 if(isRedfishSupport):
4012 url = "https://" + host + "/redfish/v1/AccountService/Accounts/"+ \
4013 args.user
4014 data = {"Password":args.password}
4015 res = session.patch(url, headers=jsonHeader, json=data,
4016 verify=False, timeout=baseTimeout)
4017 else:
4018 url = "https://" + host + "/xyz/openbmc_project/user/" + args.user + \
4019 "/action/SetPassword"
4020 res = session.post(url, headers=jsonHeader,
Marri Devender Rao2c2a5162018-11-05 08:57:11 -06004021 json={"data": [args.password]}, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06004022 timeout=baseTimeout)
Marri Devender Rao2c2a5162018-11-05 08:57:11 -06004023 except(requests.exceptions.Timeout):
4024 return(connectionErrHandler(args.json, "Timeout", None))
4025 except(requests.exceptions.ConnectionError) as err:
4026 return connectionErrHandler(args.json, "ConnectionError", err)
4027 except(requests.exceptions.RequestException) as err:
4028 return connectionErrHandler(args.json, "RequestException", err)
Sunitha Harishc99faba2019-07-19 06:55:22 -05004029 return res.status_code
Matthew Barth368e83c2019-02-01 13:48:25 -06004030
4031def getThermalZones(host, args, session):
4032 """
4033 Get the available thermal control zones
4034 @param host: string, the hostname or IP address of the bmc
4035 @param args: contains additional arguments used to get the thermal
4036 control zones
4037 @param session: the active session to use
4038 @return: Session object
4039 """
4040 url = "https://" + host + "/xyz/openbmc_project/control/thermal/enumerate"
4041
4042 try:
4043 res = session.get(url, headers=jsonHeader, verify=False, timeout=30)
4044 except(requests.exceptions.Timeout):
4045 return(connectionErrHandler(args.json, "Timeout", None))
4046 except(requests.exceptions.ConnectionError) as err:
4047 return connectionErrHandler(args.json, "ConnectionError", err)
4048 except(requests.exceptions.RequestException) as err:
4049 return connectionErrHandler(args.json, "RequestException", err)
4050
4051 if (res.status_code == 404):
4052 return "No thermal control zones found or system is in a" + \
4053 " powered off state"
4054
4055 zonesDict = json.loads(res.text)
4056 if not zonesDict['data']:
4057 return "No thermal control zones found"
4058 for zone in zonesDict['data']:
4059 z = ",".join(str(zone.split('/')[-1]) for zone in zonesDict['data'])
4060
4061 return "Zones: [ " + z + " ]"
4062
4063
4064def getThermalMode(host, args, session):
4065 """
4066 Get thermal control mode
4067 @param host: string, the hostname or IP address of the bmc
4068 @param args: contains additional arguments used to get the thermal
4069 control mode
4070 @param session: the active session to use
4071 @param args.zone: the zone to get the mode on
4072 @return: Session object
4073 """
4074 url = "https://" + host + "/xyz/openbmc_project/control/thermal/" + \
4075 args.zone
4076
4077 try:
4078 res = session.get(url, headers=jsonHeader, verify=False, timeout=30)
4079 except(requests.exceptions.Timeout):
4080 return(connectionErrHandler(args.json, "Timeout", None))
4081 except(requests.exceptions.ConnectionError) as err:
4082 return connectionErrHandler(args.json, "ConnectionError", err)
4083 except(requests.exceptions.RequestException) as err:
4084 return connectionErrHandler(args.json, "RequestException", err)
4085
4086 if (res.status_code == 404):
4087 return "Thermal control zone(" + args.zone + ") not found or" + \
4088 " system is in a powered off state"
4089
4090 propsDict = json.loads(res.text)
4091 if not propsDict['data']:
4092 return "No thermal control properties found on zone(" + args.zone + ")"
4093 curMode = "Current"
4094 supModes = "Supported"
4095 result = "\n"
4096 for prop in propsDict['data']:
4097 if (prop.casefold() == curMode.casefold()):
4098 result += curMode + " Mode: " + propsDict['data'][curMode] + "\n"
4099 if (prop.casefold() == supModes.casefold()):
4100 s = ", ".join(str(sup) for sup in propsDict['data'][supModes])
4101 result += supModes + " Modes: [ " + s + " ]\n"
4102
4103 return result
4104
4105def setThermalMode(host, args, session):
4106 """
4107 Set thermal control mode
4108 @param host: string, the hostname or IP address of the bmc
4109 @param args: contains additional arguments used for setting the thermal
4110 control mode
4111 @param session: the active session to use
4112 @param args.zone: the zone to set the mode on
4113 @param args.mode: the mode to enable
4114 @return: Session object
4115 """
4116 url = "https://" + host + "/xyz/openbmc_project/control/thermal/" + \
4117 args.zone + "/attr/Current"
4118
4119 # Check args.mode against supported modes using `getThermalMode` output
4120 modes = getThermalMode(host, args, session)
4121 modes = os.linesep.join([m for m in modes.splitlines() if m])
4122 modes = modes.replace("\n", ";").strip()
4123 modesDict = dict(m.split(': ') for m in modes.split(';'))
4124 sModes = ''.join(s for s in modesDict['Supported Modes'] if s not in '[ ]')
4125 if args.mode.casefold() not in \
4126 (m.casefold() for m in sModes.split(',')) or not args.mode:
4127 result = ("Unsupported mode('" + args.mode + "') given, " +
4128 "select a supported mode: \n" +
4129 getThermalMode(host, args, session))
4130 return result
4131
4132 data = '{"data":"' + args.mode + '"}'
4133 try:
4134 res = session.get(url, headers=jsonHeader, verify=False, timeout=30)
4135 except(requests.exceptions.Timeout):
4136 return(connectionErrHandler(args.json, "Timeout", None))
4137 except(requests.exceptions.ConnectionError) as err:
4138 return connectionErrHandler(args.json, "ConnectionError", err)
4139 except(requests.exceptions.RequestException) as err:
4140 return connectionErrHandler(args.json, "RequestException", err)
4141
4142 if (data and res.status_code != 404):
4143 try:
4144 res = session.put(url, headers=jsonHeader,
4145 data=data, verify=False,
4146 timeout=30)
4147 except(requests.exceptions.Timeout):
4148 return(connectionErrHandler(args.json, "Timeout", None))
4149 except(requests.exceptions.ConnectionError) as err:
4150 return connectionErrHandler(args.json, "ConnectionError", err)
4151 except(requests.exceptions.RequestException) as err:
4152 return connectionErrHandler(args.json, "RequestException", err)
4153
4154 if res.status_code == 403:
4155 return "The specified thermal control zone(" + args.zone + ")" + \
4156 " does not exist"
4157
4158 return res.text
4159 else:
4160 return "Setting thermal control mode(" + args.mode + ")" + \
4161 " not supported or operation not available(system powered off?)"
4162
4163
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004164def createCommandParser():
Justin Thalere412dc22018-01-12 16:28:24 -06004165 """
4166 creates the parser for the command line along with help for each command and subcommand
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004167
Justin Thalere412dc22018-01-12 16:28:24 -06004168 @return: returns the parser for the command line
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004169 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004170 parser = argparse.ArgumentParser(description='Process arguments')
Justin Thalere412dc22018-01-12 16:28:24 -06004171 parser.add_argument("-H", "--host", help='A hostname or IP for the BMC')
4172 parser.add_argument("-U", "--user", help='The username to login with')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004173 group = parser.add_mutually_exclusive_group()
4174 group.add_argument("-A", "--askpw", action='store_true', help='prompt for password')
4175 group.add_argument("-P", "--PW", help='Provide the password in-line')
Joseph Reynoldsa2d54c52019-06-11 22:02:57 -05004176 group.add_argument("-E", "--PWenvvar", action='store_true', help='Get password from envvar OPENBMCTOOL_PASSWORD')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004177 parser.add_argument('-j', '--json', action='store_true', help='output json data only')
4178 parser.add_argument('-t', '--policyTableLoc', help='The location of the policy table to parse alerts')
4179 parser.add_argument('-c', '--CerFormat', action='store_true', help=argparse.SUPPRESS)
4180 parser.add_argument('-T', '--procTime', action='store_true', help= argparse.SUPPRESS)
Justin Thalere412dc22018-01-12 16:28:24 -06004181 parser.add_argument('-V', '--version', action='store_true', help='Display the version number of the openbmctool')
4182 subparsers = parser.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004183
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004184 #fru command
4185 parser_inv = subparsers.add_parser("fru", help='Work with platform inventory')
Justin Thalere412dc22018-01-12 16:28:24 -06004186 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 -05004187 inv_subparser.required = True
4188 #fru print
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004189 inv_print = inv_subparser.add_parser("print", help="prints out a list of all FRUs")
4190 inv_print.set_defaults(func=fruPrint)
4191 #fru list [0....n]
4192 inv_list = inv_subparser.add_parser("list", help="print out details on selected FRUs. Specifying no items will list the entire inventory")
4193 inv_list.add_argument('items', nargs='?', help="print out details on selected FRUs. Specifying no items will list the entire inventory")
4194 inv_list.set_defaults(func=fruList)
4195 #fru status
4196 inv_status = inv_subparser.add_parser("status", help="prints out the status of all FRUs")
Justin Thalere412dc22018-01-12 16:28:24 -06004197 inv_status.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004198 inv_status.set_defaults(func=fruStatus)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004199
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004200 #sensors command
4201 parser_sens = subparsers.add_parser("sensors", help="Work with platform sensors")
Justin Thalere412dc22018-01-12 16:28:24 -06004202 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 -05004203 sens_subparser.required = True
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004204 #sensor print
4205 sens_print= sens_subparser.add_parser('print', help="prints out a list of all Sensors.")
4206 sens_print.set_defaults(func=sensor)
4207 #sensor list[0...n]
4208 sens_list=sens_subparser.add_parser("list", help="Lists all Sensors in the platform. Specify a sensor for full details. ")
4209 sens_list.add_argument("sensNum", nargs='?', help="The Sensor number to get full details on" )
4210 sens_list.set_defaults(func=sensor)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004211
Matthew Barth368e83c2019-02-01 13:48:25 -06004212 #thermal control commands
4213 parser_therm = subparsers.add_parser("thermal", help="Work with thermal control parameters")
4214 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')
4215 #thermal control zones
4216 parser_thermZones = therm_subparser.add_parser("zones", help="Get a list of available thermal control zones")
4217 parser_thermZones.set_defaults(func=getThermalZones)
4218 #thermal control modes
4219 parser_thermMode = therm_subparser.add_parser("modes", help="Work with thermal control modes")
4220 thermMode_sub = parser_thermMode.add_subparsers(title='subactions', description='Work with thermal control modes', help="Work with thermal control modes")
4221 #get thermal control mode
4222 parser_getThermMode = thermMode_sub.add_parser("get", help="Get current and supported thermal control modes")
4223 parser_getThermMode.add_argument('-z', '--zone', required=True, help='Thermal zone to work with')
4224 parser_getThermMode.set_defaults(func=getThermalMode)
4225 #set thermal control mode
4226 parser_setThermMode = thermMode_sub.add_parser("set", help="Set the thermal control mode")
4227 parser_setThermMode.add_argument('-z', '--zone', required=True, help='Thermal zone to work with')
4228 parser_setThermMode.add_argument('-m', '--mode', required=True, help='The supported thermal control mode')
4229 parser_setThermMode.set_defaults(func=setThermalMode)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004230
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004231 #sel command
4232 parser_sel = subparsers.add_parser("sel", help="Work with platform alerts")
Justin Thalere412dc22018-01-12 16:28:24 -06004233 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 -05004234 sel_subparser.required = True
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004235 #sel print
4236 sel_print = sel_subparser.add_parser("print", help="prints out a list of all sels in a condensed list")
4237 sel_print.add_argument('-d', '--devdebug', action='store_true', help=argparse.SUPPRESS)
4238 sel_print.add_argument('-v', '--verbose', action='store_true', help="Changes the output to being very verbose")
4239 sel_print.add_argument('-f', '--fileloc', help='Parse a file instead of the BMC output')
4240 sel_print.set_defaults(func=selPrint)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004241
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004242 #sel list
4243 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")
4244 sel_list.add_argument("selNum", nargs='?', type=int, help="The SEL entry to get details on")
4245 sel_list.set_defaults(func=selList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004246
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004247 sel_get = sel_subparser.add_parser("get", help="Gets the verbose details of a specified SEL entry")
4248 sel_get.add_argument('selNum', type=int, help="the number of the SEL entry to get")
4249 sel_get.set_defaults(func=selList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004250
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004251 sel_clear = sel_subparser.add_parser("clear", help="Clears all entries from the SEL")
4252 sel_clear.set_defaults(func=selClear)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004253
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004254 sel_setResolved = sel_subparser.add_parser("resolve", help="Sets the sel entry to resolved")
Justin Thalere412dc22018-01-12 16:28:24 -06004255 sel_setResolved.add_argument('-n', '--selNum', type=int, help="the number of the SEL entry to resolve")
4256 sel_ResolveAll_sub = sel_setResolved.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
4257 sel_ResolveAll = sel_ResolveAll_sub.add_parser('all', help='Resolve all SEL entries')
4258 sel_ResolveAll.set_defaults(func=selResolveAll)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004259 sel_setResolved.set_defaults(func=selSetResolved)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004260
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004261 parser_chassis = subparsers.add_parser("chassis", help="Work with chassis power and status")
Justin Thalere412dc22018-01-12 16:28:24 -06004262 chas_sub = parser_chassis.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004263
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004264 parser_chassis.add_argument('status', action='store_true', help='Returns the current status of the platform')
4265 parser_chassis.set_defaults(func=chassis)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004266
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004267 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 -06004268 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 -06004269 parser_chasPower.set_defaults(func=chassisPower)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004270
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004271 #control the chassis identify led
4272 parser_chasIdent = chas_sub.add_parser("identify", help="Control the chassis identify led")
4273 parser_chasIdent.add_argument('identcmd', choices=['on', 'off', 'status'], help='The control option for the led: on, off, blink, status')
4274 parser_chasIdent.set_defaults(func=chassisIdent)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004275
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004276 #collect service data
4277 parser_servData = subparsers.add_parser("collect_service_data", help="Collect all bmc data needed for service")
4278 parser_servData.add_argument('-d', '--devdebug', action='store_true', help=argparse.SUPPRESS)
4279 parser_servData.set_defaults(func=collectServiceData)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004280
Justin Thalere412dc22018-01-12 16:28:24 -06004281 #system quick health check
4282 parser_healthChk = subparsers.add_parser("health_check", help="Work with platform sensors")
4283 parser_healthChk.set_defaults(func=healthCheck)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004284
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004285 #work with bmc dumps
4286 parser_bmcdump = subparsers.add_parser("dump", help="Work with bmc dump files")
Justin Thalere412dc22018-01-12 16:28:24 -06004287 bmcDump_sub = parser_bmcdump.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Justin Thaler53bf2f12018-07-16 14:05:32 -05004288 bmcDump_sub.required = True
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004289 dump_Create = bmcDump_sub.add_parser('create', help="Create a bmc dump")
4290 dump_Create.set_defaults(func=bmcDumpCreate)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004291
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004292 dump_list = bmcDump_sub.add_parser('list', help="list all bmc dump files")
4293 dump_list.set_defaults(func=bmcDumpList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004294
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004295 parserdumpdelete = bmcDump_sub.add_parser('delete', help="Delete bmc dump files")
4296 parserdumpdelete.add_argument("-n", "--dumpNum", nargs='*', type=int, help="The Dump entry to delete")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004297 parserdumpdelete.set_defaults(func=bmcDumpDelete)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004298
Justin Thalere412dc22018-01-12 16:28:24 -06004299 bmcDumpDelsub = parserdumpdelete.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004300 deleteAllDumps = bmcDumpDelsub.add_parser('all', help='Delete all bmc dump files')
4301 deleteAllDumps.set_defaults(func=bmcDumpDeleteAll)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004302
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004303 parser_dumpretrieve = bmcDump_sub.add_parser('retrieve', help='Retrieve a dump file')
4304 parser_dumpretrieve.add_argument("dumpNum", type=int, help="The Dump entry to delete")
4305 parser_dumpretrieve.add_argument("-s", "--dumpSaveLoc", help="The location to save the bmc dump file")
4306 parser_dumpretrieve.set_defaults(func=bmcDumpRetrieve)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004307
Justin Thaler22b1bb52018-03-15 13:31:32 -05004308 #bmc command for reseting the bmc
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004309 parser_bmc = subparsers.add_parser('bmc', help="Work with the bmc")
Justin Thalere412dc22018-01-12 16:28:24 -06004310 bmc_sub = parser_bmc.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004311 parser_BMCReset = bmc_sub.add_parser('reset', help='Reset the bmc' )
4312 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 -06004313 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.")
4314 parser_bmc.set_defaults(func=bmc)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004315
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004316 #add alias to the bmc command
4317 parser_mc = subparsers.add_parser('mc', help="Work with the management controller")
Justin Thalere412dc22018-01-12 16:28:24 -06004318 mc_sub = parser_mc.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004319 parser_MCReset = mc_sub.add_parser('reset', help='Reset the bmc' )
4320 parser_MCReset.add_argument('type', choices=['warm','cold'], help="Reboot the BMC")
4321 #parser_MCReset.add_argument('cold', action='store_true', help="Reboot the BMC and CLEAR the configuration")
4322 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 -06004323 parser_MCReset.set_defaults(func=bmcReset)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004324 parser_mc.set_defaults(func=bmc)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004325
Justin Thalere412dc22018-01-12 16:28:24 -06004326 #gard clear
4327 parser_gc = subparsers.add_parser("gardclear", help="Used to clear gard records")
4328 parser_gc.set_defaults(func=gardClear)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004329
Justin Thalere412dc22018-01-12 16:28:24 -06004330 #firmware_flash
4331 parser_fw = subparsers.add_parser("firmware", help="Work with the system firmware")
4332 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 -05004333 fwflash_subproc.required = True
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004334
Justin Thalere412dc22018-01-12 16:28:24 -06004335 fwflash = fwflash_subproc.add_parser('flash', help="Flash the system firmware")
4336 fwflash.add_argument('type', choices=['bmc', 'pnor'], help="image type to flash")
4337 fwflash.add_argument('-f', '--fileloc', required=True, help="The absolute path to the firmware image")
4338 fwflash.set_defaults(func=fwFlash)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004339
Justin Thaler22b1bb52018-03-15 13:31:32 -05004340 fwActivate = fwflash_subproc.add_parser('activate', help="Activate existing image on the bmc")
Justin Thalere412dc22018-01-12 16:28:24 -06004341 fwActivate.add_argument('imageID', help="The image ID to activate from the firmware list. Ex: 63c95399")
4342 fwActivate.set_defaults(func=activateFWImage)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004343
Justin Thaler22b1bb52018-03-15 13:31:32 -05004344 fwActivateStatus = fwflash_subproc.add_parser('activation_status', help="Check Status of activations")
4345 fwActivateStatus.set_defaults(func=activateStatus)
4346
Justin Thaler3d71d402018-07-24 14:35:39 -05004347 fwList = fwflash_subproc.add_parser('list', help="List all of the installed firmware")
4348 fwList.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
4349 fwList.set_defaults(func=firmwareList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004350
Justin Thaler3d71d402018-07-24 14:35:39 -05004351 fwprint = fwflash_subproc.add_parser('print', help="List all of the installed firmware")
4352 fwprint.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
4353 fwprint.set_defaults(func=firmwareList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004354
Adriana Kobylak5af2fad2018-11-08 12:33:43 -06004355 fwDelete = fwflash_subproc.add_parser('delete', help="Delete an existing firmware version")
4356 fwDelete.add_argument('versionID', help="The version ID to delete from the firmware list. Ex: 63c95399")
4357 fwDelete.set_defaults(func=deleteFWVersion)
4358
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05004359 #logging
4360 parser_logging = subparsers.add_parser("logging", help="logging controls")
4361 logging_sub = parser_logging.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004362
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05004363 #turn rest api logging on/off
4364 parser_rest_logging = logging_sub.add_parser("rest_api", help="turn rest api logging on/off")
4365 parser_rest_logging.add_argument('rest_logging', choices=['on', 'off'], help='The control option for rest logging: on, off')
4366 parser_rest_logging.set_defaults(func=restLogging)
Deepak Kodihalli02d53282018-09-18 06:53:31 -05004367
4368 #remote logging
4369 parser_remote_logging = logging_sub.add_parser("remote_logging", help="Remote logging (rsyslog) commands")
4370 parser_remote_logging.add_argument('remote_logging', choices=['view', 'disable'], help='Remote logging (rsyslog) commands')
4371 parser_remote_logging.set_defaults(func=remoteLogging)
4372
4373 #configure remote logging
4374 parser_remote_logging_config = logging_sub.add_parser("remote_logging_config", help="Configure remote logging (rsyslog)")
4375 parser_remote_logging_config.add_argument("-a", "--address", required=True, help="Set IP address of rsyslog server")
4376 parser_remote_logging_config.add_argument("-p", "--port", required=True, type=int, help="Set Port of rsyslog server")
4377 parser_remote_logging_config.set_defaults(func=remoteLoggingConfig)
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05004378
4379 #certificate management
4380 parser_cert = subparsers.add_parser("certificate", help="Certificate management")
4381 certMgmt_subproc = parser_cert.add_subparsers(title='subcommands', description='valid certificate commands', help='sub-command help', dest='command')
4382
4383 certUpdate = certMgmt_subproc.add_parser('update', help="Update the certificate")
4384 certUpdate.add_argument('type', choices=['server', 'client', 'authority'], help="certificate type to update")
4385 certUpdate.add_argument('service', choices=['https', 'ldap'], help="Service to update")
4386 certUpdate.add_argument('-f', '--fileloc', required=True, help="The absolute path to the certificate file")
4387 certUpdate.set_defaults(func=certificateUpdate)
4388
4389 certDelete = certMgmt_subproc.add_parser('delete', help="Delete the certificate")
4390 certDelete.add_argument('type', choices=['server', 'client', 'authority'], help="certificate type to delete")
4391 certDelete.add_argument('service', choices=['https', 'ldap'], help="Service to delete the certificate")
4392 certDelete.set_defaults(func=certificateDelete)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004393
Marri Devender Raodfe81ad2019-07-01 05:38:09 -05004394 certReplace = certMgmt_subproc.add_parser('replace',
4395 help="Replace the certificate")
4396 certReplace.add_argument('type', choices=['server', 'client', 'authority'],
4397 help="certificate type to replace")
4398 certReplace.add_argument('service', choices=['https', 'ldap'],
4399 help="Service to replace the certificate")
4400 certReplace.add_argument('-f', '--fileloc', required=True,
4401 help="The absolute path to the certificate file")
4402 certReplace.set_defaults(func=certificateReplace)
4403
Marri Devender Rao34646402019-07-01 05:46:03 -05004404 certDisplay = certMgmt_subproc.add_parser('display',
4405 help="Print the certificate")
4406 certDisplay.add_argument('type', choices=['server', 'client', 'authority'],
4407 help="certificate type to display")
4408 certDisplay.set_defaults(func=certificateDisplay)
4409
Marri Devender Raoa208ff82019-07-01 05:51:27 -05004410 certList = certMgmt_subproc.add_parser('list',
4411 help="Certificate list")
4412 certList.set_defaults(func=certificateList)
4413
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05004414 certGenerateCSR = certMgmt_subproc.add_parser('generatecsr', help="Generate CSR")
4415 certGenerateCSR.add_argument('type', choices=['server', 'client', 'authority'],
4416 help="Generate CSR")
4417 certGenerateCSR.add_argument('city',
4418 help="The city or locality of the organization making the request")
4419 certGenerateCSR.add_argument('commonName',
4420 help="The fully qualified domain name of the component that is being secured.")
4421 certGenerateCSR.add_argument('country',
4422 help="The country of the organization making the request")
4423 certGenerateCSR.add_argument('organization',
4424 help="The name of the organization making the request.")
4425 certGenerateCSR.add_argument('organizationUnit',
4426 help="The name of the unit or division of the organization making the request.")
4427 certGenerateCSR.add_argument('state',
4428 help="The state, province, or region of the organization making the request.")
4429 certGenerateCSR.add_argument('keyPairAlgorithm', choices=['RSA', 'EC'],
4430 help="The type of key pair for use with signing algorithms.")
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05004431 certGenerateCSR.add_argument('keyCurveId',
4432 help="The curve ID to be used with the key, if needed based on the value of the 'KeyPairAlgorithm' parameter.")
4433 certGenerateCSR.add_argument('contactPerson',
4434 help="The name of the user making the request")
4435 certGenerateCSR.add_argument('email',
4436 help="The email address of the contact within the organization")
4437 certGenerateCSR.add_argument('alternativeNames',
4438 help="Additional hostnames of the component that is being secured")
4439 certGenerateCSR.add_argument('givenname',
4440 help="The given name of the user making the request")
4441 certGenerateCSR.add_argument('surname',
4442 help="The surname of the user making the request")
4443 certGenerateCSR.add_argument('unstructuredname',
4444 help="he unstructured name of the subject")
4445 certGenerateCSR.add_argument('initials',
4446 help="The initials of the user making the request")
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05004447 certGenerateCSR.set_defaults(func=certificateGenerateCSR)
4448
Matt Spinler7d426c22018-09-24 14:42:07 -05004449 # local users
4450 parser_users = subparsers.add_parser("local_users", help="Work with local users")
4451 parser_users.add_argument('local_users', choices=['disableall','enableall', 'queryenabled'], help="Disable, enable or query local user accounts")
4452 parser_users.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
4453 parser_users.set_defaults(func=localUsers)
4454
Ratan Gupta9166cd22018-10-01 18:09:40 +05304455 #LDAP
4456 parser_ldap = subparsers.add_parser("ldap", help="LDAP controls")
4457 ldap_sub = parser_ldap.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
4458
4459 #configure and enable LDAP
4460 parser_ldap_config = ldap_sub.add_parser("enable", help="Configure and enables the LDAP")
4461 parser_ldap_config.add_argument("-a", "--uri", required=True, help="Set LDAP server URI")
4462 parser_ldap_config.add_argument("-B", "--bindDN", required=True, help="Set the bind DN of the LDAP server")
4463 parser_ldap_config.add_argument("-b", "--baseDN", required=True, help="Set the base DN of the LDAP server")
4464 parser_ldap_config.add_argument("-p", "--bindPassword", required=True, help="Set the bind password of the LDAP server")
4465 parser_ldap_config.add_argument("-S", "--scope", choices=['sub','one', 'base'],
4466 help='Specifies the search scope:subtree, one level or base object.')
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004467 parser_ldap_config.add_argument("-t", "--serverType", required=True, choices=['ActiveDirectory','OpenLDAP'],
Ratan Gupta9166cd22018-10-01 18:09:40 +05304468 help='Specifies the configured server is ActiveDirectory(AD) or OpenLdap')
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004469 parser_ldap_config.add_argument("-g","--groupAttrName", required=False, default='', help="Group Attribute Name")
4470 parser_ldap_config.add_argument("-u","--userAttrName", required=False, default='', help="User Attribute Name")
4471 parser_ldap_config.set_defaults(func=enableLDAPConfig)
Ratan Gupta9166cd22018-10-01 18:09:40 +05304472
4473 # disable LDAP
4474 parser_disable_ldap = ldap_sub.add_parser("disable", help="disables the LDAP")
4475 parser_disable_ldap.set_defaults(func=disableLDAP)
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06004476 # view-config
4477 parser_ldap_config = \
4478 ldap_sub.add_parser("view-config", help="prints out a list of all \
4479 LDAPS's configured properties")
4480 parser_ldap_config.set_defaults(func=viewLDAPConfig)
Ratan Gupta9166cd22018-10-01 18:09:40 +05304481
Ratan Guptafeee6372018-10-17 23:25:51 +05304482 #create group privilege mapping
4483 parser_ldap_mapper = ldap_sub.add_parser("privilege-mapper", help="LDAP group privilege controls")
4484 parser_ldap_mapper_sub = parser_ldap_mapper.add_subparsers(title='subcommands', description='valid subcommands',
4485 help="sub-command help", dest='command')
4486
4487 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 -05004488 parser_ldap_mapper_create.add_argument("-t", "--serverType", choices=['ActiveDirectory','OpenLDAP'],
4489 help='Specifies the configured server is ActiveDirectory(AD) or OpenLdap')
Ratan Guptafeee6372018-10-17 23:25:51 +05304490 parser_ldap_mapper_create.add_argument("-g","--groupName",required=True,help="Group Name")
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004491 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 +05304492 parser_ldap_mapper_create.set_defaults(func=createPrivilegeMapping)
4493
4494 #list group privilege mapping
4495 parser_ldap_mapper_list = parser_ldap_mapper_sub.add_parser("list",help="List privilege mapping")
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004496 parser_ldap_mapper_list.add_argument("-t", "--serverType", choices=['ActiveDirectory','OpenLDAP'],
4497 help='Specifies the configured server is ActiveDirectory(AD) or OpenLdap')
Ratan Guptafeee6372018-10-17 23:25:51 +05304498 parser_ldap_mapper_list.set_defaults(func=listPrivilegeMapping)
4499
4500 #delete group privilege mapping
4501 parser_ldap_mapper_delete = parser_ldap_mapper_sub.add_parser("delete",help="Delete privilege mapping")
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004502 parser_ldap_mapper_delete.add_argument("-t", "--serverType", choices=['ActiveDirectory','OpenLDAP'],
4503 help='Specifies the configured server is ActiveDirectory(AD) or OpenLdap')
Ratan Guptafeee6372018-10-17 23:25:51 +05304504 parser_ldap_mapper_delete.add_argument("-g","--groupName",required=True,help="Group Name")
4505 parser_ldap_mapper_delete.set_defaults(func=deletePrivilegeMapping)
4506
Sivas SRR78835272018-11-27 05:27:19 -06004507 #deleteAll group privilege mapping
4508 parser_ldap_mapper_delete = parser_ldap_mapper_sub.add_parser("purge",help="Delete All privilege mapping")
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004509 parser_ldap_mapper_delete.add_argument("-t", "--serverType", choices=['ActiveDirectory','OpenLDAP'],
4510 help='Specifies the configured server is ActiveDirectory(AD) or OpenLdap')
Sivas SRR78835272018-11-27 05:27:19 -06004511 parser_ldap_mapper_delete.set_defaults(func=deleteAllPrivilegeMapping)
4512
Marri Devender Rao2c2a5162018-11-05 08:57:11 -06004513 # set local user password
4514 parser_set_password = subparsers.add_parser("set_password",
4515 help="Set password of local user")
4516 parser_set_password.add_argument( "-p", "--password", required=True,
4517 help="Password of local user")
4518 parser_set_password.set_defaults(func=setPassword)
4519
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004520 # network
4521 parser_nw = subparsers.add_parser("network", help="network controls")
4522 nw_sub = parser_nw.add_subparsers(title='subcommands',
4523 description='valid subcommands',
4524 help="sub-command help",
4525 dest='command')
4526
4527 # enable DHCP
4528 parser_enable_dhcp = nw_sub.add_parser("enableDHCP",
4529 help="enables the DHCP on given "
4530 "Interface")
4531 parser_enable_dhcp.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004532 help="Name of the ethernet interface(it can"
4533 "be obtained by the "
4534 "command:network view-config)"
4535 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004536 parser_enable_dhcp.set_defaults(func=enableDHCP)
4537
4538 # disable DHCP
4539 parser_disable_dhcp = nw_sub.add_parser("disableDHCP",
4540 help="disables the DHCP on given "
4541 "Interface")
4542 parser_disable_dhcp.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004543 help="Name of the ethernet interface(it can"
4544 "be obtained by the "
4545 "command:network view-config)"
4546 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004547 parser_disable_dhcp.set_defaults(func=disableDHCP)
4548
4549 # get HostName
4550 parser_gethostname = nw_sub.add_parser("getHostName",
4551 help="prints out HostName")
4552 parser_gethostname.set_defaults(func=getHostname)
4553
4554 # set HostName
4555 parser_sethostname = nw_sub.add_parser("setHostName", help="sets HostName")
4556 parser_sethostname.add_argument("-H", "--HostName", required=True,
4557 help="A HostName for the BMC")
4558 parser_sethostname.set_defaults(func=setHostname)
4559
4560 # get domainname
4561 parser_getdomainname = nw_sub.add_parser("getDomainName",
4562 help="prints out DomainName of "
4563 "given Interface")
4564 parser_getdomainname.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004565 help="Name of the ethernet interface(it "
4566 "can be obtained by the "
4567 "command:network view-config)"
4568 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004569 parser_getdomainname.set_defaults(func=getDomainName)
4570
4571 # set domainname
4572 parser_setdomainname = nw_sub.add_parser("setDomainName",
4573 help="sets DomainName of given "
4574 "Interface")
4575 parser_setdomainname.add_argument("-D", "--DomainName", required=True,
4576 help="Ex: DomainName=Domain1,Domain2,...")
4577 parser_setdomainname.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004578 help="Name of the ethernet interface(it "
4579 "can be obtained by the "
4580 "command:network view-config)"
4581 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004582 parser_setdomainname.set_defaults(func=setDomainName)
4583
4584 # get MACAddress
4585 parser_getmacaddress = nw_sub.add_parser("getMACAddress",
4586 help="prints out MACAddress the "
4587 "given Interface")
4588 parser_getmacaddress.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004589 help="Name of the ethernet interface(it "
4590 "can be obtained by the "
4591 "command:network view-config)"
4592 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004593 parser_getmacaddress.set_defaults(func=getMACAddress)
4594
4595 # set MACAddress
4596 parser_setmacaddress = nw_sub.add_parser("setMACAddress",
4597 help="sets MACAddress")
4598 parser_setmacaddress.add_argument("-MA", "--MACAddress", required=True,
4599 help="A MACAddress for the given "
4600 "Interface")
4601 parser_setmacaddress.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004602 help="Name of the ethernet interface(it can"
4603 "be obtained by the "
4604 "command:network view-config)"
4605 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004606 parser_setmacaddress.set_defaults(func=setMACAddress)
4607
4608 # get DefaultGW
4609 parser_getdefaultgw = nw_sub.add_parser("getDefaultGW",
4610 help="prints out DefaultGateway "
4611 "the BMC")
4612 parser_getdefaultgw.set_defaults(func=getDefaultGateway)
4613
4614 # set DefaultGW
4615 parser_setdefaultgw = nw_sub.add_parser("setDefaultGW",
4616 help="sets DefaultGW")
4617 parser_setdefaultgw.add_argument("-GW", "--DefaultGW", required=True,
4618 help="A DefaultGateway for the BMC")
4619 parser_setdefaultgw.set_defaults(func=setDefaultGateway)
4620
4621 # view network Config
4622 parser_ldap_config = nw_sub.add_parser("view-config", help="prints out a "
4623 "list of all network's configured "
4624 "properties")
4625 parser_ldap_config.set_defaults(func=viewNWConfig)
4626
4627 # get DNS
4628 parser_getDNS = nw_sub.add_parser("getDNS",
4629 help="prints out DNS servers on the "
4630 "given interface")
4631 parser_getDNS.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004632 help="Name of the ethernet interface(it can"
4633 "be obtained by the "
4634 "command:network view-config)"
4635 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004636 parser_getDNS.set_defaults(func=getDNS)
4637
4638 # set DNS
4639 parser_setDNS = nw_sub.add_parser("setDNS",
4640 help="sets DNS servers on the given "
4641 "interface")
4642 parser_setDNS.add_argument("-d", "--DNSServers", required=True,
4643 help="Ex: DNSSERVERS=DNS1,DNS2,...")
4644 parser_setDNS.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004645 help="Name of the ethernet interface(it can"
4646 "be obtained by the "
4647 "command:network view-config)"
4648 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004649 parser_setDNS.set_defaults(func=setDNS)
4650
4651 # get NTP
4652 parser_getNTP = nw_sub.add_parser("getNTP",
4653 help="prints out NTP servers on the "
4654 "given interface")
4655 parser_getNTP.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004656 help="Name of the ethernet interface(it can"
4657 "be obtained by the "
4658 "command:network view-config)"
4659 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004660 parser_getNTP.set_defaults(func=getNTP)
4661
4662 # set NTP
4663 parser_setNTP = nw_sub.add_parser("setNTP",
4664 help="sets NTP servers on the given "
4665 "interface")
4666 parser_setNTP.add_argument("-N", "--NTPServers", required=True,
4667 help="Ex: NTPSERVERS=NTP1,NTP2,...")
4668 parser_setNTP.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004669 help="Name of the ethernet interface(it can"
4670 "be obtained by the "
4671 "command:network view-config)"
4672 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004673 parser_setNTP.set_defaults(func=setNTP)
4674
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004675 # configure IP
4676 parser_ip_config = nw_sub.add_parser("addIP", help="Sets IP address to"
4677 "given interface")
4678 parser_ip_config.add_argument("-a", "--address", required=True,
4679 help="IP address of given interface")
4680 parser_ip_config.add_argument("-gw", "--gateway", required=False, default='',
4681 help="The gateway for given interface")
4682 parser_ip_config.add_argument("-l", "--prefixLength", required=True,
4683 help="The prefixLength of IP address")
Sunitha Harish0baf6372019-07-31 03:59:03 -05004684 parser_ip_config.add_argument("-p", "--type", required=True,
4685 choices=['ipv4', 'ipv6'],
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004686 help="The protocol type of the given"
4687 "IP address")
4688 parser_ip_config.add_argument("-I", "--Interface", required=True,
4689 help="Name of the ethernet interface(it can"
4690 "be obtained by the "
4691 "command:network view-config)"
4692 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
4693 parser_ip_config.set_defaults(func=addIP)
4694
4695 # getIP
4696 parser_getIP = nw_sub.add_parser("getIP", help="prints out IP address"
4697 "of given interface")
4698 parser_getIP.add_argument("-I", "--Interface", required=True,
4699 help="Name of the ethernet interface(it can"
4700 "be obtained by the command:network view-config)"
4701 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
4702 parser_getIP.set_defaults(func=getIP)
4703
4704 # rmIP
4705 parser_rmIP = nw_sub.add_parser("rmIP", help="deletes IP address"
4706 "of given interface")
4707 parser_rmIP.add_argument("-a", "--address", required=True,
4708 help="IP address to remove form given Interface")
4709 parser_rmIP.add_argument("-I", "--Interface", required=True,
4710 help="Name of the ethernet interface(it can"
4711 "be obtained by the command:network view-config)"
4712 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
4713 parser_rmIP.set_defaults(func=deleteIP)
4714
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004715 # add VLAN
4716 parser_create_vlan = nw_sub.add_parser("addVLAN", help="enables VLAN "
4717 "on given interface with given "
4718 "VLAN Identifier")
4719 parser_create_vlan.add_argument("-I", "--Interface", required=True,
4720 choices=['eth0', 'eth1'],
4721 help="Name of the ethernet interface")
4722 parser_create_vlan.add_argument("-n", "--Identifier", required=True,
4723 help="VLAN Identifier")
4724 parser_create_vlan.set_defaults(func=addVLAN)
4725
4726 # delete VLAN
4727 parser_delete_vlan = nw_sub.add_parser("deleteVLAN", help="disables VLAN "
4728 "on given interface with given "
4729 "VLAN Identifier")
4730 parser_delete_vlan.add_argument("-I", "--Interface", required=True,
4731 help="Name of the ethernet interface(it can"
4732 "be obtained by the "
4733 "command:network view-config)"
4734 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
4735 parser_delete_vlan.set_defaults(func=deleteVLAN)
4736
4737 # viewDHCPConfig
4738 parser_viewDHCPConfig = nw_sub.add_parser("viewDHCPConfig",
4739 help="Shows DHCP configured "
4740 "Properties")
4741 parser_viewDHCPConfig.set_defaults(func=viewDHCPConfig)
4742
4743 # configureDHCP
4744 parser_configDHCP = nw_sub.add_parser("configureDHCP",
4745 help="Configures/updates DHCP "
4746 "Properties")
4747 parser_configDHCP.add_argument("-d", "--DNSEnabled", type=str2bool,
4748 required=True, help="Sets DNSEnabled property")
4749 parser_configDHCP.add_argument("-n", "--HostNameEnabled", type=str2bool,
4750 required=True,
4751 help="Sets HostNameEnabled property")
4752 parser_configDHCP.add_argument("-t", "--NTPEnabled", type=str2bool,
4753 required=True,
4754 help="Sets NTPEnabled property")
4755 parser_configDHCP.add_argument("-s", "--SendHostNameEnabled", type=str2bool,
4756 required=True,
4757 help="Sets SendHostNameEnabled property")
4758 parser_configDHCP.set_defaults(func=configureDHCP)
4759
4760 # network factory reset
4761 parser_nw_reset = nw_sub.add_parser("nwReset",
4762 help="Resets networks setting to "
4763 "factory defaults. "
4764 "note:Reset settings will be applied "
4765 "after BMC reboot")
4766 parser_nw_reset.set_defaults(func=nwReset)
4767
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004768 return parser
4769
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004770def main(argv=None):
Justin Thalere412dc22018-01-12 16:28:24 -06004771 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004772 main function for running the command line utility as a sub application
4773 """
4774 global toolVersion
Marri Devender Rao82590dc2019-06-06 04:54:22 -05004775 toolVersion = "1.15"
Sunitha Harishc99faba2019-07-19 06:55:22 -05004776 global isRedfishSupport
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004777
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004778 parser = createCommandParser()
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004779 args = parser.parse_args(argv)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004780
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004781 totTimeStart = int(round(time.time()*1000))
4782
4783 if(sys.version_info < (3,0)):
4784 urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
4785 if sys.version_info >= (3,0):
4786 requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)
Justin Thalere412dc22018-01-12 16:28:24 -06004787 if (args.version):
Justin Thaler22b1bb52018-03-15 13:31:32 -05004788 print("Version: "+ toolVersion)
Justin Thalere412dc22018-01-12 16:28:24 -06004789 sys.exit(0)
4790 if (hasattr(args, 'fileloc') and args.fileloc is not None and 'print' in args.command):
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004791 mysess = None
Justin Thalere412dc22018-01-12 16:28:24 -06004792 print(selPrint('N/A', args, mysess))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004793 else:
Justin Thalere412dc22018-01-12 16:28:24 -06004794 if(hasattr(args, 'host') and hasattr(args,'user')):
4795 if (args.askpw):
4796 pw = getpass.getpass()
4797 elif(args.PW is not None):
4798 pw = args.PW
Joseph Reynoldsa2d54c52019-06-11 22:02:57 -05004799 elif(args.PWenvvar):
4800 pw = os.environ['OPENBMCTOOL_PASSWORD']
Justin Thalere412dc22018-01-12 16:28:24 -06004801 else:
4802 print("You must specify a password")
4803 sys.exit()
4804 logintimeStart = int(round(time.time()*1000))
4805 mysess = login(args.host, args.user, pw, args.json)
Sunitha Harish336cda22019-07-23 02:02:52 -05004806 if(mysess == None):
4807 print("Login Failed!")
4808 sys.exit()
Justin Thalera9415b42018-05-25 19:40:13 -05004809 if(sys.version_info < (3,0)):
4810 if isinstance(mysess, basestring):
4811 print(mysess)
4812 sys.exit(1)
4813 elif sys.version_info >= (3,0):
4814 if isinstance(mysess, str):
4815 print(mysess)
4816 sys.exit(1)
Justin Thalere412dc22018-01-12 16:28:24 -06004817 logintimeStop = int(round(time.time()*1000))
Sunitha Harishc99faba2019-07-19 06:55:22 -05004818 isRedfishSupport = redfishSupportPresent(args.host,mysess)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004819 commandTimeStart = int(round(time.time()*1000))
Justin Thalere412dc22018-01-12 16:28:24 -06004820 output = args.func(args.host, args, mysess)
4821 commandTimeStop = int(round(time.time()*1000))
Justin Thaler761484a2019-03-26 19:20:23 -05004822 if isinstance(output, dict):
4823 print(json.dumps(output, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False))
4824 else:
4825 print(output)
Justin Thalere412dc22018-01-12 16:28:24 -06004826 if (mysess is not None):
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004827 logout(args.host, args.user, pw, mysess, args.json)
4828 if(args.procTime):
Justin Thalere412dc22018-01-12 16:28:24 -06004829 print("Total time: " + str(int(round(time.time()*1000))- totTimeStart))
4830 print("loginTime: " + str(logintimeStop - logintimeStart))
4831 print("command Time: " + str(commandTimeStop - commandTimeStart))
4832 else:
Joseph Reynoldsa2d54c52019-06-11 22:02:57 -05004833 print("usage:\n"
4834 " OPENBMCTOOL_PASSWORD=secret # if using -E\n"
4835 " openbmctool.py [-h] -H HOST -U USER {-A | -P PW | -E} [-j]\n" +
Justin Thalere412dc22018-01-12 16:28:24 -06004836 "\t[-t POLICYTABLELOC] [-V]\n" +
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05004837 "\t{fru,sensors,sel,chassis,collect_service_data, \
4838 health_check,dump,bmc,mc,gardclear,firmware,logging}\n" +
Justin Thalere412dc22018-01-12 16:28:24 -06004839 "\t...\n" +
4840 "openbmctool.py: error: the following arguments are required: -H/--host, -U/--user")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004841 sys.exit()
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004842
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004843if __name__ == '__main__':
Justin Thalere412dc22018-01-12 16:28:24 -06004844 """
4845 main function when called from the command line
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004846
4847 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004848 import sys
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004849
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004850 isTTY = sys.stdout.isatty()
4851 assert sys.version_info >= (2,7)
4852 main()