blob: 48cdff0f64b837548c3f86df90d9a86c8772b3e7 [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
Ravi Tejad8be0b42020-03-18 14:31:46 -050033import ssl
34import socket
35import select
36import http.client
37from subprocess import check_output
Justin Thalerb4256672020-04-07 19:38:26 -050038import traceback
Justin Thalerf9aee3e2017-12-05 12:11:09 -060039
Ravi Tejad8be0b42020-03-18 14:31:46 -050040
41MAX_NBD_PACKET_SIZE = 131088
Matt Spinler220c3c42019-01-04 15:09:29 -060042jsonHeader = {'Content-Type' : 'application/json'}
43xAuthHeader = {}
Justin Thaler27197622019-01-23 14:42:11 -060044baseTimeout = 60
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -050045serverTypeMap = {
46 'ActiveDirectory' : 'active_directory',
47 'OpenLDAP' : 'openldap'
48 }
Matt Spinler220c3c42019-01-04 15:09:29 -060049
Ravi Tejad8be0b42020-03-18 14:31:46 -050050class NBDPipe:
51
52 def openHTTPSocket(self,args):
53
54 try:
55 _create_unverified_https_context = ssl._create_unverified_context
56 except AttributeError:
57 # Legacy Python that doesn't verify HTTPS certificates by default
58 pass
59 else:
60 # Handle target environment that doesn't support HTTPS verification
61 ssl._create_default_https_context = _create_unverified_https_context
62
63
64 token = gettoken(args)
65 self.conn = http.client.HTTPSConnection(args.host,port=443)
Ravi Tejabef8da42020-07-14 23:01:51 -050066
67 uri = "/redfish/v1/Systems/system/LogServices/Dump/attachment/"+args.dumpNum
68
69 self.conn.request("GET",uri, headers={"X-Auth-Token":token})
Ravi Tejad8be0b42020-03-18 14:31:46 -050070
71 def openTCPSocket(self):
72 # Create a TCP/IP socket
73 self.tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
74 # Connect the socket to the port where the server is listening
75 server_address = ('localhost', 1043)
76 self.tcp.connect(server_address)
77
78 def waitformessage(self):
79 inputs = [self.conn.sock,self.tcp]
80 outputs = []
81 message_queues = {}
82 while True:
83 readable, writable, exceptional = select.select(
84 inputs, outputs, inputs)
85
86 for s in readable:
87 if s is self.conn.sock:
88
89 data = self.conn.sock.recv(MAX_NBD_PACKET_SIZE)
90 print("<<HTTP")
Ravi Tejad8be0b42020-03-18 14:31:46 -050091 if data:
92 self.tcp.send(data)
93 else:
94 print ("BMC Closed the connection")
95 self.conn.close()
96 self.tcp.close()
97 sys.exit(1)
98 elif s is self.tcp:
99 data = self.tcp.recv(MAX_NBD_PACKET_SIZE)
100 print(">>TCP")
Ravi Tejad8be0b42020-03-18 14:31:46 -0500101 if data:
102 self.conn.sock.send(data)
103 else:
104 print("NBD server closed the connection")
105 self.conn.sock.close()
106 self.tcp.close()
107 sys.exit(1)
108 for s in exceptional:
109 inputs.remove(s)
110 print("Exceptional closing the socket")
111 s.close()
112
113def getsize(host,args,session):
Ravi Tejabef8da42020-07-14 23:01:51 -0500114 url = "https://"+host+"/redfish/v1/Systems/system/LogServices/Dump/Entries/"+str(args.dumpNum)
Ravi Tejad8be0b42020-03-18 14:31:46 -0500115 try:
116 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
117 if resp.status_code==200:
Asmitha Karunanithi4e178112020-10-01 08:18:21 -0500118 size = resp.json()['AdditionalDataSizeBytes']
Ravi Tejad8be0b42020-03-18 14:31:46 -0500119 return size
120 else:
121 return "Failed get Size"
122 except(requests.exceptions.Timeout):
123 return connectionErrHandler(args.json, "Timeout", None)
124
125 except(requests.exceptions.ConnectionError) as err:
126 return connectionErrHandler(args.json, "ConnectionError", err)
127
128def gettoken(args):
129 mysess = requests.session()
130 resp = mysess.post('https://'+args.host+'/login', headers=jsonHeader,json={"data":[args.user,args.PW]},verify=False)
131 if resp.status_code == 200:
132 cookie = resp.headers['Set-Cookie']
133 match = re.search('SESSION=(\w+);', cookie)
134 return match.group(1)
135
136
137
138def get_pid(name):
139 try:
140 pid = map(int, check_output(["pidof", "-s",name]))
141 except Exception:
142 pid = 0
143
144 return pid
145
146def findThisProcess( process_name ):
147 ps = subprocess.Popen("ps -eaf | grep "+process_name, shell=True, stdout=subprocess.PIPE)
148 output = ps.stdout.read()
149 ps.stdout.close()
150 ps.wait()
151 pid = get_pid(process_name)
Ravi Tejad8be0b42020-03-18 14:31:46 -0500152 return output
153
154def isThisProcessRunning( process_name ):
155 pid = get_pid(process_name)
156 if (pid == 0 ):
157 return False
158 else:
159 return True
160
161def NBDSetup(host,args,session):
162 user=os.getenv("SUDO_USER")
163 if user is None:
164 path = os.getcwd()
165 nbdServerPath = path + "/nbd-server"
Ravi Tejad8be0b42020-03-18 14:31:46 -0500166 if not os.path.exists(nbdServerPath):
167 print("Error: this program did not run as sudo!\nplease copy nbd-server to current directory and run script again")
168 exit()
169
170 if isThisProcessRunning('nbd-server') == True:
171 print("nbd-server already Running! killing the nbd-server")
172 os.system('killall nbd-server')
173
174 if (args.dumpSaveLoc is not None):
175 if(os.path.exists(args.dumpSaveLoc)):
176 print("Error: File already exists.")
177 exit()
178
179 fp= open(args.dumpSaveLoc,"w")
180 sizeInBytes = getsize(host,args,session)
181 #Round off size to mutiples of 1024
182 size = int(sizeInBytes)
Ravi Tejad8be0b42020-03-18 14:31:46 -0500183 mod = size % 1024
184 if mod :
185 roundoff = 1024 - mod
186 size = size + roundoff
187
188 cmd = 'chmod 777 ' + args.dumpSaveLoc
189 os.system(cmd)
190
191 #Run truncate to create file with given size
192 cmd = 'truncate -s ' + str(size) + ' '+ args.dumpSaveLoc
193 os.system(cmd)
194
195 if user is None:
196 cmd = './nbd-server 1043 '+ args.dumpSaveLoc
197 else:
198 cmd = 'nbd-server 1043 '+ args.dumpSaveLoc
199 os.system(cmd)
200
201
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600202def hilight(textToColor, color, bold):
Justin Thalere412dc22018-01-12 16:28:24 -0600203 """
204 Used to add highlights to various text for displaying in a terminal
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600205
Justin Thalere412dc22018-01-12 16:28:24 -0600206 @param textToColor: string, the text to be colored
207 @param color: string, used to color the text red or green
208 @param bold: boolean, used to bold the textToColor
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600209 @return: Buffered reader containing the modified string.
210 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600211 if(sys.platform.__contains__("win")):
212 if(color == "red"):
213 os.system('color 04')
214 elif(color == "green"):
215 os.system('color 02')
216 else:
217 os.system('color') #reset to default
218 return textToColor
219 else:
220 attr = []
221 if(color == "red"):
222 attr.append('31')
223 elif(color == "green"):
224 attr.append('32')
225 else:
226 attr.append('0')
227 if bold:
228 attr.append('1')
229 else:
230 attr.append('0')
231 return '\x1b[%sm%s\x1b[0m' % (';'.join(attr),textToColor)
232
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600233def connectionErrHandler(jsonFormat, errorStr, err):
Justin Thalere412dc22018-01-12 16:28:24 -0600234 """
235 Error handler various connection errors to bmcs
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600236
237 @param jsonFormat: boolean, used to output in json format with an error code.
Justin Thalere412dc22018-01-12 16:28:24 -0600238 @param errorStr: string, used to color the text red or green
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600239 @param err: string, the text from the exception
240 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600241 if errorStr == "Timeout":
242 if not jsonFormat:
243 return("FQPSPIN0000M: Connection timed out. Ensure you have network connectivity to the bmc")
244 else:
Justin Thaler115bca72018-05-25 19:29:08 -0500245 conerror = {}
246 conerror['CommonEventID'] = 'FQPSPIN0000M'
247 conerror['sensor']="N/A"
248 conerror['state']="N/A"
249 conerror['additionalDetails'] = "N/A"
250 conerror['Message']="Connection timed out. Ensure you have network connectivity to the BMC"
251 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."
252 conerror['Serviceable']="Yes"
253 conerror['CallHomeCandidate']= "No"
254 conerror['Severity'] = "Critical"
255 conerror['EventType'] = "Communication Failure/Timeout"
256 conerror['VMMigrationFlag'] = "Yes"
257 conerror["AffectedSubsystem"] = "Interconnect (Networking)"
258 conerror["timestamp"] = str(int(time.time()))
259 conerror["UserAction"] = "Verify network connectivity between the two systems and the bmc is functional."
260 eventdict = {}
261 eventdict['event0'] = conerror
262 eventdict['numAlerts'] = '1'
Justin Thaler115bca72018-05-25 19:29:08 -0500263 errorMessageStr = errorMessageStr = json.dumps(eventdict, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600264 return(errorMessageStr)
265 elif errorStr == "ConnectionError":
266 if not jsonFormat:
267 return("FQPSPIN0001M: " + str(err))
268 else:
Justin Thaler115bca72018-05-25 19:29:08 -0500269 conerror = {}
270 conerror['CommonEventID'] = 'FQPSPIN0001M'
271 conerror['sensor']="N/A"
272 conerror['state']="N/A"
273 conerror['additionalDetails'] = str(err)
274 conerror['Message']="Connection Error. View additional details for more information"
275 conerror['LengthyDescription'] = "A connection error to the specified BMC occurred and additional details are provided. Review these details to resolve the issue."
276 conerror['Serviceable']="Yes"
277 conerror['CallHomeCandidate']= "No"
278 conerror['Severity'] = "Critical"
279 conerror['EventType'] = "Communication Failure/Timeout"
280 conerror['VMMigrationFlag'] = "Yes"
281 conerror["AffectedSubsystem"] = "Interconnect (Networking)"
282 conerror["timestamp"] = str(int(time.time()))
283 conerror["UserAction"] = "Correct the issue highlighted in additional details and try again"
284 eventdict = {}
285 eventdict['event0'] = conerror
286 eventdict['numAlerts'] = '1'
Justin Thaler115bca72018-05-25 19:29:08 -0500287 errorMessageStr = json.dumps(eventdict, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600288 return(errorMessageStr)
Justin Thaler115bca72018-05-25 19:29:08 -0500289
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600290 else:
291 return("Unknown Error: "+ str(err))
292
Justin Thalere412dc22018-01-12 16:28:24 -0600293
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600294def setColWidth(keylist, numCols, dictForOutput, colNames):
Justin Thalere412dc22018-01-12 16:28:24 -0600295 """
296 Sets the output width of the columns to display
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600297
298 @param keylist: list, list of strings representing the keys for the dictForOutput
Justin Thalere412dc22018-01-12 16:28:24 -0600299 @param numcols: the total number of columns in the final output
300 @param dictForOutput: dictionary, contains the information to print to the screen
301 @param colNames: list, The strings to use for the column headings, in order of the keylist
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600302 @return: A list of the column widths for each respective column.
Justin Thalere412dc22018-01-12 16:28:24 -0600303 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600304 colWidths = []
305 for x in range(0, numCols):
306 colWidths.append(0)
307 for key in dictForOutput:
308 for x in range(0, numCols):
309 colWidths[x] = max(colWidths[x], len(str(dictForOutput[key][keylist[x]])))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600310
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600311 for x in range(0, numCols):
312 colWidths[x] = max(colWidths[x], len(colNames[x])) +2
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600313
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600314 return colWidths
315
316def loadPolicyTable(pathToPolicyTable):
Justin Thalere412dc22018-01-12 16:28:24 -0600317 """
318 loads a json based policy table into a dictionary
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600319
Justin Thalere412dc22018-01-12 16:28:24 -0600320 @param value: boolean, the value to convert
321 @return: A string of "Yes" or "No"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600322 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600323 policyTable = {}
324 if(os.path.exists(pathToPolicyTable)):
325 with open(pathToPolicyTable, 'r') as stream:
326 try:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600327 contents =json.load(stream)
328 policyTable = contents['events']
Justin Thalere412dc22018-01-12 16:28:24 -0600329 except Exception as err:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600330 print(err)
331 return policyTable
332
Justin Thalere412dc22018-01-12 16:28:24 -0600333
334def boolToString(value):
335 """
336 converts a boolean value to a human readable string value
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600337
Justin Thalere412dc22018-01-12 16:28:24 -0600338 @param value: boolean, the value to convert
339 @return: A string of "Yes" or "No"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600340 """
Justin Thalere412dc22018-01-12 16:28:24 -0600341 if(value):
342 return "Yes"
343 else:
344 return "No"
345
Justin Thalera6b5df72018-07-16 11:10:07 -0500346def stringToInt(text):
347 """
348 returns an integer if the string can be converted, otherwise returns the string
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600349
Justin Thalera6b5df72018-07-16 11:10:07 -0500350 @param text: the string to try to convert to an integer
351 """
352 if text.isdigit():
353 return int(text)
354 else:
355 return text
Justin Thalere412dc22018-01-12 16:28:24 -0600356
Justin Thalera6b5df72018-07-16 11:10:07 -0500357def naturalSort(text):
358 """
359 provides a way to naturally sort a list
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600360
Justin Thalera6b5df72018-07-16 11:10:07 -0500361 @param text: the key to convert for sorting
362 @return list containing the broken up string parts by integers and strings
363 """
364 stringPartList = []
365 for c in re.split('(\d+)', text):
366 stringPartList.append(stringToInt(c))
367 return stringPartList
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600368
Justin Thalere412dc22018-01-12 16:28:24 -0600369def tableDisplay(keylist, colNames, output):
370 """
371 Logs into the BMC and creates a session
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600372
Justin Thalere412dc22018-01-12 16:28:24 -0600373 @param keylist: list, keys for the output dictionary, ordered by colNames
374 @param colNames: Names for the Table of the columns
375 @param output: The dictionary of data to display
376 @return: Session object
377 """
378 colWidth = setColWidth(keylist, len(colNames), output, colNames)
379 row = ""
380 outputText = ""
381 for i in range(len(colNames)):
382 if (i != 0): row = row + "| "
383 row = row + colNames[i].ljust(colWidth[i])
384 outputText += row + "\n"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600385
Justin Thalera6b5df72018-07-16 11:10:07 -0500386 output_keys = list(output.keys())
387 output_keys.sort(key=naturalSort)
388 for key in output_keys:
Justin Thalere412dc22018-01-12 16:28:24 -0600389 row = ""
Justin Thaler8fe0c732018-07-24 14:32:35 -0500390 for i in range(len(keylist)):
Justin Thalere412dc22018-01-12 16:28:24 -0600391 if (i != 0): row = row + "| "
392 row = row + output[key][keylist[i]].ljust(colWidth[i])
393 outputText += row + "\n"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600394
Justin Thalere412dc22018-01-12 16:28:24 -0600395 return outputText
396
Justin Thaler22b1bb52018-03-15 13:31:32 -0500397def checkFWactivation(host, args, session):
398 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600399 Checks the software inventory for an image that is being activated.
400
Justin Thaler22b1bb52018-03-15 13:31:32 -0500401 @return: True if an image is being activated, false is no activations are happening
402 """
403 url="https://"+host+"/xyz/openbmc_project/software/enumerate"
Justin Thaler22b1bb52018-03-15 13:31:32 -0500404 try:
Justin Thaler27197622019-01-23 14:42:11 -0600405 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thaler22b1bb52018-03-15 13:31:32 -0500406 except(requests.exceptions.Timeout):
407 print(connectionErrHandler(args.json, "Timeout", None))
408 return(True)
409 except(requests.exceptions.ConnectionError) as err:
410 print( connectionErrHandler(args.json, "ConnectionError", err))
411 return True
Justin Thaler3a5771b2019-01-23 14:31:52 -0600412 fwInfo = resp.json()['data']
Justin Thaler22b1bb52018-03-15 13:31:32 -0500413 for key in fwInfo:
414 if 'Activation' in fwInfo[key]:
415 if 'Activating' in fwInfo[key]['Activation'] or 'Activating' in fwInfo[key]['RequestedActivation']:
416 return True
417 return False
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600418
Joy Onyerikwu182c3a32019-10-15 08:33:59 -0500419def login(host, username, pw,jsonFormat, allowExpiredPassword):
Justin Thalere412dc22018-01-12 16:28:24 -0600420 """
421 Logs into the BMC and creates a session
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600422
Justin Thalere412dc22018-01-12 16:28:24 -0600423 @param host: string, the hostname or IP address of the bmc to log into
424 @param username: The user name for the bmc to log into
425 @param pw: The password for the BMC to log into
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600426 @param jsonFormat: boolean, flag that will only allow relevant data from user command to be display. This function becomes silent when set to true.
Joy Onyerikwu182c3a32019-10-15 08:33:59 -0500427 @param allowExpiredPassword: true, if the requested operation should
428 be allowed when the password is expired
Justin Thalere412dc22018-01-12 16:28:24 -0600429 @return: Session object
430 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600431 if(jsonFormat==False):
432 print("Attempting login...")
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600433 mysess = requests.session()
434 try:
Justin Thaler27197622019-01-23 14:42:11 -0600435 r = mysess.post('https://'+host+'/login', headers=jsonHeader, json = {"data": [username, pw]}, verify=False, timeout=baseTimeout)
Sunitha Harish336cda22019-07-23 02:02:52 -0500436 if r.status_code == 200:
437 cookie = r.headers['Set-Cookie']
438 match = re.search('SESSION=(\w+);', cookie)
439 if match:
440 xAuthHeader['X-Auth-Token'] = match.group(1)
441 jsonHeader.update(xAuthHeader)
442 loginMessage = json.loads(r.text)
443 if (loginMessage['status'] != "ok"):
444 print(loginMessage["data"]["description"].encode('utf-8'))
445 sys.exit(1)
Joy Onyerikwu182c3a32019-10-15 08:33:59 -0500446 if (('extendedMessage' in r.json()) and
447 ('The password for this account must be changed' in r.json()['extendedMessage'])):
448 if not allowExpiredPassword:
449 print("The password for this system has expired and must be changed"+
450 "\nsee openbmctool.py set_password --help")
451 logout(host, username, pw, mysess, jsonFormat)
452 sys.exit(1)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600453# if(sys.version_info < (3,0)):
454# urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
455# if sys.version_info >= (3,0):
456# requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)
Sunitha Harish336cda22019-07-23 02:02:52 -0500457 return mysess
458 else:
459 return None
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600460 except(requests.exceptions.Timeout):
Justin Thaler115bca72018-05-25 19:29:08 -0500461 return (connectionErrHandler(jsonFormat, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600462 except(requests.exceptions.ConnectionError) as err:
Justin Thaler115bca72018-05-25 19:29:08 -0500463 return (connectionErrHandler(jsonFormat, "ConnectionError", err))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600464
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600465
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600466def logout(host, username, pw, session, jsonFormat):
Justin Thalere412dc22018-01-12 16:28:24 -0600467 """
468 Logs out of the bmc and terminates the session
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600469
Justin Thalere412dc22018-01-12 16:28:24 -0600470 @param host: string, the hostname or IP address of the bmc to log out of
471 @param username: The user name for the bmc to log out of
472 @param pw: The password for the BMC to log out of
473 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600474 @param jsonFormat: boolean, flag that will only allow relevant data from user command to be display. This function becomes silent when set to true.
475 """
Justin Thalere412dc22018-01-12 16:28:24 -0600476 try:
Justin Thaler27197622019-01-23 14:42:11 -0600477 r = session.post('https://'+host+'/logout', headers=jsonHeader,json = {"data": [username, pw]}, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600478 except(requests.exceptions.Timeout):
479 print(connectionErrHandler(jsonFormat, "Timeout", None))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600480
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600481 if(jsonFormat==False):
Matt Spinlereae05b02019-01-24 12:59:34 -0600482 if r.status_code == 200:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600483 print('User ' +username + ' has been logged out')
484
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600485
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600486def fru(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -0600487 """
488 prints out the system inventory. deprecated see fruPrint and fruList
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600489
Justin Thalere412dc22018-01-12 16:28:24 -0600490 @param host: string, the hostname or IP address of the bmc
491 @param args: contains additional arguments used by the fru sub command
492 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600493 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
494 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600495 #url="https://"+host+"/org/openbmc/inventory/system/chassis/enumerate"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600496
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600497 #print(url)
498 #res = session.get(url, headers=httpHeader, verify=False)
499 #print(res.text)
500 #sample = res.text
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600501
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600502 #inv_list = json.loads(sample)["data"]
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600503
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600504 url="https://"+host+"/xyz/openbmc_project/inventory/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600505 try:
Justin Thaler27197622019-01-23 14:42:11 -0600506 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600507 except(requests.exceptions.Timeout):
508 return(connectionErrHandler(args.json, "Timeout", None))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600509
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600510 sample = res.text
511# inv_list.update(json.loads(sample)["data"])
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600512#
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600513# #determine column width's
514# colNames = ["FRU Name", "FRU Type", "Has Fault", "Is FRU", "Present", "Version"]
515# colWidths = setColWidth(["FRU Name", "fru_type", "fault", "is_fru", "present", "version"], 6, inv_list, colNames)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600516#
517# 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 -0600518# "Present".ljust(colWidths[4]) + "Version".ljust(colWidths[5]))
519# format the output
520# for key in sorted(inv_list.keys()):
521# keyParts = key.split("/")
522# isFRU = "True" if (inv_list[key]["is_fru"]==1) else "False"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600523#
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600524# fruEntry = (keyParts[len(keyParts) - 1].ljust(colWidths[0]) + inv_list[key]["fru_type"].ljust(colWidths[1])+
525# inv_list[key]["fault"].ljust(colWidths[2])+isFRU.ljust(colWidths[3])+
526# inv_list[key]["present"].ljust(colWidths[4])+ inv_list[key]["version"].ljust(colWidths[5]))
527# if(isTTY):
528# if(inv_list[key]["is_fru"] == 1):
529# color = "green"
530# bold = True
531# else:
532# color='black'
533# bold = False
534# fruEntry = hilight(fruEntry, color, bold)
535# print (fruEntry)
536 return sample
Justin Thalere412dc22018-01-12 16:28:24 -0600537
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600538def fruPrint(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -0600539 """
540 prints out all inventory
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600541
Justin Thalere412dc22018-01-12 16:28:24 -0600542 @param host: string, the hostname or IP address of the bmc
543 @param args: contains additional arguments used by the fru sub command
544 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600545 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
546 @return returns the total fru list.
547 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600548 url="https://"+host+"/xyz/openbmc_project/inventory/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600549 try:
Justin Thaler27197622019-01-23 14:42:11 -0600550 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600551 except(requests.exceptions.Timeout):
552 return(connectionErrHandler(args.json, "Timeout", None))
553
Justin Thaler3a5771b2019-01-23 14:31:52 -0600554 frulist={}
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600555# print(res.text)
Justin Thaler3a5771b2019-01-23 14:31:52 -0600556 if res.status_code==200:
557 frulist['Hardware'] = res.json()['data']
558 else:
559 if not args.json:
560 return "Error retrieving the system inventory. BMC message: {msg}".format(msg=res.json()['message'])
561 else:
562 return res.json()
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600563 url="https://"+host+"/xyz/openbmc_project/software/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600564 try:
Justin Thaler27197622019-01-23 14:42:11 -0600565 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600566 except(requests.exceptions.Timeout):
567 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600568# print(res.text)
Justin Thaler3a5771b2019-01-23 14:31:52 -0600569 if res.status_code==200:
570 frulist['Software'] = res.json()['data']
571 else:
572 if not args.json():
573 return "Error retrieving the system inventory. BMC message: {msg}".format(msg=res.json()['message'])
574 else:
575 return res.json()
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600576 return frulist
577
Justin Thalere412dc22018-01-12 16:28:24 -0600578
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600579def fruList(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -0600580 """
581 prints out all inventory or only a specific specified item
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 fru 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 if(args.items==True):
589 return fruPrint(host, args, session)
590 else:
Justin Thalere412dc22018-01-12 16:28:24 -0600591 return fruPrint(host, args, session)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600592
593
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600594
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600595def fruStatus(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -0600596 """
597 prints out the status of all FRUs
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600598
Justin Thalere412dc22018-01-12 16:28:24 -0600599 @param host: string, the hostname or IP address of the bmc
600 @param args: contains additional arguments used by the fru sub command
601 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600602 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
603 """
Justin Thalere412dc22018-01-12 16:28:24 -0600604 url="https://"+host+"/xyz/openbmc_project/inventory/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600605 try:
Matt Spinler220c3c42019-01-04 15:09:29 -0600606 res = session.get(url, headers=jsonHeader, verify=False)
Justin Thalere412dc22018-01-12 16:28:24 -0600607 except(requests.exceptions.Timeout):
608 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600609# print(res.text)
Justin Thaler3a5771b2019-01-23 14:31:52 -0600610 frulist = res.json()['data']
Justin Thalere412dc22018-01-12 16:28:24 -0600611 frus = {}
612 for key in frulist:
613 component = frulist[key]
614 isFru = False
615 present = False
616 func = False
617 hasSels = False
618 keyPieces = key.split('/')
619 fruName = keyPieces[-1]
620 if 'core' in fruName: #associate cores to cpus
621 fruName = keyPieces[-2] + '-' + keyPieces[-1]
622 if 'Functional' in component:
623 if('Present' in component):
Justin Thalere412dc22018-01-12 16:28:24 -0600624 if 'FieldReplaceable' in component:
625 if component['FieldReplaceable'] == 1:
626 isFru = True
627 if "fan" in fruName:
628 isFru = True;
629 if component['Present'] == 1:
630 present = True
631 if component['Functional'] == 1:
632 func = True
633 if ((key + "/fault") in frulist):
634 hasSels = True;
635 if args.verbose:
636 if hasSels:
637 loglist = []
638 faults = frulist[key+"/fault"]['endpoints']
639 for item in faults:
640 loglist.append(item.split('/')[-1])
641 frus[fruName] = {"compName": fruName, "Functional": boolToString(func), "Present":boolToString(present), "IsFru": boolToString(isFru), "selList": ', '.join(loglist).strip() }
642 else:
643 frus[fruName] = {"compName": fruName, "Functional": boolToString(func), "Present":boolToString(present), "IsFru": boolToString(isFru), "selList": "None" }
644 else:
645 frus[fruName] = {"compName": fruName, "Functional": boolToString(func), "Present":boolToString(present), "IsFru": boolToString(isFru), "hasSEL": boolToString(hasSels) }
Justin Thalerfb9c81c2018-07-16 11:14:37 -0500646 elif "power_supply" in fruName or "powersupply" in fruName:
Justin Thalere412dc22018-01-12 16:28:24 -0600647 if component['Present'] ==1:
648 present = True
649 isFru = True
650 if ((key + "/fault") in frulist):
651 hasSels = True;
652 if args.verbose:
653 if hasSels:
654 loglist = []
655 faults = frulist[key+"/fault"]['endpoints']
Obihörnchenff8035f2018-12-05 21:07:37 +0100656 for item in faults:
657 loglist.append(item.split('/')[-1])
Justin Thalere412dc22018-01-12 16:28:24 -0600658 frus[fruName] = {"compName": fruName, "Functional": "No", "Present":boolToString(present), "IsFru": boolToString(isFru), "selList": ', '.join(loglist).strip() }
659 else:
660 frus[fruName] = {"compName": fruName, "Functional": "Yes", "Present":boolToString(present), "IsFru": boolToString(isFru), "selList": "None" }
661 else:
662 frus[fruName] = {"compName": fruName, "Functional": boolToString(not hasSels), "Present":boolToString(present), "IsFru": boolToString(isFru), "hasSEL": boolToString(hasSels) }
663 if not args.json:
664 if not args.verbose:
665 colNames = ["Component", "Is a FRU", "Present", "Functional", "Has Logs"]
666 keylist = ["compName", "IsFru", "Present", "Functional", "hasSEL"]
667 else:
668 colNames = ["Component", "Is a FRU", "Present", "Functional", "Assoc. Log Number(s)"]
669 keylist = ["compName", "IsFru", "Present", "Functional", "selList"]
670 return tableDisplay(keylist, colNames, frus)
671 else:
672 return str(json.dumps(frus, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600673
Justin Thalere412dc22018-01-12 16:28:24 -0600674def sensor(host, args, session):
675 """
676 prints out all sensors
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600677
Justin Thalere412dc22018-01-12 16:28:24 -0600678 @param host: string, the hostname or IP address of the bmc
679 @param args: contains additional arguments used by the sensor sub command
680 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600681 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
682 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600683 url="https://"+host+"/xyz/openbmc_project/sensors/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600684 try:
Justin Thaler27197622019-01-23 14:42:11 -0600685 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600686 except(requests.exceptions.Timeout):
687 return(connectionErrHandler(args.json, "Timeout", None))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600688
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600689 #Get OCC status
690 url="https://"+host+"/org/open_power/control/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600691 try:
Justin Thaler27197622019-01-23 14:42:11 -0600692 occres = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600693 except(requests.exceptions.Timeout):
694 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600695 if not args.json:
696 colNames = ['sensor', 'type', 'units', 'value', 'target']
Justin Thaler3a5771b2019-01-23 14:31:52 -0600697 sensors = res.json()["data"]
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600698 output = {}
699 for key in sensors:
700 senDict = {}
701 keyparts = key.split("/")
Matt Spinler596ef742019-09-20 08:54:36 -0500702
703 # Associations like the following also show up here:
704 # /xyz/openbmc_project/sensors/<type>/<name>/<assoc-name>
705 # Skip them.
706 # Note: keyparts[0] = '' which is why there are 7 segments.
707 if len(keyparts) > 6:
708 continue
709
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600710 senDict['sensorName'] = keyparts[-1]
711 senDict['type'] = keyparts[-2]
Justin Thalere412dc22018-01-12 16:28:24 -0600712 try:
713 senDict['units'] = sensors[key]['Unit'].split('.')[-1]
714 except KeyError:
Justin Thaler22b1bb52018-03-15 13:31:32 -0500715 senDict['units'] = "N/A"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600716 if('Scale' in sensors[key]):
717 scale = 10 ** sensors[key]['Scale']
718 else:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600719 scale = 1
Justin Thaler22b1bb52018-03-15 13:31:32 -0500720 try:
721 senDict['value'] = str(sensors[key]['Value'] * scale)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600722 except KeyError:
Justin Thaler22b1bb52018-03-15 13:31:32 -0500723 if 'value' in sensors[key]:
724 senDict['value'] = sensors[key]['value']
725 else:
726 senDict['value'] = "N/A"
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600727 if 'Target' in sensors[key]:
728 senDict['target'] = str(sensors[key]['Target'])
729 else:
730 senDict['target'] = 'N/A'
731 output[senDict['sensorName']] = senDict
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600732
Justin Thaler3a5771b2019-01-23 14:31:52 -0600733 occstatus = occres.json()["data"]
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600734 if '/org/open_power/control/occ0' in occstatus:
735 occ0 = occstatus["/org/open_power/control/occ0"]['OccActive']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600736 if occ0 == 1:
737 occ0 = 'Active'
738 else:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600739 occ0 = 'Inactive'
740 output['OCC0'] = {'sensorName':'OCC0', 'type': 'Discrete', 'units': 'N/A', 'value': occ0, 'target': 'Active'}
741 occ1 = occstatus["/org/open_power/control/occ1"]['OccActive']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600742 if occ1 == 1:
743 occ1 = 'Active'
744 else:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600745 occ1 = 'Inactive'
746 output['OCC1'] = {'sensorName':'OCC1', 'type': 'Discrete', 'units': 'N/A', 'value': occ0, 'target': 'Active'}
747 else:
748 output['OCC0'] = {'sensorName':'OCC0', 'type': 'Discrete', 'units': 'N/A', 'value': 'Inactive', 'target': 'Inactive'}
749 output['OCC1'] = {'sensorName':'OCC1', 'type': 'Discrete', 'units': 'N/A', 'value': 'Inactive', 'target': 'Inactive'}
750 keylist = ['sensorName', 'type', 'units', 'value', 'target']
Justin Thalere412dc22018-01-12 16:28:24 -0600751
752 return tableDisplay(keylist, colNames, output)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600753 else:
754 return res.text + occres.text
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600755
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600756def sel(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -0600757 """
758 prints out the bmc alerts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600759
Justin Thalere412dc22018-01-12 16:28:24 -0600760 @param host: string, the hostname or IP address of the bmc
761 @param args: contains additional arguments used by the sel sub command
762 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600763 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
764 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600765
766 url="https://"+host+"/xyz/openbmc_project/logging/entry/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600767 try:
Justin Thaler27197622019-01-23 14:42:11 -0600768 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600769 except(requests.exceptions.Timeout):
770 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600771 return res.text
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600772
773
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600774def parseESEL(args, eselRAW):
Justin Thalere412dc22018-01-12 16:28:24 -0600775 """
776 parses the esel data and gets predetermined search terms
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600777
Justin Thalere412dc22018-01-12 16:28:24 -0600778 @param eselRAW: string, the raw esel string from the bmc
779 @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 -0600780 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600781 eselParts = {}
782 esel_bin = binascii.unhexlify(''.join(eselRAW.split()[16:]))
783 #search terms contains the search term as the key and the return dictionary key as it's value
784 searchTerms = { 'Signature Description':'signatureDescription', 'devdesc':'devdesc',
Justin Thaler22b1bb52018-03-15 13:31:32 -0500785 'Callout type': 'calloutType', 'Procedure':'procedure', 'Sensor Type': 'sensorType'}
Justin Thaler24d4efa2018-11-08 22:48:10 -0600786 uniqueID = str(uuid.uuid4())
787 eselBinPath = tempfile.gettempdir() + os.sep + uniqueID + 'esel.bin'
Justin Thalercf1deae2018-05-25 19:35:21 -0500788 with open(eselBinPath, 'wb') as f:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600789 f.write(esel_bin)
790 errlPath = ""
791 #use the right errl file for the machine architecture
792 arch = platform.machine()
793 if(arch =='x86_64' or arch =='AMD64'):
794 if os.path.exists('/opt/ibm/ras/bin/x86_64/errl'):
795 errlPath = '/opt/ibm/ras/bin/x86_64/errl'
796 elif os.path.exists('errl/x86_64/errl'):
797 errlPath = 'errl/x86_64/errl'
798 else:
799 errlPath = 'x86_64/errl'
800 elif (platform.machine()=='ppc64le'):
801 if os.path.exists('/opt/ibm/ras/bin/ppc64le/errl'):
802 errlPath = '/opt/ibm/ras/bin/ppc64le/errl'
803 elif os.path.exists('errl/ppc64le/errl'):
804 errlPath = 'errl/ppc64le/errl'
805 else:
806 errlPath = 'ppc64le/errl'
807 else:
808 print("machine architecture not supported for parsing eSELs")
809 return eselParts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600810
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600811 if(os.path.exists(errlPath)):
Justin Thalercf1deae2018-05-25 19:35:21 -0500812 output= subprocess.check_output([errlPath, '-d', '--file='+eselBinPath]).decode('utf-8')
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600813# output = proc.communicate()[0]
814 lines = output.split('\n')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600815
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600816 if(hasattr(args, 'fullEsel')):
817 return output
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600818
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600819 for i in range(0, len(lines)):
820 lineParts = lines[i].split(':')
821 if(len(lineParts)>1): #ignore multi lines, output formatting lines, and other information
822 for term in searchTerms:
823 if(term in lineParts[0]):
824 temp = lines[i][lines[i].find(':')+1:].strip()[:-1].strip()
825 if lines[i+1].find(':') != -1:
826 if (len(lines[i+1].split(':')[0][1:].strip())==0):
827 while(len(lines[i][:lines[i].find(':')].strip())>2):
Justin Thaler43030422018-11-08 22:50:21 -0600828 #has multiple lines, process and update line counter
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600829 if((i+1) <= len(lines)):
830 i+=1
831 else:
832 i=i-1
833 break
Justin Thaler43030422018-11-08 22:50:21 -0600834 #Append the content from the next line removing the pretty display characters
835 #Finds the first colon then starts 2 characters after, then removes all whitespace
836 temp = temp + lines[i][lines[i].find(':')+2:].strip()[:-1].strip()[:-1].strip()
Justin Thaler22b1bb52018-03-15 13:31:32 -0500837 if(searchTerms[term] in eselParts):
838 eselParts[searchTerms[term]] = eselParts[searchTerms[term]] + ", " + temp
839 else:
840 eselParts[searchTerms[term]] = temp
Justin Thalercf1deae2018-05-25 19:35:21 -0500841 os.remove(eselBinPath)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600842 else:
843 print("errl file cannot be found")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600844
845 return eselParts
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600846
Justin Thalere412dc22018-01-12 16:28:24 -0600847
Matt Spinler02d0dff2018-08-29 13:19:25 -0500848def getESELSeverity(esel):
849 """
850 Finds the severity type in an eSEL from the User Header section.
851 @param esel - the eSEL data
852 @return severity - e.g. 'Critical'
853 """
854
855 # everything but 1 and 2 are Critical
856 # '1': 'recovered',
857 # '2': 'predictive',
858 # '4': 'unrecoverable',
859 # '5': 'critical',
860 # '6': 'diagnostic',
861 # '7': 'symptom'
862 severities = {
863 '1': 'Informational',
864 '2': 'Warning'
865 }
866
867 try:
868 headerPosition = esel.index('55 48') # 'UH'
869 # The severity is the last byte in the 8 byte section (a byte is ' bb')
870 severity = esel[headerPosition:headerPosition+32].split(' ')[-1]
871 type = severity[0]
872 except ValueError:
873 print("Could not find severity value in UH section in eSEL")
874 type = 'x';
875
876 return severities.get(type, 'Critical')
877
878
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600879def sortSELs(events):
Justin Thalere412dc22018-01-12 16:28:24 -0600880 """
881 sorts the sels by timestamp, then log entry number
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600882
Justin Thalere412dc22018-01-12 16:28:24 -0600883 @param events: Dictionary containing events
884 @return: list containing a list of the ordered log entries, and dictionary of keys
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600885 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600886 logNumList = []
887 timestampList = []
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600888 eventKeyDict = {}
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600889 eventsWithTimestamp = {}
890 logNum2events = {}
891 for key in events:
892 if key == 'numAlerts': continue
893 if 'callout' in key: continue
894 timestamp = (events[key]['timestamp'])
895 if timestamp not in timestampList:
896 eventsWithTimestamp[timestamp] = [events[key]['logNum']]
897 else:
898 eventsWithTimestamp[timestamp].append(events[key]['logNum'])
899 #map logNumbers to the event dictionary keys
900 eventKeyDict[str(events[key]['logNum'])] = key
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600901
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600902 timestampList = list(eventsWithTimestamp.keys())
903 timestampList.sort()
904 for ts in timestampList:
905 if len(eventsWithTimestamp[ts]) > 1:
906 tmplist = eventsWithTimestamp[ts]
907 tmplist.sort()
908 logNumList = logNumList + tmplist
909 else:
910 logNumList = logNumList + eventsWithTimestamp[ts]
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600911
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600912 return [logNumList, eventKeyDict]
913
Justin Thalere412dc22018-01-12 16:28:24 -0600914
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600915def parseAlerts(policyTable, selEntries, args):
Justin Thalere412dc22018-01-12 16:28:24 -0600916 """
917 parses alerts in the IBM CER format, using an IBM policy Table
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600918
Justin Thalere412dc22018-01-12 16:28:24 -0600919 @param policyTable: dictionary, the policy table entries
920 @param selEntries: dictionary, the alerts retrieved from the bmc
921 @return: A dictionary of the parsed entries, in chronological order
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600922 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600923 eventDict = {}
924 eventNum =""
925 count = 0
926 esel = ""
927 eselParts = {}
928 i2cdevice= ""
Matt Spinler02d0dff2018-08-29 13:19:25 -0500929 eselSeverity = None
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600930
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600931 'prepare and sort the event entries'
Justin Thaler667f87c2020-04-06 16:13:12 -0500932 sels = {}
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600933 for key in selEntries:
Justin Thaler667f87c2020-04-06 16:13:12 -0500934 if '/xyz/openbmc_project/logging/entry/' not in key: continue
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600935 if 'callout' not in key:
Justin Thaler667f87c2020-04-06 16:13:12 -0500936 sels[key] = selEntries[key]
937 sels[key]['logNum'] = key.split('/')[-1]
938 sels[key]['timestamp'] = selEntries[key]['Timestamp']
939 sortedEntries = sortSELs(sels)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600940 logNumList = sortedEntries[0]
941 eventKeyDict = sortedEntries[1]
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600942
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600943 for logNum in logNumList:
944 key = eventKeyDict[logNum]
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600945 hasEsel=False
946 i2creadFail = False
947 if 'callout' in key:
948 continue
949 else:
950 messageID = str(selEntries[key]['Message'])
951 addDataPiece = selEntries[key]['AdditionalData']
952 calloutIndex = 0
953 calloutFound = False
954 for i in range(len(addDataPiece)):
955 if("CALLOUT_INVENTORY_PATH" in addDataPiece[i]):
956 calloutIndex = i
957 calloutFound = True
958 fruCallout = str(addDataPiece[calloutIndex]).split('=')[1]
959 if("CALLOUT_DEVICE_PATH" in addDataPiece[i]):
960 i2creadFail = True
Matt Spinlerd178a472018-08-31 09:48:52 -0500961
962 fruCallout = str(addDataPiece[calloutIndex]).split('=')[1]
963
964 # Fall back to "I2C"/"FSI" if dev path isn't in policy table
965 if (messageID + '||' + fruCallout) not in policyTable:
966 i2cdevice = str(addDataPiece[i]).strip().split('=')[1]
967 i2cdevice = '/'.join(i2cdevice.split('/')[-4:])
968 if 'fsi' in str(addDataPiece[calloutIndex]).split('=')[1]:
969 fruCallout = 'FSI'
970 else:
971 fruCallout = 'I2C'
Justin Thalere34c43a2018-05-25 19:37:55 -0500972 calloutFound = True
973 if("CALLOUT_GPIO_NUM" in addDataPiece[i]):
974 if not calloutFound:
975 fruCallout = 'GPIO'
976 calloutFound = True
977 if("CALLOUT_IIC_BUS" in addDataPiece[i]):
978 if not calloutFound:
979 fruCallout = "I2C"
980 calloutFound = True
981 if("CALLOUT_IPMI_SENSOR_NUM" in addDataPiece[i]):
982 if not calloutFound:
983 fruCallout = "IPMI"
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600984 calloutFound = True
985 if("ESEL" in addDataPiece[i]):
986 esel = str(addDataPiece[i]).strip().split('=')[1]
Matt Spinler02d0dff2018-08-29 13:19:25 -0500987 eselSeverity = getESELSeverity(esel)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600988 if args.devdebug:
989 eselParts = parseESEL(args, esel)
990 hasEsel=True
991 if("GPU" in addDataPiece[i]):
992 fruCallout = '/xyz/openbmc_project/inventory/system/chassis/motherboard/gpu' + str(addDataPiece[i]).strip()[-1]
993 calloutFound = True
994 if("PROCEDURE" in addDataPiece[i]):
995 fruCallout = str(hex(int(str(addDataPiece[i]).split('=')[1])))[2:]
996 calloutFound = True
Justin Thalere412dc22018-01-12 16:28:24 -0600997 if("RAIL_NAME" in addDataPiece[i]):
998 calloutFound=True
999 fruCallout = str(addDataPiece[i]).split('=')[1].strip()
1000 if("INPUT_NAME" in addDataPiece[i]):
1001 calloutFound=True
1002 fruCallout = str(addDataPiece[i]).split('=')[1].strip()
1003 if("SENSOR_TYPE" in addDataPiece[i]):
1004 calloutFound=True
1005 fruCallout = str(addDataPiece[i]).split('=')[1].strip()
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001006
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001007 if(calloutFound):
Justin Thaler667f87c2020-04-06 16:13:12 -05001008 if fruCallout.strip() != "":
Justin Thaler22b1bb52018-03-15 13:31:32 -05001009 policyKey = messageID +"||" + fruCallout
Matt Spinler02d0dff2018-08-29 13:19:25 -05001010
1011 # Also use the severity for hostboot errors
1012 if eselSeverity and messageID == 'org.open_power.Host.Error.Event':
1013 policyKey += '||' + eselSeverity
1014
1015 # if not in the table, fall back to the original key
1016 if policyKey not in policyTable:
1017 policyKey = policyKey.replace('||'+eselSeverity, '')
1018
Justin Thalere34c43a2018-05-25 19:37:55 -05001019 if policyKey not in policyTable:
1020 policyKey = messageID
Justin Thaler22b1bb52018-03-15 13:31:32 -05001021 else:
1022 policyKey = messageID
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001023 else:
1024 policyKey = messageID
1025 event = {}
1026 eventNum = str(count)
1027 if policyKey in policyTable:
1028 for pkey in policyTable[policyKey]:
1029 if(type(policyTable[policyKey][pkey])== bool):
1030 event[pkey] = boolToString(policyTable[policyKey][pkey])
1031 else:
1032 if (i2creadFail and pkey == 'Message'):
1033 event[pkey] = policyTable[policyKey][pkey] + ' ' +i2cdevice
1034 else:
1035 event[pkey] = policyTable[policyKey][pkey]
1036 event['timestamp'] = selEntries[key]['Timestamp']
1037 event['resolved'] = bool(selEntries[key]['Resolved'])
1038 if(hasEsel):
1039 if args.devdebug:
1040 event['eselParts'] = eselParts
1041 event['raweSEL'] = esel
1042 event['logNum'] = key.split('/')[-1]
1043 eventDict['event' + eventNum] = event
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001044
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001045 else:
1046 severity = str(selEntries[key]['Severity']).split('.')[-1]
1047 if severity == 'Error':
1048 severity = 'Critical'
1049 eventDict['event'+eventNum] = {}
1050 eventDict['event' + eventNum]['error'] = "error: Not found in policy table: " + policyKey
1051 eventDict['event' + eventNum]['timestamp'] = selEntries[key]['Timestamp']
1052 eventDict['event' + eventNum]['Severity'] = severity
1053 if(hasEsel):
1054 if args.devdebug:
1055 eventDict['event' +eventNum]['eselParts'] = eselParts
1056 eventDict['event' +eventNum]['raweSEL'] = esel
1057 eventDict['event' +eventNum]['logNum'] = key.split('/')[-1]
1058 eventDict['event' +eventNum]['resolved'] = bool(selEntries[key]['Resolved'])
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001059 count += 1
1060 return eventDict
1061
1062
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001063def selDisplay(events, args):
Justin Thalere412dc22018-01-12 16:28:24 -06001064 """
1065 displays alerts in human readable format
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001066
Justin Thalere412dc22018-01-12 16:28:24 -06001067 @param events: Dictionary containing events
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001068 @return:
1069 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001070 activeAlerts = []
1071 historyAlerts = []
1072 sortedEntries = sortSELs(events)
1073 logNumList = sortedEntries[0]
1074 eventKeyDict = sortedEntries[1]
1075 keylist = ['Entry', 'ID', 'Timestamp', 'Serviceable', 'Severity','Message']
1076 if(args.devdebug):
1077 colNames = ['Entry', 'ID', 'Timestamp', 'Serviceable', 'Severity','Message', 'eSEL contents']
1078 keylist.append('eSEL')
1079 else:
1080 colNames = ['Entry', 'ID', 'Timestamp', 'Serviceable', 'Severity', 'Message']
1081 for log in logNumList:
1082 selDict = {}
1083 alert = events[eventKeyDict[str(log)]]
1084 if('error' in alert):
1085 selDict['Entry'] = alert['logNum']
1086 selDict['ID'] = 'Unknown'
1087 selDict['Timestamp'] = datetime.datetime.fromtimestamp(int(alert['timestamp']/1000)).strftime("%Y-%m-%d %H:%M:%S")
1088 msg = alert['error']
1089 polMsg = msg.split("policy table:")[0]
1090 msg = msg.split("policy table:")[1]
1091 msgPieces = msg.split("||")
1092 err = msgPieces[0]
1093 if(err.find("org.open_power.")!=-1):
1094 err = err.split("org.open_power.")[1]
1095 elif(err.find("xyz.openbmc_project.")!=-1):
1096 err = err.split("xyz.openbmc_project.")[1]
1097 else:
1098 err = msgPieces[0]
1099 callout = ""
1100 if len(msgPieces) >1:
1101 callout = msgPieces[1]
1102 if(callout.find("/org/open_power/")!=-1):
1103 callout = callout.split("/org/open_power/")[1]
1104 elif(callout.find("/xyz/openbmc_project/")!=-1):
1105 callout = callout.split("/xyz/openbmc_project/")[1]
1106 else:
1107 callout = msgPieces[1]
1108 selDict['Message'] = polMsg +"policy table: "+ err + "||" + callout
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001109 selDict['Serviceable'] = 'Unknown'
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001110 selDict['Severity'] = alert['Severity']
1111 else:
1112 selDict['Entry'] = alert['logNum']
1113 selDict['ID'] = alert['CommonEventID']
1114 selDict['Timestamp'] = datetime.datetime.fromtimestamp(int(alert['timestamp']/1000)).strftime("%Y-%m-%d %H:%M:%S")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001115 selDict['Message'] = alert['Message']
1116 selDict['Serviceable'] = alert['Serviceable']
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001117 selDict['Severity'] = alert['Severity']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001118
1119
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001120 eselOrder = ['refCode','signatureDescription', 'eselType', 'devdesc', 'calloutType', 'procedure']
1121 if ('eselParts' in alert and args.devdebug):
1122 eselOutput = ""
1123 for item in eselOrder:
1124 if item in alert['eselParts']:
1125 eselOutput = eselOutput + item + ": " + alert['eselParts'][item] + " | "
1126 selDict['eSEL'] = eselOutput
1127 else:
1128 if args.devdebug:
1129 selDict['eSEL'] = "None"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001130
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001131 if not alert['resolved']:
1132 activeAlerts.append(selDict)
1133 else:
1134 historyAlerts.append(selDict)
1135 mergedOutput = activeAlerts + historyAlerts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001136 colWidth = setColWidth(keylist, len(colNames), dict(enumerate(mergedOutput)), colNames)
1137
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001138 output = ""
1139 if(len(activeAlerts)>0):
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001140 row = ""
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001141 output +="----Active Alerts----\n"
1142 for i in range(0, len(colNames)):
1143 if i!=0: row =row + "| "
1144 row = row + colNames[i].ljust(colWidth[i])
1145 output += row + "\n"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001146
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001147 for i in range(0,len(activeAlerts)):
1148 row = ""
1149 for j in range(len(activeAlerts[i])):
1150 if (j != 0): row = row + "| "
1151 row = row + activeAlerts[i][keylist[j]].ljust(colWidth[j])
1152 output += row + "\n"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001153
1154 if(len(historyAlerts)>0):
1155 row = ""
1156 output+= "----Historical Alerts----\n"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001157 for i in range(len(colNames)):
1158 if i!=0: row =row + "| "
1159 row = row + colNames[i].ljust(colWidth[i])
1160 output += row + "\n"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001161
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001162 for i in range(0, len(historyAlerts)):
1163 row = ""
1164 for j in range(len(historyAlerts[i])):
1165 if (j != 0): row = row + "| "
1166 row = row + historyAlerts[i][keylist[j]].ljust(colWidth[j])
1167 output += row + "\n"
1168# print(events[eventKeyDict[str(log)]])
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001169 return output
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001170
Justin Thalere412dc22018-01-12 16:28:24 -06001171
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001172def selPrint(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001173 """
1174 prints out all bmc alerts
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.policyTableLoc is None):
1182 if os.path.exists('policyTable.json'):
1183 ptableLoc = "policyTable.json"
1184 elif os.path.exists('/opt/ibm/ras/lib/policyTable.json'):
1185 ptableLoc = '/opt/ibm/ras/lib/policyTable.json'
1186 else:
1187 ptableLoc = 'lib/policyTable.json'
1188 else:
1189 ptableLoc = args.policyTableLoc
1190 policyTable = loadPolicyTable(ptableLoc)
1191 rawselEntries = ""
1192 if(hasattr(args, 'fileloc') and args.fileloc is not None):
1193 if os.path.exists(args.fileloc):
1194 with open(args.fileloc, 'r') as selFile:
1195 selLines = selFile.readlines()
1196 rawselEntries = ''.join(selLines)
1197 else:
1198 print("Error: File not found")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001199 sys.exit(1)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001200 else:
1201 rawselEntries = sel(host, args, session)
1202 loadFailed = False
1203 try:
1204 selEntries = json.loads(rawselEntries)
1205 except ValueError:
1206 loadFailed = True
1207 if loadFailed:
1208 cleanSels = json.dumps(rawselEntries).replace('\\n', '')
1209 #need to load json twice as original content was string escaped a second time
1210 selEntries = json.loads(json.loads(cleanSels))
1211 selEntries = selEntries['data']
Justin Thalere412dc22018-01-12 16:28:24 -06001212
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001213 if 'description' in selEntries:
1214 if(args.json):
1215 return("{\n\t\"numAlerts\": 0\n}")
1216 else:
1217 return("No log entries found")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001218
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001219 else:
1220 if(len(policyTable)>0):
1221 events = parseAlerts(policyTable, selEntries, args)
1222 if(args.json):
1223 events["numAlerts"] = len(events)
1224 retValue = str(json.dumps(events, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False))
1225 return retValue
1226 elif(hasattr(args, 'fullSel')):
1227 return events
1228 else:
1229 #get log numbers to order event entries sequentially
1230 return selDisplay(events, args)
1231 else:
1232 if(args.json):
1233 return selEntries
1234 else:
1235 print("error: Policy Table not found.")
1236 return selEntries
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001237
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001238def selList(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001239 """
1240 prints out all all bmc alerts, or only prints out the specified alerts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001241
Justin Thalere412dc22018-01-12 16:28:24 -06001242 @param host: string, the hostname or IP address of the bmc
1243 @param args: contains additional arguments used by the fru sub command
1244 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001245 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1246 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001247 return(sel(host, args, session))
1248
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001249
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001250def selClear(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001251 """
1252 clears all alerts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001253
Justin Thalere412dc22018-01-12 16:28:24 -06001254 @param host: string, the hostname or IP address of the bmc
1255 @param args: contains additional arguments used by the fru sub command
1256 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001257 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1258 """
Matt Spinler47b13e92019-01-04 14:58:53 -06001259 url="https://"+host+"/xyz/openbmc_project/logging/action/DeleteAll"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001260 data = "{\"data\": [] }"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001261
Justin Thalere412dc22018-01-12 16:28:24 -06001262 try:
Justin Thaler27197622019-01-23 14:42:11 -06001263 res = session.post(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001264 except(requests.exceptions.Timeout):
1265 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001266 if res.status_code == 200:
1267 return "The Alert Log has been cleared. Please allow a few minutes for the action to complete."
1268 else:
1269 print("Unable to clear the logs, trying to clear 1 at a time")
1270 sels = json.loads(sel(host, args, session))['data']
1271 for key in sels:
1272 if 'callout' not in key:
1273 logNum = key.split('/')[-1]
1274 url = "https://"+ host+ "/xyz/openbmc_project/logging/entry/"+logNum+"/action/Delete"
1275 try:
Justin Thaler27197622019-01-23 14:42:11 -06001276 session.post(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001277 except(requests.exceptions.Timeout):
1278 return connectionErrHandler(args.json, "Timeout", None)
1279 sys.exit(1)
1280 except(requests.exceptions.ConnectionError) as err:
1281 return connectionErrHandler(args.json, "ConnectionError", err)
1282 sys.exit(1)
1283 return ('Sel clearing complete')
1284
1285def selSetResolved(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001286 """
1287 sets a sel entry to resolved
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001288
Justin Thalere412dc22018-01-12 16:28:24 -06001289 @param host: string, the hostname or IP address of the bmc
1290 @param args: contains additional arguments used by the fru sub command
1291 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001292 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1293 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001294 url="https://"+host+"/xyz/openbmc_project/logging/entry/" + str(args.selNum) + "/attr/Resolved"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001295 data = "{\"data\": 1 }"
Justin Thalere412dc22018-01-12 16:28:24 -06001296 try:
Justin Thaler27197622019-01-23 14:42:11 -06001297 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001298 except(requests.exceptions.Timeout):
1299 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001300 if res.status_code == 200:
1301 return "Sel entry "+ str(args.selNum) +" is now set to resolved"
1302 else:
1303 return "Unable to set the alert to resolved"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001304
Justin Thalere412dc22018-01-12 16:28:24 -06001305def selResolveAll(host, args, session):
1306 """
1307 sets a sel entry to resolved
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001308
Justin Thalere412dc22018-01-12 16:28:24 -06001309 @param host: string, the hostname or IP address of the bmc
1310 @param args: contains additional arguments used by the fru sub command
1311 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001312 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1313 """
Justin Thalere412dc22018-01-12 16:28:24 -06001314 rawselEntries = sel(host, args, session)
1315 loadFailed = False
1316 try:
1317 selEntries = json.loads(rawselEntries)
1318 except ValueError:
1319 loadFailed = True
1320 if loadFailed:
1321 cleanSels = json.dumps(rawselEntries).replace('\\n', '')
1322 #need to load json twice as original content was string escaped a second time
1323 selEntries = json.loads(json.loads(cleanSels))
1324 selEntries = selEntries['data']
1325
1326 if 'description' in selEntries:
1327 if(args.json):
1328 return("{\n\t\"selsResolved\": 0\n}")
1329 else:
1330 return("No log entries found")
1331 else:
1332 d = vars(args)
1333 successlist = []
1334 failedlist = []
1335 for key in selEntries:
1336 if 'callout' not in key:
1337 d['selNum'] = key.split('/')[-1]
1338 resolved = selSetResolved(host,args,session)
1339 if 'Sel entry' in resolved:
1340 successlist.append(d['selNum'])
1341 else:
1342 failedlist.append(d['selNum'])
1343 output = ""
1344 successlist.sort()
1345 failedlist.sort()
1346 if len(successlist)>0:
1347 output = "Successfully resolved: " +', '.join(successlist) +"\n"
1348 if len(failedlist)>0:
1349 output += "Failed to resolve: " + ', '.join(failedlist) + "\n"
1350 return output
1351
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001352def chassisPower(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001353 """
1354 called by the chassis function. Controls the power state of the chassis, or gets the status
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001355
Justin Thalere412dc22018-01-12 16:28:24 -06001356 @param host: string, the hostname or IP address of the bmc
1357 @param args: contains additional arguments used by the fru sub command
1358 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001359 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1360 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001361 if(args.powcmd == 'on'):
Justin Thaler22b1bb52018-03-15 13:31:32 -05001362 if checkFWactivation(host, args, session):
1363 return ("Chassis Power control disabled during firmware activation")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001364 print("Attempting to Power on...:")
1365 url="https://"+host+"/xyz/openbmc_project/state/host0/attr/RequestedHostTransition"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001366 data = '{"data":"xyz.openbmc_project.State.Host.Transition.On"}'
Justin Thalere412dc22018-01-12 16:28:24 -06001367 try:
Justin Thaler27197622019-01-23 14:42:11 -06001368 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001369 except(requests.exceptions.Timeout):
1370 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001371 return res.text
Justin Thalere412dc22018-01-12 16:28:24 -06001372 elif(args.powcmd == 'softoff'):
Justin Thaler22b1bb52018-03-15 13:31:32 -05001373 if checkFWactivation(host, args, session):
1374 return ("Chassis Power control disabled during firmware activation")
Justin Thalere412dc22018-01-12 16:28:24 -06001375 print("Attempting to Power off gracefully...:")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001376 url="https://"+host+"/xyz/openbmc_project/state/host0/attr/RequestedHostTransition"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001377 data = '{"data":"xyz.openbmc_project.State.Host.Transition.Off"}'
Justin Thalere412dc22018-01-12 16:28:24 -06001378 try:
Justin Thaler27197622019-01-23 14:42:11 -06001379 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001380 except(requests.exceptions.Timeout):
1381 return(connectionErrHandler(args.json, "Timeout", None))
1382 return res.text
1383 elif(args.powcmd == 'hardoff'):
Justin Thaler22b1bb52018-03-15 13:31:32 -05001384 if checkFWactivation(host, args, session):
1385 return ("Chassis Power control disabled during firmware activation")
Justin Thalere412dc22018-01-12 16:28:24 -06001386 print("Attempting to Power off immediately...:")
1387 url="https://"+host+"/xyz/openbmc_project/state/chassis0/attr/RequestedPowerTransition"
Justin Thalere412dc22018-01-12 16:28:24 -06001388 data = '{"data":"xyz.openbmc_project.State.Chassis.Transition.Off"}'
1389 try:
Justin Thaler27197622019-01-23 14:42:11 -06001390 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001391 except(requests.exceptions.Timeout):
1392 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001393 return res.text
1394 elif(args.powcmd == 'status'):
1395 url="https://"+host+"/xyz/openbmc_project/state/chassis0/attr/CurrentPowerState"
Justin Thalere412dc22018-01-12 16:28:24 -06001396 try:
Justin Thaler27197622019-01-23 14:42:11 -06001397 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001398 except(requests.exceptions.Timeout):
1399 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001400 chassisState = json.loads(res.text)['data'].split('.')[-1]
1401 url="https://"+host+"/xyz/openbmc_project/state/host0/attr/CurrentHostState"
Justin Thalere412dc22018-01-12 16:28:24 -06001402 try:
Justin Thaler27197622019-01-23 14:42:11 -06001403 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001404 except(requests.exceptions.Timeout):
1405 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001406 hostState = json.loads(res.text)['data'].split('.')[-1]
1407 url="https://"+host+"/xyz/openbmc_project/state/bmc0/attr/CurrentBMCState"
Justin Thalere412dc22018-01-12 16:28:24 -06001408 try:
Justin Thaler27197622019-01-23 14:42:11 -06001409 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001410 except(requests.exceptions.Timeout):
1411 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001412 bmcState = json.loads(res.text)['data'].split('.')[-1]
1413 if(args.json):
1414 outDict = {"Chassis Power State" : chassisState, "Host Power State" : hostState, "BMC Power State":bmcState}
1415 return json.dumps(outDict, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False)
1416 else:
1417 return "Chassis Power State: " +chassisState + "\nHost Power State: " + hostState + "\nBMC Power State: " + bmcState
1418 else:
1419 return "Invalid chassis power command"
1420
Justin Thalere412dc22018-01-12 16:28:24 -06001421
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001422def chassisIdent(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001423 """
1424 called by the chassis function. Controls the identify led of the chassis. Sets or gets the state
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001425
Justin Thalere412dc22018-01-12 16:28:24 -06001426 @param host: string, the hostname or IP address of the bmc
1427 @param args: contains additional arguments used by the fru sub command
1428 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001429 @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 -06001430 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001431 if(args.identcmd == 'on'):
1432 print("Attempting to turn identify light on...:")
1433 url="https://"+host+"/xyz/openbmc_project/led/groups/enclosure_identify/attr/Asserted"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001434 data = '{"data":true}'
Justin Thalere412dc22018-01-12 16:28:24 -06001435 try:
Justin Thaler27197622019-01-23 14:42:11 -06001436 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001437 except(requests.exceptions.Timeout):
1438 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001439 return res.text
1440 elif(args.identcmd == 'off'):
1441 print("Attempting to turn identify light off...:")
1442 url="https://"+host+"/xyz/openbmc_project/led/groups/enclosure_identify/attr/Asserted"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001443 data = '{"data":false}'
Justin Thalere412dc22018-01-12 16:28:24 -06001444 try:
Justin Thaler27197622019-01-23 14:42:11 -06001445 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001446 except(requests.exceptions.Timeout):
1447 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001448 return res.text
1449 elif(args.identcmd == 'status'):
1450 url="https://"+host+"/xyz/openbmc_project/led/groups/enclosure_identify"
Justin Thalere412dc22018-01-12 16:28:24 -06001451 try:
Justin Thaler27197622019-01-23 14:42:11 -06001452 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001453 except(requests.exceptions.Timeout):
1454 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001455 status = json.loads(res.text)['data']
1456 if(args.json):
1457 return status
1458 else:
1459 if status['Asserted'] == 0:
1460 return "Identify light is off"
1461 else:
1462 return "Identify light is blinking"
1463 else:
1464 return "Invalid chassis identify command"
1465
Justin Thalere412dc22018-01-12 16:28:24 -06001466
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001467def chassis(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001468 """
1469 controls the different chassis commands
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001470
Justin Thalere412dc22018-01-12 16:28:24 -06001471 @param host: string, the hostname or IP address of the bmc
1472 @param args: contains additional arguments used by the fru sub command
1473 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001474 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1475 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001476 if(hasattr(args, 'powcmd')):
1477 result = chassisPower(host,args,session)
1478 elif(hasattr(args, 'identcmd')):
1479 result = chassisIdent(host, args, session)
1480 else:
Justin Thaler22b1bb52018-03-15 13:31:32 -05001481 return "This feature is not yet implemented"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001482 return result
Justin Thalere412dc22018-01-12 16:28:24 -06001483
Asmitha Karunanithi4e178112020-10-01 08:18:21 -05001484def getTask(host, args, session):
1485 """
1486 Get operation on the Task Monitor URI
1487
1488 @param host: string, the hostname or IP address of the bmc
1489 @param args: contains additional arguments used by the task sub command
1490 @param session: the active session to use
1491 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1492 """
1493 if args.taskURI is not None:
1494 url ='https://'+host+str(args.taskURI)
1495 try:
1496 r = session.post(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
1497 if (r.status_code == 200 and not args.json):
1498 return r.text
1499 elif (r.status_code == 200 and args.json):
1500 return r.json()
1501 else:
1502 return ('Failed to retrieve the data on Task Monitor URI')
1503 except(requests.exceptions.Timeout):
1504 return connectionErrHandler(args.json, "Timeout", None)
1505 except(requests.exceptions.ConnectionError) as err:
1506 return connectionErrHandler(args.json, "ConnectionError", err)
1507 else:
1508 return 'You must specify the Task Monitor URI'
1509
1510
Ravi Tejad8be0b42020-03-18 14:31:46 -05001511def dumpRetrieve(host, args, session):
1512 """
1513 Downloads dump of given dump type
1514
1515 @param host: string, the hostname or IP address of the bmc
1516 @param args: contains additional arguments used by the collectServiceData sub command
1517 @param session: the active session to use
1518 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1519 """
1520 dumpType = args.dumpType
1521 if (args.dumpType=="SystemDump"):
1522 dumpResp=systemDumpRetrieve(host,args,session)
1523 elif(args.dumpType=="bmc"):
1524 dumpResp=bmcDumpRetrieve(host,args,session)
1525 return dumpResp
1526
1527def dumpList(host, args, session):
1528 """
1529 Lists dump of the given dump type
1530
1531 @param host: string, the hostname or IP address of the bmc
1532 @param args: contains additional arguments used by the collectServiceData sub command
1533 @param session: the active session to use
1534 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1535 """
1536 if (args.dumpType=="SystemDump"):
1537 dumpResp=systemDumpList(host,args,session)
1538 elif(args.dumpType=="bmc"):
1539 dumpResp=bmcDumpList(host,args,session)
1540 return dumpResp
1541
1542def dumpDelete(host, args, session):
1543 """
1544 Deletes dump of the given dump type
1545
1546 @param host: string, the hostname or IP address of the bmc
1547 @param args: contains additional arguments used by the collectServiceData sub command
1548 @param session: the active session to use
1549 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1550 """
1551 if (args.dumpType=="SystemDump"):
1552 dumpResp=systemDumpDelete(host,args,session)
1553 elif(args.dumpType=="bmc"):
1554 dumpResp=bmcDumpDelete(host,args,session)
1555 return dumpResp
1556
1557def dumpDeleteAll(host, args, session):
1558 """
1559 Deletes all dumps of the given dump type
1560
1561 @param host: string, the hostname or IP address of the bmc
1562 @param args: contains additional arguments used by the collectServiceData sub command
1563 @param session: the active session to use
1564 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1565 """
1566 if (args.dumpType=="SystemDump"):
1567 dumpResp=systemDumpDeleteAll(host,args,session)
1568 elif(args.dumpType=="bmc"):
1569 dumpResp=bmcDumpDeleteAll(host,args,session)
1570 return dumpResp
1571
1572def dumpCreate(host, args, session):
1573 """
1574 Creates dump for the given dump type
1575
1576 @param host: string, the hostname or IP address of the bmc
1577 @param args: contains additional arguments used by the collectServiceData sub command
1578 @param session: the active session to use
1579 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1580 """
1581 if (args.dumpType=="SystemDump"):
1582 dumpResp=systemDumpCreate(host,args,session)
1583 elif(args.dumpType=="bmc"):
Justin Thaler0a3e1692020-04-07 19:10:40 -05001584 dumpResp=bmcDumpCreate(host,args,session)
Ravi Tejad8be0b42020-03-18 14:31:46 -05001585 return dumpResp
1586
1587
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001588def bmcDumpRetrieve(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001589 """
1590 Downloads a dump file from the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001591
Justin Thalere412dc22018-01-12 16:28:24 -06001592 @param host: string, the hostname or IP address of the bmc
1593 @param args: contains additional arguments used by the collectServiceData sub command
1594 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001595 @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 -06001596 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001597 dumpNum = args.dumpNum
1598 if (args.dumpSaveLoc is not None):
1599 saveLoc = args.dumpSaveLoc
1600 else:
Justin Thalercf1deae2018-05-25 19:35:21 -05001601 saveLoc = tempfile.gettempdir()
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001602 url ='https://'+host+'/download/dump/' + str(dumpNum)
1603 try:
Justin Thaler27197622019-01-23 14:42:11 -06001604 r = session.get(url, headers=jsonHeader, stream=True, verify=False, timeout=baseTimeout)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001605 if (args.dumpSaveLoc is not None):
1606 if os.path.exists(saveLoc):
1607 if saveLoc[-1] != os.path.sep:
1608 saveLoc = saveLoc + os.path.sep
1609 filename = saveLoc + host+'-dump' + str(dumpNum) + '.tar.xz'
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001610
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001611 else:
1612 return 'Invalid save location specified'
1613 else:
Justin Thalercf1deae2018-05-25 19:35:21 -05001614 filename = tempfile.gettempdir()+os.sep + host+'-dump' + str(dumpNum) + '.tar.xz'
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001615
1616 with open(filename, 'wb') as f:
1617 for chunk in r.iter_content(chunk_size =1024):
1618 if chunk:
1619 f.write(chunk)
1620 return 'Saved as ' + filename
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001621
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001622 except(requests.exceptions.Timeout):
1623 return connectionErrHandler(args.json, "Timeout", None)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001624
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001625 except(requests.exceptions.ConnectionError) as err:
1626 return connectionErrHandler(args.json, "ConnectionError", err)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001627
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001628def bmcDumpList(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001629 """
1630 Lists the number of dump files on the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001631
Justin Thalere412dc22018-01-12 16:28:24 -06001632 @param host: string, the hostname or IP address of the bmc
1633 @param args: contains additional arguments used by the collectServiceData sub command
1634 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001635 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1636 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001637 url ='https://'+host+'/xyz/openbmc_project/dump/list'
1638 try:
Justin Thaler27197622019-01-23 14:42:11 -06001639 r = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thaler3a5771b2019-01-23 14:31:52 -06001640 dumpList = r.json()
Justin Thaler3b3c6582020-04-07 19:17:36 -05001641 formattedList = []
1642 #remove items that aren't dump entries 'entry, internal, manager endpoints'
1643 if 'data' in dumpList:
1644 for entry in dumpList['data']:
1645 if 'entry' in entry:
1646 if entry.split('/')[-1].isnumeric():
1647 formattedList.append(entry)
1648 dumpList['data']= formattedList
Justin Thaler3a5771b2019-01-23 14:31:52 -06001649 return dumpList
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001650 except(requests.exceptions.Timeout):
1651 return connectionErrHandler(args.json, "Timeout", None)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001652
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001653 except(requests.exceptions.ConnectionError) as err:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001654 return connectionErrHandler(args.json, "ConnectionError", err)
1655
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001656def bmcDumpDelete(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001657 """
1658 Deletes BMC dump files from the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001659
Justin Thalere412dc22018-01-12 16:28:24 -06001660 @param host: string, the hostname or IP address of the bmc
1661 @param args: contains additional arguments used by the collectServiceData sub command
1662 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001663 @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 -06001664 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001665 dumpList = []
1666 successList = []
1667 failedList = []
1668 if args.dumpNum is not None:
1669 if isinstance(args.dumpNum, list):
1670 dumpList = args.dumpNum
1671 else:
1672 dumpList.append(args.dumpNum)
1673 for dumpNum in dumpList:
1674 url ='https://'+host+'/xyz/openbmc_project/dump/entry/'+str(dumpNum)+'/action/Delete'
1675 try:
Justin Thaler27197622019-01-23 14:42:11 -06001676 r = session.post(url, headers=jsonHeader, json = {"data": []}, verify=False, timeout=baseTimeout)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001677 if r.status_code == 200:
1678 successList.append(str(dumpNum))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001679 else:
1680 failedList.append(str(dumpNum))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001681 except(requests.exceptions.Timeout):
1682 return connectionErrHandler(args.json, "Timeout", None)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001683 except(requests.exceptions.ConnectionError) as err:
1684 return connectionErrHandler(args.json, "ConnectionError", err)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001685 output = "Successfully deleted dumps: " + ', '.join(successList)
1686 if(len(failedList)>0):
1687 output+= '\nFailed to delete dumps: ' + ', '.join(failedList)
1688 return output
1689 else:
1690 return 'You must specify an entry number to delete'
1691
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001692def bmcDumpDeleteAll(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001693 """
1694 Deletes All BMC dump files from the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001695
Justin Thalere412dc22018-01-12 16:28:24 -06001696 @param host: string, the hostname or IP address of the bmc
1697 @param args: contains additional arguments used by the collectServiceData sub command
1698 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001699 @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 -06001700 """
1701 dumpResp = bmcDumpList(host, args, session)
1702 if 'FQPSPIN0000M' in dumpResp or 'FQPSPIN0001M'in dumpResp:
1703 return dumpResp
Justin Thaler3a5771b2019-01-23 14:31:52 -06001704 dumpList = dumpResp['data']
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001705 d = vars(args)
1706 dumpNums = []
1707 for dump in dumpList:
Alvin Wang28bd09d2019-10-28 13:23:58 +08001708 dumpNum = dump.strip().split('/')[-1]
1709 if dumpNum.isdigit():
1710 dumpNums.append(int(dumpNum))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001711 d['dumpNum'] = dumpNums
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001712
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001713 return bmcDumpDelete(host, args, session)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001714
Justin Thalere412dc22018-01-12 16:28:24 -06001715
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001716def bmcDumpCreate(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001717 """
1718 Creates a bmc dump file
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001719
Justin Thalere412dc22018-01-12 16:28:24 -06001720 @param host: string, the hostname or IP address of the bmc
1721 @param args: contains additional arguments used by the collectServiceData sub command
1722 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001723 @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 -06001724 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001725 url = 'https://'+host+'/xyz/openbmc_project/dump/action/CreateDump'
1726 try:
Justin Thaler27197622019-01-23 14:42:11 -06001727 r = session.post(url, headers=jsonHeader, json = {"data": []}, verify=False, timeout=baseTimeout)
Justin Thaler2f59aea2020-04-07 19:27:01 -05001728 info = r.json()
Matt Spinlereae05b02019-01-24 12:59:34 -06001729 if(r.status_code == 200 and not args.json):
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001730 return ('Dump successfully created')
Justin Thaler3a5771b2019-01-23 14:31:52 -06001731 elif(args.json):
Justin Thaler2f59aea2020-04-07 19:27:01 -05001732 return info
1733 elif 'data' in info:
1734 if 'QuotaExceeded' in info['data']['description']:
1735 return 'BMC dump space is full. Please delete at least one existing dump entry and try again.'
1736 else:
1737 return "Failed to create a BMC dump. BMC Response:\n {resp}".format(resp=info)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001738 else:
Justin Thaler2f59aea2020-04-07 19:27:01 -05001739 return "Failed to create a BMC dump. BMC Response:\n {resp}".format(resp=info)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001740 except(requests.exceptions.Timeout):
1741 return connectionErrHandler(args.json, "Timeout", None)
1742 except(requests.exceptions.ConnectionError) as err:
1743 return connectionErrHandler(args.json, "ConnectionError", err)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001744
Justin Thaler2f59aea2020-04-07 19:27:01 -05001745
Ravi Tejad8be0b42020-03-18 14:31:46 -05001746def systemDumpRetrieve(host, args, session):
1747 """
1748 Downloads system dump
1749
1750 @param host: string, the hostname or IP address of the bmc
1751 @param args: contains additional arguments used by the collectServiceData sub command
1752 @param session: the active session to use
1753 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1754 """
1755 NBDSetup(host,args,session)
1756 pipe = NBDPipe()
1757 pipe.openHTTPSocket(args)
1758 pipe.openTCPSocket()
1759 pipe.waitformessage()
1760
1761def systemDumpList(host, args, session):
1762 """
1763 Lists system dumps
1764
1765 @param host: string, the hostname or IP address of the bmc
1766 @param args: contains additional arguments used by the collectServiceData sub command
1767 @param session: the active session to use
1768 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1769 """
Ravi Tejabef8da42020-07-14 23:01:51 -05001770 url = "https://"+host+"/redfish/v1/Systems/system/LogServices/Dump/Entries"
Ravi Tejad8be0b42020-03-18 14:31:46 -05001771 try:
1772 r = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
1773 dumpList = r.json()
1774 return dumpList
1775 except(requests.exceptions.Timeout):
1776 return connectionErrHandler(args.json, "Timeout", None)
1777
1778 except(requests.exceptions.ConnectionError) as err:
1779 return connectionErrHandler(args.json, "ConnectionError", err)
1780
1781
1782def systemDumpDelete(host, args, session):
1783 """
1784 Deletes system dump
1785
1786 @param host: string, the hostname or IP address of the bmc
1787 @param args: contains additional arguments used by the collectServiceData sub command
1788 @param session: the active session to use
1789 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1790 """
1791 dumpList = []
1792 successList = []
1793 failedList = []
1794 if args.dumpNum is not None:
1795 if isinstance(args.dumpNum, list):
1796 dumpList = args.dumpNum
1797 else:
1798 dumpList.append(args.dumpNum)
1799 for dumpNum in dumpList:
Ravi Tejabef8da42020-07-14 23:01:51 -05001800 url = 'https://'+host+'/redfish/v1/Systems/system/LogServices/Dump/Entries/'+ str(dumpNum)
Ravi Tejad8be0b42020-03-18 14:31:46 -05001801 try:
1802 r = session.delete(url, headers=jsonHeader, json = {"data": []}, verify=False, timeout=baseTimeout)
1803 if r.status_code == 200:
1804 successList.append(str(dumpNum))
1805 else:
1806 failedList.append(str(dumpNum))
1807 except(requests.exceptions.Timeout):
1808 return connectionErrHandler(args.json, "Timeout", None)
1809 except(requests.exceptions.ConnectionError) as err:
1810 return connectionErrHandler(args.json, "ConnectionError", err)
1811 output = "Successfully deleted dumps: " + ', '.join(successList)
1812 if(len(failedList)>0):
1813 output+= '\nFailed to delete dumps: ' + ', '.join(failedList)
1814 return output
1815 else:
1816 return 'You must specify an entry number to delete'
1817
1818def systemDumpDeleteAll(host, args, session):
1819 """
1820 Deletes All system dumps
1821
1822 @param host: string, the hostname or IP address of the bmc
1823 @param args: contains additional arguments used by the collectServiceData sub command
1824 @param session: the active session to use
1825 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1826 """
Ravi Tejabef8da42020-07-14 23:01:51 -05001827 url = 'https://'+host+'/redfish/v1/Systems/system/LogServices/Dump/Actions/LogService.ClearLog'
Ravi Tejad8be0b42020-03-18 14:31:46 -05001828 try:
1829 r = session.post(url, headers=jsonHeader, json = {"data": []}, verify=False, timeout=baseTimeout)
1830 if(r.status_code == 200 and not args.json):
1831 return ('Dumps successfully cleared')
1832 elif(args.json):
1833 return r.json()
1834 else:
1835 return ('Failed to clear dumps')
1836 except(requests.exceptions.Timeout):
1837 return connectionErrHandler(args.json, "Timeout", None)
1838 except(requests.exceptions.ConnectionError) as err:
1839 return connectionErrHandler(args.json, "ConnectionError", err)
1840
1841def systemDumpCreate(host, args, session):
1842 """
1843 Creates a system dump
1844
1845 @param host: string, the hostname or IP address of the bmc
1846 @param args: contains additional arguments used by the collectServiceData sub command
1847 @param session: the active session to use
1848 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1849 """
Asmitha Karunanithi4e178112020-10-01 08:18:21 -05001850 url = 'https://'+host+'/redfish/v1/Systems/system/LogServices/Dump/Actions/LogService.CollectDiagnosticData'
1851 params = {'DiagnosticDataType':'OEM', 'OEMDiagnosticDataType':'System'}
Ravi Tejad8be0b42020-03-18 14:31:46 -05001852 try:
Asmitha Karunanithi4e178112020-10-01 08:18:21 -05001853 r = session.post(url, headers=jsonHeader, params=params, data = json.dumps(params), verify=False, timeout=baseTimeout)
Ravi Tejabef8da42020-07-14 23:01:51 -05001854 if(r.status_code == 200):
Ravi Tejad8be0b42020-03-18 14:31:46 -05001855 return r.json()
1856 else:
1857 return ('Failed to create dump')
1858 except(requests.exceptions.Timeout):
1859 return connectionErrHandler(args.json, "Timeout", None)
1860 except(requests.exceptions.ConnectionError) as err:
1861 return connectionErrHandler(args.json, "ConnectionError", err)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001862
Justin Thaler666cf342019-01-23 14:44:27 -06001863def csdDumpInitiate(host, args, session):
1864 """
1865 Starts the process of getting the current list of dumps then initiates the creation of one.
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001866
Justin Thaler666cf342019-01-23 14:44:27 -06001867 @param host: string, the hostname or IP address of the bmc
1868 @param args: contains additional arguments used by the collectServiceData sub command
1869 @param session: the active session to use
1870 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1871 """
1872 errorInfo = ""
1873 dumpcount = 0
1874 try:
1875 d = vars(args)
1876 d['json'] = True
1877 except Exception as e:
1878 errorInfo += "Failed to set the json flag to True \n Exception: {eInfo}\n".format(eInfo=e)
Justin Thalerb4256672020-04-07 19:38:26 -05001879 exc_type, exc_obj, exc_tb = sys.exc_info()
1880 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
1881 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
1882 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06001883
1884 try:
1885 for i in range(3):
1886 dumpInfo = bmcDumpList(host, args, session)
1887 if 'data' in dumpInfo:
1888 dumpcount = len(dumpInfo['data'])
1889 break
1890 else:
1891 errorInfo+= "Dump List Message returned: " + json.dumps(dumpInfo,indent=0, separators=(',', ':')).replace('\n','') +"\n"
1892 except Exception as e:
1893 errorInfo+= "Failed to collect the list of dumps.\nException: {eInfo}\n".format(eInfo=e)
Justin Thalerb4256672020-04-07 19:38:26 -05001894 exc_type, exc_obj, exc_tb = sys.exc_info()
1895 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
1896 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
1897 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06001898
1899 #Create a user initiated dump
Justin Thalerb4256672020-04-07 19:38:26 -05001900 dumpFailure = True
Justin Thaler666cf342019-01-23 14:44:27 -06001901 try:
1902 for i in range(3):
1903 dumpcreated = bmcDumpCreate(host, args, session)
1904 if 'message' in dumpcreated:
1905 if 'ok' in dumpcreated['message'].lower():
Justin Thalerb4256672020-04-07 19:38:26 -05001906 dumpFailure = False
Justin Thaler666cf342019-01-23 14:44:27 -06001907 break
Justin Thalerb4256672020-04-07 19:38:26 -05001908 elif 'data' in dumpcreated:
1909 if 'QuotaExceeded' in dumpcreated['data']['description']:
1910 print('Not enough dump space on the BMC to create a new dump. Please delete the oldest entry (lowest number) and rerun the collect_service_data command.')
1911 errorInfo+='Dump Space is full. No new dump was created with this collection'
1912 break
1913 else:
1914 errorInfo+= "Dump create message returned: " + json.dumps(dumpcreated,indent=0, separators=(',', ':')).replace('\n','') +"\n"
Justin Thaler666cf342019-01-23 14:44:27 -06001915 else:
Justin Thalerb4256672020-04-07 19:38:26 -05001916 errorInfo+= "Dump create message returned: " + json.dumps(dumpcreated,indent=0, separators=(',', ':')).replace('\n','') +"\n"
Justin Thaler666cf342019-01-23 14:44:27 -06001917 else:
Justin Thalerb4256672020-04-07 19:38:26 -05001918 errorInfo+= "Dump create message returned: " + json.dumps(dumpcreated,indent=0, separators=(',', ':')).replace('\n','') +"\n"
Justin Thaler666cf342019-01-23 14:44:27 -06001919 except Exception as e:
1920 errorInfo+= "Dump create exception encountered: {eInfo}\n".format(eInfo=e)
Justin Thalerb4256672020-04-07 19:38:26 -05001921 exc_type, exc_obj, exc_tb = sys.exc_info()
1922 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
1923 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
1924 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06001925
1926 output = {}
1927 output['errors'] = errorInfo
1928 output['dumpcount'] = dumpcount
Justin Thalerb4256672020-04-07 19:38:26 -05001929 if dumpFailure: output['dumpFailure'] = True
Justin Thaler666cf342019-01-23 14:44:27 -06001930 return output
1931
1932def csdInventory(host, args,session, fileDir):
1933 """
1934 Collects the BMC inventory, retrying if necessary
1935
1936 @param host: string, the hostname or IP address of the bmc
1937 @param args: contains additional arguments used by the collectServiceData sub command
1938 @param session: the active session to use
1939 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1940 @param fileDir: string representation of the path to use for putting files created
1941 """
1942 errorInfo = "===========Inventory =============\n"
1943 output={}
1944 inventoryCollected = False
1945 try:
1946 for i in range(3):
1947 frulist = fruPrint(host, args, session)
1948 if 'Hardware' in frulist:
1949 inventoryCollected = True
1950 break
1951 else:
1952 errorInfo += json.dumps(frulist, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n'
1953 except Exception as e:
1954 errorInfo += "Inventory collection exception: {eInfo}\n".format(eInfo=e)
Justin Thalerb4256672020-04-07 19:38:26 -05001955 exc_type, exc_obj, exc_tb = sys.exc_info()
1956 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
1957 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
1958 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06001959 if inventoryCollected:
1960 try:
1961 with open(fileDir +os.sep+'inventory.txt', 'w') as f:
1962 f.write(json.dumps(frulist, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n')
1963 print("Inventory collected and stored in " + fileDir + os.sep + "inventory.txt")
1964 output['fileLoc'] = fileDir+os.sep+'inventory.txt'
1965 except Exception as e:
1966 print("Failed to write inventory to file.")
1967 errorInfo += "Error writing inventory to the file. Exception: {eInfo}\n".format(eInfo=e)
Justin Thalerb4256672020-04-07 19:38:26 -05001968 exc_type, exc_obj, exc_tb = sys.exc_info()
1969 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
1970 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
1971 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06001972
1973 output['errors'] = errorInfo
1974
1975 return output
1976
1977def csdSensors(host, args,session, fileDir):
1978 """
1979 Collects the BMC sensor readings, retrying if necessary
1980
1981 @param host: string, the hostname or IP address of the bmc
1982 @param args: contains additional arguments used by the collectServiceData sub command
1983 @param session: the active session to use
1984 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1985 @param fileDir: string representation of the path to use for putting files created
1986 """
1987 errorInfo = "===========Sensors =============\n"
1988 sensorsCollected = False
1989 output={}
1990 try:
1991 d = vars(args)
1992 d['json'] = False
1993 except Exception as e:
1994 errorInfo += "Failed to set the json flag to False \n Exception: {eInfo}\n".format(eInfo=e)
Justin Thalerb4256672020-04-07 19:38:26 -05001995 exc_type, exc_obj, exc_tb = sys.exc_info()
1996 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
1997 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
1998 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06001999
2000 try:
2001 for i in range(3):
2002 sensorReadings = sensor(host, args, session)
2003 if 'OCC0' in sensorReadings:
2004 sensorsCollected = True
2005 break
2006 else:
2007 errorInfo += sensorReadings
2008 except Exception as e:
2009 errorInfo += "Sensor reading collection exception: {eInfo}\n".format(eInfo=e)
Justin Thalerb4256672020-04-07 19:38:26 -05002010 exc_type, exc_obj, exc_tb = sys.exc_info()
2011 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
2012 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
2013 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06002014 if sensorsCollected:
2015 try:
2016 with open(fileDir +os.sep+'sensorReadings.txt', 'w') as f:
2017 f.write(sensorReadings)
2018 print("Sensor readings collected and stored in " + fileDir + os.sep+ "sensorReadings.txt")
2019 output['fileLoc'] = fileDir+os.sep+'sensorReadings.txt'
2020 except Exception as e:
2021 print("Failed to write sensor readings to file system.")
2022 errorInfo += "Error writing sensor readings to the file. Exception: {eInfo}\n".format(eInfo=e)
Justin Thalerb4256672020-04-07 19:38:26 -05002023 exc_type, exc_obj, exc_tb = sys.exc_info()
2024 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
2025 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
2026 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06002027
2028 output['errors'] = errorInfo
2029 return output
2030
2031def csdLEDs(host,args, session, fileDir):
2032 """
2033 Collects the BMC LED status, retrying if necessary
2034
2035 @param host: string, the hostname or IP address of the bmc
2036 @param args: contains additional arguments used by the collectServiceData sub command
2037 @param session: the active session to use
2038 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
2039 @param fileDir: string representation of the path to use for putting files created
2040 """
2041 errorInfo = "===========LEDs =============\n"
2042 ledsCollected = False
2043 output={}
2044 try:
2045 d = vars(args)
2046 d['json'] = True
2047 except Exception as e:
2048 errorInfo += "Failed to set the json flag to False \n Exception: {eInfo}\n".format(eInfo=e)
Justin Thalerb4256672020-04-07 19:38:26 -05002049 exc_type, exc_obj, exc_tb = sys.exc_info()
2050 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
2051 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
2052 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06002053 try:
2054 url="https://"+host+"/xyz/openbmc_project/led/enumerate"
2055 httpHeader = {'Content-Type':'application/json'}
2056 for i in range(3):
2057 try:
2058 ledRes = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
2059 if ledRes.status_code == 200:
2060 ledsCollected = True
2061 leds = ledRes.json()['data']
2062 break
2063 else:
2064 errorInfo += ledRes.text
2065 except(requests.exceptions.Timeout):
2066 errorInfo+=json.dumps( connectionErrHandler(args.json, "Timeout", None), sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n'
2067 except(requests.exceptions.ConnectionError) as err:
2068 errorInfo += json.dumps(connectionErrHandler(args.json, "ConnectionError", err), sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n'
Justin Thalerb4256672020-04-07 19:38:26 -05002069 exc_type, exc_obj, exc_tb = sys.exc_info()
2070 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
2071 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
2072 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06002073 except Exception as e:
2074 errorInfo += "LED status collection exception: {eInfo}\n".format(eInfo=e)
Justin Thalerb4256672020-04-07 19:38:26 -05002075 exc_type, exc_obj, exc_tb = sys.exc_info()
2076 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
2077 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
2078 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06002079
2080 if ledsCollected:
2081 try:
2082 with open(fileDir +os.sep+'ledStatus.txt', 'w') as f:
2083 f.write(json.dumps(leds, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n')
2084 print("LED status collected and stored in " + fileDir + os.sep+ "ledStatus.txt")
2085 output['fileLoc'] = fileDir+os.sep+'ledStatus.txt'
2086 except Exception as e:
2087 print("Failed to write LED status to file system.")
2088 errorInfo += "Error writing LED status to the file. Exception: {eInfo}\n".format(eInfo=e)
Justin Thalerb4256672020-04-07 19:38:26 -05002089 exc_type, exc_obj, exc_tb = sys.exc_info()
2090 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
2091 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
2092 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06002093
2094 output['errors'] = errorInfo
2095 return output
2096
2097def csdSelShortList(host, args, session, fileDir):
2098 """
2099 Collects the BMC log entries, retrying if necessary
2100
2101 @param host: string, the hostname or IP address of the bmc
2102 @param args: contains additional arguments used by the collectServiceData sub command
2103 @param session: the active session to use
2104 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
2105 @param fileDir: string representation of the path to use for putting files created
2106 """
2107 errorInfo = "===========SEL Short List =============\n"
2108 selsCollected = False
2109 output={}
2110 try:
2111 d = vars(args)
2112 d['json'] = False
2113 except Exception as e:
2114 errorInfo += "Failed to set the json flag to False \n Exception: {eInfo}\n".format(eInfo=e)
Justin Thalerb4256672020-04-07 19:38:26 -05002115 exc_type, exc_obj, exc_tb = sys.exc_info()
2116 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
2117 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
2118 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06002119
2120 try:
2121 for i in range(3):
2122 sels = selPrint(host,args,session)
2123 if '----Active Alerts----' in sels or 'No log entries found' in sels or '----Historical Alerts----' in sels:
2124 selsCollected = True
2125 break
2126 else:
2127 errorInfo += sels + '\n'
2128 except Exception as e:
2129 errorInfo += "SEL short list collection exception: {eInfo}\n".format(eInfo=e)
Justin Thalerb4256672020-04-07 19:38:26 -05002130 exc_type, exc_obj, exc_tb = sys.exc_info()
2131 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
2132 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
2133 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06002134
2135 if selsCollected:
2136 try:
2137 with open(fileDir +os.sep+'SELshortlist.txt', 'w') as f:
2138 f.write(sels)
2139 print("SEL short list collected and stored in " + fileDir + os.sep+ "SELshortlist.txt")
2140 output['fileLoc'] = fileDir+os.sep+'SELshortlist.txt'
2141 except Exception as e:
2142 print("Failed to write SEL short list to file system.")
2143 errorInfo += "Error writing SEL short list to the file. Exception: {eInfo}\n".format(eInfo=e)
Justin Thalerb4256672020-04-07 19:38:26 -05002144 exc_type, exc_obj, exc_tb = sys.exc_info()
2145 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
2146 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
2147 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06002148
2149 output['errors'] = errorInfo
2150 return output
2151
2152def csdParsedSels(host, args, session, fileDir):
2153 """
2154 Collects the BMC log entries, retrying if necessary
2155
2156 @param host: string, the hostname or IP address of the bmc
2157 @param args: contains additional arguments used by the collectServiceData sub command
2158 @param session: the active session to use
2159 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
2160 @param fileDir: string representation of the path to use for putting files created
2161 """
2162 errorInfo = "===========SEL Parsed List =============\n"
2163 selsCollected = False
2164 output={}
2165 try:
2166 d = vars(args)
2167 d['json'] = True
2168 d['fullEsel'] = True
2169 except Exception as e:
2170 errorInfo += "Failed to set the json flag to True \n Exception: {eInfo}\n".format(eInfo=e)
Justin Thalerb4256672020-04-07 19:38:26 -05002171 exc_type, exc_obj, exc_tb = sys.exc_info()
2172 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
2173 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
2174 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06002175
2176 try:
2177 for i in range(3):
2178 parsedfullsels = json.loads(selPrint(host,args,session))
2179 if 'numAlerts' in parsedfullsels:
2180 selsCollected = True
2181 break
2182 else:
2183 errorInfo += parsedfullsels + '\n'
2184 except Exception as e:
2185 errorInfo += "Parsed full SELs collection exception: {eInfo}\n".format(eInfo=e)
Justin Thalerb4256672020-04-07 19:38:26 -05002186 exc_type, exc_obj, exc_tb = sys.exc_info()
2187 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
2188 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
2189 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06002190
2191 if selsCollected:
2192 try:
2193 sortedSELs = sortSELs(parsedfullsels)
2194 with open(fileDir +os.sep+'parsedSELs.txt', 'w') as f:
2195 for log in sortedSELs[0]:
2196 esel = ""
2197 parsedfullsels[sortedSELs[1][str(log)]]['timestamp'] = datetime.datetime.fromtimestamp(int(parsedfullsels[sortedSELs[1][str(log)]]['timestamp']/1000)).strftime("%Y-%m-%d %H:%M:%S")
2198 if ('raweSEL' in parsedfullsels[sortedSELs[1][str(log)]] and args.devdebug):
2199 esel = parsedfullsels[sortedSELs[1][str(log)]]['raweSEL']
2200 del parsedfullsels[sortedSELs[1][str(log)]]['raweSEL']
2201 f.write(json.dumps(parsedfullsels[sortedSELs[1][str(log)]],sort_keys=True, indent=4, separators=(',', ': ')))
2202 if(args.devdebug and esel != ""):
2203 f.write(parseESEL(args, esel))
2204 print("Parsed SELs collected and stored in " + fileDir + os.sep+ "parsedSELs.txt")
2205 output['fileLoc'] = fileDir+os.sep+'parsedSELs.txt'
2206 except Exception as e:
2207 print("Failed to write fully parsed SELs to file system.")
2208 errorInfo += "Error writing fully parsed SELs to the file. Exception: {eInfo}\n".format(eInfo=e)
Justin Thalerb4256672020-04-07 19:38:26 -05002209 exc_type, exc_obj, exc_tb = sys.exc_info()
2210 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
2211 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
2212 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06002213
2214 output['errors'] = errorInfo
2215 return output
2216
2217def csdFullEnumeration(host, args, session, fileDir):
2218 """
2219 Collects a full enumeration of /xyz/openbmc_project/, retrying if necessary
2220
2221 @param host: string, the hostname or IP address of the bmc
2222 @param args: contains additional arguments used by the collectServiceData sub command
2223 @param session: the active session to use
2224 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
2225 @param fileDir: string representation of the path to use for putting files created
2226 """
2227 errorInfo = "===========BMC Full Enumeration =============\n"
2228 bmcFullCollected = False
2229 output={}
2230 try:
2231 d = vars(args)
2232 d['json'] = True
2233 except Exception as e:
2234 errorInfo += "Failed to set the json flag to False \n Exception: {eInfo}\n".format(eInfo=e)
Justin Thalerb4256672020-04-07 19:38:26 -05002235 exc_type, exc_obj, exc_tb = sys.exc_info()
2236 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
2237 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
2238 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06002239 try:
2240 print("Attempting to get a full BMC enumeration")
2241 url="https://"+host+"/xyz/openbmc_project/enumerate"
2242 httpHeader = {'Content-Type':'application/json'}
2243 for i in range(3):
2244 try:
2245 bmcRes = session.get(url, headers=jsonHeader, verify=False, timeout=180)
2246 if bmcRes.status_code == 200:
2247 bmcFullCollected = True
2248 fullEnumeration = bmcRes.json()
2249 break
2250 else:
2251 errorInfo += bmcRes.text
2252 except(requests.exceptions.Timeout):
2253 errorInfo+=json.dumps( connectionErrHandler(args.json, "Timeout", None), sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n'
2254 except(requests.exceptions.ConnectionError) as err:
2255 errorInfo += json.dumps(connectionErrHandler(args.json, "ConnectionError", err), sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n'
Justin Thalerb4256672020-04-07 19:38:26 -05002256 exc_type, exc_obj, exc_tb = sys.exc_info()
2257 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
2258 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
2259 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06002260 except Exception as e:
2261 errorInfo += "RAW BMC data collection exception: {eInfo}\n".format(eInfo=e)
Justin Thalerb4256672020-04-07 19:38:26 -05002262 exc_type, exc_obj, exc_tb = sys.exc_info()
2263 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
2264 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
2265 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06002266
2267 if bmcFullCollected:
2268 try:
2269 with open(fileDir +os.sep+'bmcFullRaw.txt', 'w') as f:
2270 f.write(json.dumps(fullEnumeration, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n')
2271 print("RAW BMC data collected and saved into " + fileDir + os.sep+ "bmcFullRaw.txt")
2272 output['fileLoc'] = fileDir+os.sep+'bmcFullRaw.txt'
2273 except Exception as e:
2274 print("Failed to write RAW BMC data to file system.")
2275 errorInfo += "Error writing RAW BMC data collection to the file. Exception: {eInfo}\n".format(eInfo=e)
Justin Thalerb4256672020-04-07 19:38:26 -05002276 exc_type, exc_obj, exc_tb = sys.exc_info()
2277 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
2278 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
2279 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06002280
2281 output['errors'] = errorInfo
2282 return output
2283
2284def csdCollectAllDumps(host, args, session, fileDir):
2285 """
2286 Collects all of the bmc dump files and stores them in fileDir
2287
2288 @param host: string, the hostname or IP address of the bmc
2289 @param args: contains additional arguments used by the collectServiceData sub command
2290 @param session: the active session to use
2291 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
2292 @param fileDir: string representation of the path to use for putting files created
2293 """
2294
2295 errorInfo = "===========BMC Dump Collection =============\n"
2296 dumpListCollected = False
2297 output={}
2298 dumpList = {}
2299 try:
2300 d = vars(args)
2301 d['json'] = True
2302 d['dumpSaveLoc'] = fileDir
2303 except Exception as e:
2304 errorInfo += "Failed to set the json flag to True, or failed to set the dumpSave Location \n Exception: {eInfo}\n".format(eInfo=e)
Justin Thalerb4256672020-04-07 19:38:26 -05002305 exc_type, exc_obj, exc_tb = sys.exc_info()
2306 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
2307 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
2308 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06002309
2310 print('Collecting bmc dump files')
2311
2312 try:
2313 for i in range(3):
2314 dumpResp = bmcDumpList(host, args, session)
2315 if 'message' in dumpResp:
2316 if 'ok' in dumpResp['message'].lower():
2317 dumpList = dumpResp['data']
2318 dumpListCollected = True
2319 break
2320 else:
2321 errorInfo += "Status was not OK when retrieving the list of dumps available. \n Response: \n{resp}\n".format(resp=dumpResp)
2322 else:
2323 errorInfo += "Invalid response received from the BMC while retrieving the list of dumps available.\n {resp}\n".format(resp=dumpResp)
2324 except Exception as e:
2325 errorInfo += "BMC dump list exception: {eInfo}\n".format(eInfo=e)
Justin Thalerb4256672020-04-07 19:38:26 -05002326 exc_type, exc_obj, exc_tb = sys.exc_info()
2327 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
2328 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
2329 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06002330
2331 if dumpListCollected:
2332 output['fileList'] = []
2333 for dump in dumpList:
2334 try:
2335 if '/xyz/openbmc_project/dump/internal/manager' not in dump:
2336 d['dumpNum'] = int(dump.strip().split('/')[-1])
2337 print('retrieving dump file ' + str(d['dumpNum']))
2338 filename = bmcDumpRetrieve(host, args, session).split('Saved as ')[-1]
2339 output['fileList'].append(filename)
2340 except Exception as e:
2341 print("Unable to collect dump: {dumpInfo}".format(dumpInfo=dump))
2342 errorInfo += "Exception collecting a bmc dump {dumpInfo}\n {eInfo}\n".format(dumpInfo=dump, eInfo=e)
Justin Thalerb4256672020-04-07 19:38:26 -05002343 exc_type, exc_obj, exc_tb = sys.exc_info()
2344 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
2345 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
2346 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06002347 output['errors'] = errorInfo
2348 return output
Justin Thalere412dc22018-01-12 16:28:24 -06002349
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002350def collectServiceData(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06002351 """
2352 Collects all data needed for service from the BMC
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002353
Justin Thalere412dc22018-01-12 16:28:24 -06002354 @param host: string, the hostname or IP address of the bmc
2355 @param args: contains additional arguments used by the collectServiceData sub command
2356 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002357 @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 -06002358 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002359
Justin Thaler22b1bb52018-03-15 13:31:32 -05002360 global toolVersion
Justin Thaler666cf342019-01-23 14:44:27 -06002361 filelist = []
2362 errorInfo = ""
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002363
Justin Thaler666cf342019-01-23 14:44:27 -06002364 #get current number of bmc dumps and create a new bmc dump
2365 dumpInitdata = csdDumpInitiate(host, args, session)
Justin Thalerb4256672020-04-07 19:38:26 -05002366 if 'dumpFailure' in dumpInitdata:
2367 return 'Collect service data is stopping due to not being able to create a new dump. No service data was collected.'
Justin Thaler666cf342019-01-23 14:44:27 -06002368 dumpcount = dumpInitdata['dumpcount']
2369 errorInfo += dumpInitdata['errors']
2370 #create the directory to put files
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002371 try:
2372 args.silent = True
Justin Thalercf1deae2018-05-25 19:35:21 -05002373 myDir = tempfile.gettempdir()+os.sep + host + "--" + datetime.datetime.now().strftime("%Y-%m-%d_%H.%M.%S")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002374 os.makedirs(myDir)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002375
Justin Thaler666cf342019-01-23 14:44:27 -06002376 except Exception as e:
2377 print('Unable to create the temporary directory for data collection. Ensure sufficient privileges to create temporary directory. Aborting.')
Justin Thalerb4256672020-04-07 19:38:26 -05002378 exc_type, exc_obj, exc_tb = sys.exc_info()
2379 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
2380 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
2381 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06002382 return("Python exception: {eInfo}".format(eInfo = e))
2383
2384 #Collect Inventory
2385 inventoryData = csdInventory(host, args, session, myDir)
2386 if 'fileLoc' in inventoryData:
2387 filelist.append(inventoryData['fileLoc'])
2388 errorInfo += inventoryData['errors']
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002389 #Read all the sensor and OCC status
Justin Thaler666cf342019-01-23 14:44:27 -06002390 sensorData = csdSensors(host,args,session,myDir)
2391 if 'fileLoc' in sensorData:
2392 filelist.append(sensorData['fileLoc'])
2393 errorInfo += sensorData['errors']
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002394 #Collect all of the LEDs status
Justin Thaler666cf342019-01-23 14:44:27 -06002395 ledStatus = csdLEDs(host, args, session, myDir)
2396 if 'fileLoc' in ledStatus:
2397 filelist.append(ledStatus['fileLoc'])
2398 errorInfo += ledStatus['errors']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002399
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002400 #Collect the bmc logs
Justin Thaler666cf342019-01-23 14:44:27 -06002401 selShort = csdSelShortList(host, args, session, myDir)
2402 if 'fileLoc' in selShort:
2403 filelist.append(selShort['fileLoc'])
2404 errorInfo += selShort['errors']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002405
Justin Thaler666cf342019-01-23 14:44:27 -06002406 parsedSELs = csdParsedSels(host, args, session, myDir)
2407 if 'fileLoc' in parsedSELs:
2408 filelist.append(parsedSELs['fileLoc'])
2409 errorInfo += parsedSELs['errors']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002410
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002411 #collect RAW bmc enumeration
Justin Thaler666cf342019-01-23 14:44:27 -06002412 bmcRaw = csdFullEnumeration(host, args, session, myDir)
2413 if 'fileLoc' in bmcRaw:
2414 filelist.append(bmcRaw['fileLoc'])
2415 errorInfo += bmcRaw['errors']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002416
Justin Thaler666cf342019-01-23 14:44:27 -06002417 #wait for new dump to finish being created
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002418 waitingForNewDump = True
2419 count = 0;
Justin Thalerb4256672020-04-07 19:38:26 -05002420 print("Waiting for new BMC dump to finish being created. Wait time could be up to 5 minutes")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002421 while(waitingForNewDump):
Justin Thaler666cf342019-01-23 14:44:27 -06002422 dumpList = bmcDumpList(host, args, session)['data']
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002423 if len(dumpList) > dumpcount:
2424 waitingForNewDump = False
2425 break;
Justin Thalerb4256672020-04-07 19:38:26 -05002426 elif(count>150):
2427 print("Timed out waiting for bmc to make a new dump file. Continuing without it.")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002428 break;
2429 else:
2430 time.sleep(2)
2431 count += 1
Justin Thaler666cf342019-01-23 14:44:27 -06002432
2433 #collect all of the dump files
2434 getBMCDumps = csdCollectAllDumps(host, args, session, myDir)
2435 if 'fileList' in getBMCDumps:
2436 filelist+= getBMCDumps['fileList']
2437 errorInfo += getBMCDumps['errors']
2438
2439 #write the runtime errors to a file
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002440 try:
Justin Thaler666cf342019-01-23 14:44:27 -06002441 with open(myDir +os.sep+'openbmctoolRuntimeErrors.txt', 'w') as f:
2442 f.write(errorInfo)
2443 print("OpenBMC tool runtime errors collected and stored in " + myDir + os.sep+ "openbmctoolRuntimeErrors.txt")
2444 filelist.append(myDir+os.sep+'openbmctoolRuntimeErrors.txt')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002445 except Exception as e:
Justin Thaler666cf342019-01-23 14:44:27 -06002446 print("Failed to write OpenBMC tool runtime errors to file system.")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002447
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002448 #create the zip file
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002449 try:
Justin Thalercf1deae2018-05-25 19:35:21 -05002450 filename = myDir.split(tempfile.gettempdir()+os.sep)[-1] + "_" + toolVersion + '_openbmc.zip'
Justin Thaler666cf342019-01-23 14:44:27 -06002451 zf = zipfile.ZipFile(myDir+os.sep + filename, 'w')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002452 for myfile in filelist:
2453 zf.write(myfile, os.path.basename(myfile))
2454 zf.close()
Justin Thaler666cf342019-01-23 14:44:27 -06002455 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 -06002456 except Exception as e:
2457 print("Failed to create zip file with collected information")
Justin Thaler666cf342019-01-23 14:44:27 -06002458 return "data collection finished"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002459
Justin Thalere412dc22018-01-12 16:28:24 -06002460
2461def healthCheck(host, args, session):
2462 """
2463 runs a health check on the platform
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002464
Justin Thalere412dc22018-01-12 16:28:24 -06002465 @param host: string, the hostname or IP address of the bmc
2466 @param args: contains additional arguments used by the bmc sub command
2467 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002468 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
2469 """
Justin Thalere412dc22018-01-12 16:28:24 -06002470 #check fru status and get as json to easily work through
2471 d = vars(args)
2472 useJson = d['json']
2473 d['json'] = True
2474 d['verbose']= False
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002475
Justin Thalere412dc22018-01-12 16:28:24 -06002476 frus = json.loads(fruStatus(host, args, session))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002477
Justin Thalere412dc22018-01-12 16:28:24 -06002478 hwStatus= "OK"
2479 performanceStatus = "OK"
2480 for key in frus:
2481 if frus[key]["Functional"] == "No" and frus[key]["Present"] == "Yes":
2482 hwStatus= "Degraded"
Justin Thalerfb9c81c2018-07-16 11:14:37 -05002483 if("power_supply" in key or "powersupply" in key):
2484 gpuCount =0
2485 for comp in frus:
Justin Thalere412dc22018-01-12 16:28:24 -06002486 if "gv100card" in comp:
2487 gpuCount +=1
2488 if gpuCount > 4:
2489 hwStatus = "Critical"
2490 performanceStatus="Degraded"
2491 break;
2492 elif("fan" in key):
2493 hwStatus = "Degraded"
2494 else:
2495 performanceStatus = "Degraded"
2496 if useJson:
2497 output = {"Hardware Status": hwStatus, "Performance": performanceStatus}
2498 output = json.dumps(output, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False)
2499 else:
2500 output = ("Hardware Status: " + hwStatus +
2501 "\nPerformance: " +performanceStatus )
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002502
2503
Justin Thalere412dc22018-01-12 16:28:24 -06002504 #SW407886: Clear the duplicate entries
2505 #collect the dups
2506 d['devdebug'] = False
2507 sels = json.loads(selPrint(host, args, session))
2508 logNums2Clr = []
2509 oldestLogNum={"logNum": "bogus" ,"key" : ""}
2510 count = 0
2511 if sels['numAlerts'] > 0:
2512 for key in sels:
2513 if "numAlerts" in key:
2514 continue
2515 try:
2516 if "slave@00:00/00:00:00:06/sbefifo1-dev0/occ1-dev0" in sels[key]['Message']:
2517 count += 1
2518 if count > 1:
2519 #preserve first occurrence
2520 if sels[key]['timestamp'] < sels[oldestLogNum['key']]['timestamp']:
2521 oldestLogNum['key']=key
2522 oldestLogNum['logNum'] = sels[key]['logNum']
2523 else:
2524 oldestLogNum['key']=key
2525 oldestLogNum['logNum'] = sels[key]['logNum']
2526 logNums2Clr.append(sels[key]['logNum'])
2527 except KeyError:
2528 continue
2529 if(count >0):
2530 logNums2Clr.remove(oldestLogNum['logNum'])
2531 #delete the dups
2532 if count >1:
Justin Thalere412dc22018-01-12 16:28:24 -06002533 data = "{\"data\": [] }"
2534 for logNum in logNums2Clr:
2535 url = "https://"+ host+ "/xyz/openbmc_project/logging/entry/"+logNum+"/action/Delete"
2536 try:
Justin Thaler27197622019-01-23 14:42:11 -06002537 session.post(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002538 except(requests.exceptions.Timeout):
2539 deleteFailed = True
2540 except(requests.exceptions.ConnectionError) as err:
2541 deleteFailed = True
2542 #End of defect resolve code
2543 d['json'] = useJson
2544 return output
2545
2546
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002547
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002548def bmc(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06002549 """
2550 handles various bmc level commands, currently bmc rebooting
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002551
Justin Thalere412dc22018-01-12 16:28:24 -06002552 @param host: string, the hostname or IP address of the bmc
2553 @param args: contains additional arguments used by the bmc sub command
2554 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002555 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
2556 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002557 if(args.type is not None):
2558 return bmcReset(host, args, session)
Justin Thalere412dc22018-01-12 16:28:24 -06002559 if(args.info):
2560 return "Not implemented at this time"
2561
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002562
Justin Thalere412dc22018-01-12 16:28:24 -06002563
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002564def bmcReset(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06002565 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002566 controls resetting the bmc. warm reset reboots the bmc, cold reset removes the configuration and reboots.
2567
Justin Thalere412dc22018-01-12 16:28:24 -06002568 @param host: string, the hostname or IP address of the bmc
2569 @param args: contains additional arguments used by the bmcReset sub command
2570 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002571 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
2572 """
Justin Thaler22b1bb52018-03-15 13:31:32 -05002573 if checkFWactivation(host, args, session):
2574 return ("BMC reset control disabled during firmware activation")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002575 if(args.type == "warm"):
2576 print("\nAttempting to reboot the BMC...:")
2577 url="https://"+host+"/xyz/openbmc_project/state/bmc0/attr/RequestedBMCTransition"
Justin Thalere412dc22018-01-12 16:28:24 -06002578 data = '{"data":"xyz.openbmc_project.State.BMC.Transition.Reboot"}'
Justin Thaler27197622019-01-23 14:42:11 -06002579 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002580 return res.text
2581 elif(args.type =="cold"):
Justin Thalere412dc22018-01-12 16:28:24 -06002582 print("\nAttempting to reboot the BMC...:")
2583 url="https://"+host+"/xyz/openbmc_project/state/bmc0/attr/RequestedBMCTransition"
Justin Thalere412dc22018-01-12 16:28:24 -06002584 data = '{"data":"xyz.openbmc_project.State.BMC.Transition.Reboot"}'
Justin Thaler27197622019-01-23 14:42:11 -06002585 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002586 return res.text
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002587 else:
2588 return "invalid command"
Justin Thalere412dc22018-01-12 16:28:24 -06002589
2590def gardClear(host, args, session):
2591 """
2592 clears the gard records from the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002593
Justin Thalere412dc22018-01-12 16:28:24 -06002594 @param host: string, the hostname or IP address of the bmc
2595 @param args: contains additional arguments used by the gardClear sub command
2596 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002597 """
Justin Thalere412dc22018-01-12 16:28:24 -06002598 url="https://"+host+"/org/open_power/control/gard/action/Reset"
Justin Thalere412dc22018-01-12 16:28:24 -06002599 data = '{"data":[]}'
2600 try:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002601
Justin Thaler27197622019-01-23 14:42:11 -06002602 res = session.post(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002603 if res.status_code == 404:
2604 return "Command not supported by this firmware version"
2605 else:
2606 return res.text
2607 except(requests.exceptions.Timeout):
2608 return connectionErrHandler(args.json, "Timeout", None)
2609 except(requests.exceptions.ConnectionError) as err:
2610 return connectionErrHandler(args.json, "ConnectionError", err)
2611
2612def activateFWImage(host, args, session):
2613 """
2614 activates a firmware image on the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002615
Justin Thalere412dc22018-01-12 16:28:24 -06002616 @param host: string, the hostname or IP address of the bmc
2617 @param args: contains additional arguments used by the fwflash sub command
2618 @param session: the active session to use
2619 @param fwID: the unique ID of the fw image to activate
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002620 """
Justin Thalere412dc22018-01-12 16:28:24 -06002621 fwID = args.imageID
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002622
Justin Thalere412dc22018-01-12 16:28:24 -06002623 #determine the existing versions
Justin Thalere412dc22018-01-12 16:28:24 -06002624 url="https://"+host+"/xyz/openbmc_project/software/enumerate"
2625 try:
Justin Thaler27197622019-01-23 14:42:11 -06002626 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002627 except(requests.exceptions.Timeout):
2628 return connectionErrHandler(args.json, "Timeout", None)
2629 except(requests.exceptions.ConnectionError) as err:
2630 return connectionErrHandler(args.json, "ConnectionError", err)
2631 existingSoftware = json.loads(resp.text)['data']
2632 altVersionID = ''
2633 versionType = ''
2634 imageKey = '/xyz/openbmc_project/software/'+fwID
2635 if imageKey in existingSoftware:
2636 versionType = existingSoftware[imageKey]['Purpose']
2637 for key in existingSoftware:
2638 if imageKey == key:
2639 continue
2640 if 'Purpose' in existingSoftware[key]:
2641 if versionType == existingSoftware[key]['Purpose']:
2642 altVersionID = key.split('/')[-1]
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002643
2644
2645
2646
Justin Thalere412dc22018-01-12 16:28:24 -06002647 url="https://"+host+"/xyz/openbmc_project/software/"+ fwID + "/attr/Priority"
2648 url1="https://"+host+"/xyz/openbmc_project/software/"+ altVersionID + "/attr/Priority"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002649 data = "{\"data\": 0}"
Justin Thalere412dc22018-01-12 16:28:24 -06002650 data1 = "{\"data\": 1 }"
2651 try:
Justin Thaler27197622019-01-23 14:42:11 -06002652 resp = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
2653 resp1 = session.put(url1, headers=jsonHeader, data=data1, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002654 except(requests.exceptions.Timeout):
2655 return connectionErrHandler(args.json, "Timeout", None)
2656 except(requests.exceptions.ConnectionError) as err:
2657 return connectionErrHandler(args.json, "ConnectionError", err)
2658 if(not args.json):
2659 if resp.status_code == 200 and resp1.status_code == 200:
Justin Thaler22b1bb52018-03-15 13:31:32 -05002660 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 -06002661 else:
2662 return "Firmware activation failed."
2663 else:
2664 return resp.text + resp1.text
Justin Thaler22b1bb52018-03-15 13:31:32 -05002665
2666def activateStatus(host, args, session):
2667 if checkFWactivation(host, args, session):
2668 return("Firmware is currently being activated. Do not reboot the BMC or start the Host OS")
2669 else:
2670 return("No firmware activations are pending")
2671
2672def extractFWimage(path, imageType):
2673 """
2674 extracts the bmc image and returns information about the package
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002675
Justin Thaler22b1bb52018-03-15 13:31:32 -05002676 @param path: the path and file name of the firmware image
2677 @param imageType: The type of image the user is trying to flash. Host or BMC
2678 @return: the image id associated with the package. returns an empty string on error.
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002679 """
Justin Thaler22b1bb52018-03-15 13:31:32 -05002680 f = tempfile.TemporaryFile()
2681 tmpDir = tempfile.gettempdir()
2682 newImageID = ""
2683 if os.path.exists(path):
2684 try:
2685 imageFile = tarfile.open(path,'r')
2686 contents = imageFile.getmembers()
2687 for tf in contents:
2688 if 'MANIFEST' in tf.name:
2689 imageFile.extract(tf.name, path=tmpDir)
2690 with open(tempfile.gettempdir() +os.sep+ tf.name, 'r') as imageInfo:
2691 for line in imageInfo:
2692 if 'purpose' in line:
2693 purpose = line.split('=')[1]
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002694 if imageType not in purpose.split('.')[-1]:
Justin Thaler22b1bb52018-03-15 13:31:32 -05002695 print('The specified image is not for ' + imageType)
2696 print('Please try again with the image for ' + imageType)
2697 return ""
2698 if 'version' == line.split('=')[0]:
2699 version = line.split('=')[1].strip().encode('utf-8')
2700 m = hashlib.sha512()
2701 m.update(version)
2702 newImageID = m.hexdigest()[:8]
2703 break
2704 try:
2705 os.remove(tempfile.gettempdir() +os.sep+ tf.name)
2706 except OSError:
2707 pass
2708 return newImageID
2709 except tarfile.ExtractError as e:
2710 print('Unable to extract information from the firmware file.')
2711 print('Ensure you have write access to the directory: ' + tmpDir)
2712 return newImageID
2713 except tarfile.TarError as e:
2714 print('This is not a valid firmware file.')
2715 return newImageID
2716 print("This is not a valid firmware file.")
2717 return newImageID
2718 else:
2719 print('The filename and path provided are not valid.')
2720 return newImageID
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002721
Justin Thaler22b1bb52018-03-15 13:31:32 -05002722def getAllFWImageIDs(fwInvDict):
2723 """
2724 gets a list of all the firmware image IDs
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002725
Justin Thaler22b1bb52018-03-15 13:31:32 -05002726 @param fwInvDict: the dictionary to search for FW image IDs
2727 @return: list containing string representation of the found image ids
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002728 """
Justin Thaler22b1bb52018-03-15 13:31:32 -05002729 idList = []
2730 for key in fwInvDict:
2731 if 'Version' in fwInvDict[key]:
2732 idList.append(key.split('/')[-1])
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002733 return idList
2734
Justin Thalere412dc22018-01-12 16:28:24 -06002735def fwFlash(host, args, session):
2736 """
2737 updates the bmc firmware and pnor firmware
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002738
Justin Thalere412dc22018-01-12 16:28:24 -06002739 @param host: string, the hostname or IP address of the bmc
2740 @param args: contains additional arguments used by the fwflash sub command
2741 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002742 """
Justin Thaler22b1bb52018-03-15 13:31:32 -05002743 d = vars(args)
Justin Thalere412dc22018-01-12 16:28:24 -06002744 if(args.type == 'bmc'):
2745 purp = 'BMC'
2746 else:
2747 purp = 'Host'
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002748
2749 #check power state of the machine. No concurrent FW updates allowed
Justin Thaler22b1bb52018-03-15 13:31:32 -05002750 d['powcmd'] = 'status'
2751 powerstate = chassisPower(host, args, session)
2752 if 'Chassis Power State: On' in powerstate:
2753 return("Aborting firmware update. Host is powered on. Please turn off the host and try again.")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002754
Justin Thaler22b1bb52018-03-15 13:31:32 -05002755 #determine the existing images on the bmc
Justin Thalere412dc22018-01-12 16:28:24 -06002756 url="https://"+host+"/xyz/openbmc_project/software/enumerate"
2757 try:
Justin Thaler27197622019-01-23 14:42:11 -06002758 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002759 except(requests.exceptions.Timeout):
2760 return connectionErrHandler(args.json, "Timeout", None)
2761 except(requests.exceptions.ConnectionError) as err:
2762 return connectionErrHandler(args.json, "ConnectionError", err)
2763 oldsoftware = json.loads(resp.text)['data']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002764
Justin Thaler22b1bb52018-03-15 13:31:32 -05002765 #Extract the tar and get information from the manifest file
2766 newversionID = extractFWimage(args.fileloc, purp)
2767 if newversionID == "":
2768 return "Unable to verify FW image."
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002769
2770
Justin Thaler22b1bb52018-03-15 13:31:32 -05002771 #check if the new image is already on the bmc
2772 if newversionID not in getAllFWImageIDs(oldsoftware):
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002773
Justin Thaler22b1bb52018-03-15 13:31:32 -05002774 #upload the file
2775 httpHeader = {'Content-Type':'application/octet-stream'}
Matt Spinler220c3c42019-01-04 15:09:29 -06002776 httpHeader.update(xAuthHeader)
Justin Thaler22b1bb52018-03-15 13:31:32 -05002777 url="https://"+host+"/upload/image"
2778 data=open(args.fileloc,'rb').read()
2779 print("Uploading file to BMC")
Justin Thalere412dc22018-01-12 16:28:24 -06002780 try:
Justin Thaler22b1bb52018-03-15 13:31:32 -05002781 resp = session.post(url, headers=httpHeader, data=data, verify=False)
Justin Thalere412dc22018-01-12 16:28:24 -06002782 except(requests.exceptions.Timeout):
2783 return connectionErrHandler(args.json, "Timeout", None)
2784 except(requests.exceptions.ConnectionError) as err:
2785 return connectionErrHandler(args.json, "ConnectionError", err)
Justin Thaler22b1bb52018-03-15 13:31:32 -05002786 if resp.status_code != 200:
2787 return "Failed to upload the file to the bmc"
Justin Thalere412dc22018-01-12 16:28:24 -06002788 else:
Justin Thaler22b1bb52018-03-15 13:31:32 -05002789 print("Upload complete.")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002790
Justin Thaler22b1bb52018-03-15 13:31:32 -05002791 #verify bmc processed the image
2792 software ={}
2793 for i in range(0, 5):
Justin Thaler22b1bb52018-03-15 13:31:32 -05002794 url="https://"+host+"/xyz/openbmc_project/software/enumerate"
2795 try:
Justin Thaler27197622019-01-23 14:42:11 -06002796 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thaler22b1bb52018-03-15 13:31:32 -05002797 except(requests.exceptions.Timeout):
2798 return connectionErrHandler(args.json, "Timeout", None)
2799 except(requests.exceptions.ConnectionError) as err:
2800 return connectionErrHandler(args.json, "ConnectionError", err)
2801 software = json.loads(resp.text)['data']
2802 #check if bmc is done processing the new image
2803 if (newversionID in getAllFWImageIDs(software)):
Justin Thalere412dc22018-01-12 16:28:24 -06002804 break
Justin Thaler22b1bb52018-03-15 13:31:32 -05002805 else:
2806 time.sleep(15)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002807
Justin Thaler22b1bb52018-03-15 13:31:32 -05002808 #activate the new image
2809 print("Activating new image: "+newversionID)
2810 url="https://"+host+"/xyz/openbmc_project/software/"+ newversionID + "/attr/RequestedActivation"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002811 data = '{"data":"xyz.openbmc_project.Software.Activation.RequestedActivations.Active"}'
Justin Thaler22b1bb52018-03-15 13:31:32 -05002812 try:
Justin Thaler27197622019-01-23 14:42:11 -06002813 resp = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thaler22b1bb52018-03-15 13:31:32 -05002814 except(requests.exceptions.Timeout):
2815 return connectionErrHandler(args.json, "Timeout", None)
2816 except(requests.exceptions.ConnectionError) as err:
2817 return connectionErrHandler(args.json, "ConnectionError", err)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002818
Justin Thaler22b1bb52018-03-15 13:31:32 -05002819 #wait for the activation to complete, timeout after ~1 hour
2820 i=0
2821 while i < 360:
2822 url="https://"+host+"/xyz/openbmc_project/software/"+ newversionID
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002823 data = '{"data":"xyz.openbmc_project.Software.Activation.RequestedActivations.Active"}'
Justin Thaler22b1bb52018-03-15 13:31:32 -05002824 try:
Justin Thaler27197622019-01-23 14:42:11 -06002825 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thaler22b1bb52018-03-15 13:31:32 -05002826 except(requests.exceptions.Timeout):
2827 return connectionErrHandler(args.json, "Timeout", None)
2828 except(requests.exceptions.ConnectionError) as err:
2829 return connectionErrHandler(args.json, "ConnectionError", err)
2830 fwInfo = json.loads(resp.text)['data']
2831 if 'Activating' not in fwInfo['Activation'] and 'Activating' not in fwInfo['RequestedActivation']:
2832 print('')
2833 break
2834 else:
2835 sys.stdout.write('.')
2836 sys.stdout.flush()
2837 time.sleep(10) #check every 10 seconds
2838 return "Firmware flash and activation completed. Please reboot the bmc and then boot the host OS for the changes to take effect. "
2839 else:
2840 print("This image has been found on the bmc. Activating image: " + newversionID)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002841
Justin Thaler22b1bb52018-03-15 13:31:32 -05002842 d['imageID'] = newversionID
2843 return activateFWImage(host, args, session)
Justin Thalere412dc22018-01-12 16:28:24 -06002844
Justin Thaler3d71d402018-07-24 14:35:39 -05002845def getFWInventoryAttributes(rawFWInvItem, ID):
2846 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002847 gets and lists all of the firmware in the system.
2848
Justin Thaler3d71d402018-07-24 14:35:39 -05002849 @return: returns a dictionary containing the image attributes
2850 """
2851 reqActivation = rawFWInvItem["RequestedActivation"].split('.')[-1]
2852 pendingActivation = ""
2853 if reqActivation == "None":
2854 pendingActivation = "No"
2855 else:
2856 pendingActivation = "Yes"
2857 firmwareAttr = {ID: {
2858 "Purpose": rawFWInvItem["Purpose"].split('.')[-1],
2859 "Version": rawFWInvItem["Version"],
2860 "RequestedActivation": pendingActivation,
2861 "ID": ID}}
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002862
Justin Thaler3d71d402018-07-24 14:35:39 -05002863 if "ExtendedVersion" in rawFWInvItem:
2864 firmwareAttr[ID]['ExtendedVersion'] = rawFWInvItem['ExtendedVersion'].split(',')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002865 else:
Justin Thaler3d71d402018-07-24 14:35:39 -05002866 firmwareAttr[ID]['ExtendedVersion'] = ""
2867 return firmwareAttr
2868
2869def parseFWdata(firmwareDict):
2870 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002871 creates a dictionary with parsed firmware data
2872
Justin Thaler3d71d402018-07-24 14:35:39 -05002873 @return: returns a dictionary containing the image attributes
2874 """
2875 firmwareInfoDict = {"Functional": {}, "Activated":{}, "NeedsActivated":{}}
2876 for key in firmwareDict['data']:
2877 #check for valid endpoint
2878 if "Purpose" in firmwareDict['data'][key]:
2879 id = key.split('/')[-1]
2880 if firmwareDict['data'][key]['Activation'].split('.')[-1] == "Active":
2881 fwActivated = True
2882 else:
2883 fwActivated = False
Justin Thalercb68e062019-03-26 19:04:52 -05002884 if 'Priority' in firmwareDict['data'][key]:
2885 if firmwareDict['data'][key]['Priority'] == 0:
2886 firmwareInfoDict['Functional'].update(getFWInventoryAttributes(firmwareDict['data'][key], id))
2887 elif firmwareDict['data'][key]['Priority'] >= 0 and fwActivated:
2888 firmwareInfoDict['Activated'].update(getFWInventoryAttributes(firmwareDict['data'][key], id))
2889 else:
2890 firmwareInfoDict['NeedsActivated'].update(getFWInventoryAttributes(firmwareDict['data'][key], id))
Justin Thaler3d71d402018-07-24 14:35:39 -05002891 else:
Justin Thalercb68e062019-03-26 19:04:52 -05002892 firmwareInfoDict['NeedsActivated'].update(getFWInventoryAttributes(firmwareDict['data'][key], id))
Justin Thaler3d71d402018-07-24 14:35:39 -05002893 emptySections = []
2894 for key in firmwareInfoDict:
2895 if len(firmwareInfoDict[key])<=0:
2896 emptySections.append(key)
2897 for key in emptySections:
2898 del firmwareInfoDict[key]
2899 return firmwareInfoDict
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002900
Justin Thaler3d71d402018-07-24 14:35:39 -05002901def displayFWInvenory(firmwareInfoDict, args):
2902 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002903 gets and lists all of the firmware in the system.
2904
Justin Thaler3d71d402018-07-24 14:35:39 -05002905 @return: returns a string containing all of the firmware information
2906 """
2907 output = ""
2908 if not args.json:
2909 for key in firmwareInfoDict:
2910 for subkey in firmwareInfoDict[key]:
2911 firmwareInfoDict[key][subkey]['ExtendedVersion'] = str(firmwareInfoDict[key][subkey]['ExtendedVersion'])
2912 if not args.verbose:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002913 output = "---Running Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002914 colNames = ["Purpose", "Version", "ID"]
2915 keylist = ["Purpose", "Version", "ID"]
2916 output += tableDisplay(keylist, colNames, firmwareInfoDict["Functional"])
2917 if "Activated" in firmwareInfoDict:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002918 output += "\n---Available Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002919 output += tableDisplay(keylist, colNames, firmwareInfoDict["Activated"])
2920 if "NeedsActivated" in firmwareInfoDict:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002921 output += "\n---Needs Activated Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002922 output += tableDisplay(keylist, colNames, firmwareInfoDict["NeedsActivated"])
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002923
Justin Thaler3d71d402018-07-24 14:35:39 -05002924 else:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002925 output = "---Running Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002926 colNames = ["Purpose", "Version", "ID", "Pending Activation", "Extended Version"]
2927 keylist = ["Purpose", "Version", "ID", "RequestedActivation", "ExtendedVersion"]
2928 output += tableDisplay(keylist, colNames, firmwareInfoDict["Functional"])
2929 if "Activated" in firmwareInfoDict:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002930 output += "\n---Available Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002931 output += tableDisplay(keylist, colNames, firmwareInfoDict["Activated"])
2932 if "NeedsActivated" in firmwareInfoDict:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002933 output += "\n---Needs Activated Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002934 output += tableDisplay(keylist, colNames, firmwareInfoDict["NeedsActivated"])
2935 return output
2936 else:
2937 return str(json.dumps(firmwareInfoDict, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False))
2938
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002939def firmwareList(host, args, session):
Justin Thaler3d71d402018-07-24 14:35:39 -05002940 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002941 gets and lists all of the firmware in the system.
2942
Justin Thaler3d71d402018-07-24 14:35:39 -05002943 @return: returns a string containing all of the firmware information
2944 """
Justin Thaler3d71d402018-07-24 14:35:39 -05002945 url="https://{hostname}/xyz/openbmc_project/software/enumerate".format(hostname=host)
2946 try:
Justin Thaler27197622019-01-23 14:42:11 -06002947 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thaler3d71d402018-07-24 14:35:39 -05002948 except(requests.exceptions.Timeout):
2949 return(connectionErrHandler(args.json, "Timeout", None))
2950 firmwareDict = json.loads(res.text)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002951
Justin Thaler3d71d402018-07-24 14:35:39 -05002952 #sort the received information
2953 firmwareInfoDict = parseFWdata(firmwareDict)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002954
Justin Thaler3d71d402018-07-24 14:35:39 -05002955 #display the information
2956 return displayFWInvenory(firmwareInfoDict, args)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002957
2958
Adriana Kobylak5af2fad2018-11-08 12:33:43 -06002959def deleteFWVersion(host, args, session):
2960 """
2961 deletes a firmware version on the BMC
2962
2963 @param host: string, the hostname or IP address of the BMC
2964 @param args: contains additional arguments used by the fwflash sub command
2965 @param session: the active session to use
2966 @param fwID: the unique ID of the fw version to delete
2967 """
2968 fwID = args.versionID
2969
2970 print("Deleting version: "+fwID)
2971 url="https://"+host+"/xyz/openbmc_project/software/"+ fwID + "/action/Delete"
Adriana Kobylak5af2fad2018-11-08 12:33:43 -06002972 data = "{\"data\": [] }"
2973
2974 try:
Justin Thaler27197622019-01-23 14:42:11 -06002975 res = session.post(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Adriana Kobylak5af2fad2018-11-08 12:33:43 -06002976 except(requests.exceptions.Timeout):
2977 return(connectionErrHandler(args.json, "Timeout", None))
2978 if res.status_code == 200:
2979 return ('The firmware version has been deleted')
2980 else:
2981 return ('Unable to delete the specified firmware version')
2982
Klaus Heinrich Kiwi0b5b2042020-12-03 14:20:27 -03002983def deleteFWAll(host, args, session):
2984 """
2985 deletes ALL contents for firmware software catalog
2986
2987 @param host: string, the hostname or IP address of the BMC
2988 @param args: contains additional arguments used by the fwflash sub command
2989 @param session: the active session to use
2990 """
2991
2992 print("Deleting ALL firmware versions")
2993 url="https://"+host+"/xyz/openbmc_project/software/action/DeleteAll"
2994 data = "{\"data\": [] }"
2995
2996 try:
2997 res = session.post(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
2998 except(requests.exceptions.Timeout):
2999 return(connectionErrHandler(args.json, "Timeout", None))
3000 if res.status_code == 200:
3001 return ('All firmware versions were deleted')
3002 else:
3003 return ('Uspecified error while deleting All firmware versions')
3004
Adriana Kobylak5af2fad2018-11-08 12:33:43 -06003005
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05003006def restLogging(host, args, session):
3007 """
3008 Called by the logging function. Turns REST API logging on/off.
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003009
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05003010 @param host: string, the hostname or IP address of the bmc
3011 @param args: contains additional arguments used by the logging sub command
3012 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003013 @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 -05003014 """
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05003015 url="https://"+host+"/xyz/openbmc_project/logging/rest_api_logs/attr/Enabled"
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05003016
3017 if(args.rest_logging == 'on'):
3018 data = '{"data": 1}'
3019 elif(args.rest_logging == 'off'):
3020 data = '{"data": 0}'
3021 else:
3022 return "Invalid logging rest_api command"
3023
3024 try:
Justin Thaler27197622019-01-23 14:42:11 -06003025 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05003026 except(requests.exceptions.Timeout):
3027 return(connectionErrHandler(args.json, "Timeout", None))
3028 return res.text
3029
3030
Deepak Kodihalli02d53282018-09-18 06:53:31 -05003031def remoteLogging(host, args, session):
3032 """
3033 Called by the logging function. View config information for/disable remote logging (rsyslog).
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003034
Deepak Kodihalli02d53282018-09-18 06:53:31 -05003035 @param host: string, the hostname or IP address of the bmc
3036 @param args: contains additional arguments used by the logging sub command
3037 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003038 @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 -05003039 """
3040
3041 url="https://"+host+"/xyz/openbmc_project/logging/config/remote"
Deepak Kodihalli02d53282018-09-18 06:53:31 -05003042
3043 try:
3044 if(args.remote_logging == 'view'):
Justin Thaler27197622019-01-23 14:42:11 -06003045 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Deepak Kodihalli02d53282018-09-18 06:53:31 -05003046 elif(args.remote_logging == 'disable'):
Justin Thaler27197622019-01-23 14:42:11 -06003047 res = session.put(url + '/attr/Port', headers=jsonHeader, json = {"data": 0}, verify=False, timeout=baseTimeout)
3048 res = session.put(url + '/attr/Address', headers=jsonHeader, json = {"data": ""}, verify=False, timeout=baseTimeout)
Deepak Kodihalli02d53282018-09-18 06:53:31 -05003049 else:
3050 return "Invalid logging remote_logging command"
3051 except(requests.exceptions.Timeout):
3052 return(connectionErrHandler(args.json, "Timeout", None))
3053 return res.text
3054
3055
3056def remoteLoggingConfig(host, args, session):
3057 """
3058 Called by the logging function. Configures remote logging (rsyslog).
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003059
Deepak Kodihalli02d53282018-09-18 06:53:31 -05003060 @param host: string, the hostname or IP address of the bmc
3061 @param args: contains additional arguments used by the logging sub command
3062 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003063 @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 -05003064 """
3065
3066 url="https://"+host+"/xyz/openbmc_project/logging/config/remote"
Deepak Kodihalli02d53282018-09-18 06:53:31 -05003067
3068 try:
Justin Thaler27197622019-01-23 14:42:11 -06003069 res = session.put(url + '/attr/Port', headers=jsonHeader, json = {"data": args.port}, verify=False, timeout=baseTimeout)
3070 res = session.put(url + '/attr/Address', headers=jsonHeader, json = {"data": args.address}, verify=False, timeout=baseTimeout)
Deepak Kodihalli02d53282018-09-18 06:53:31 -05003071 except(requests.exceptions.Timeout):
3072 return(connectionErrHandler(args.json, "Timeout", None))
3073 return res.text
3074
Marri Devender Rao82590dc2019-06-06 04:54:22 -05003075def redfishSupportPresent(host, session):
3076 url = "https://" + host + "/redfish/v1"
3077 try:
3078 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
3079 except(requests.exceptions.Timeout):
3080 return False
3081 except(requests.exceptions.ConnectionError) as err:
3082 return False
3083 if resp.status_code != 200:
3084 return False
3085 else:
3086 return True
Ratan Gupta9166cd22018-10-01 18:09:40 +05303087
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05003088def certificateUpdate(host, args, session):
3089 """
3090 Called by certificate management function. update server/client/authority certificates
3091 Example:
3092 certificate update server https -f cert.pem
3093 certificate update authority ldap -f Root-CA.pem
3094 certificate update client ldap -f cert.pem
3095 @param host: string, the hostname or IP address of the bmc
3096 @param args: contains additional arguments used by the certificate update sub command
3097 @param session: the active session to use
3098 """
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05003099 httpHeader = {'Content-Type': 'application/octet-stream'}
Matt Spinler220c3c42019-01-04 15:09:29 -06003100 httpHeader.update(xAuthHeader)
Brad Bishop5da038f2020-07-10 14:21:43 -04003101 data = open(args.fileloc, 'r').read()
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05003102 try:
Marri Devender Rao82590dc2019-06-06 04:54:22 -05003103 if redfishSupportPresent(host, session):
Marri Devender Rao62db08a2019-08-22 03:16:02 -05003104 if(args.type.lower() == 'server' and args.service.lower() != "https"):
3105 return "Invalid service type"
3106 if(args.type.lower() == 'client' and args.service.lower() != "ldap"):
3107 return "Invalid service type"
3108 if(args.type.lower() == 'authority' and args.service.lower() != "ldap"):
3109 return "Invalid service type"
Marri Devender Rao82590dc2019-06-06 04:54:22 -05003110 url = "";
3111 if(args.type.lower() == 'server'):
3112 url = "https://" + host + \
3113 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"
3114 elif(args.type.lower() == 'client'):
3115 url = "https://" + host + \
3116 "/redfish/v1/AccountService/LDAP/Certificates"
3117 elif(args.type.lower() == 'authority'):
3118 url = "https://" + host + \
3119 "/redfish/v1/Managers/bmc/Truststore/Certificates"
3120 else:
3121 return "Unsupported certificate type"
3122 resp = session.post(url, headers=httpHeader, data=data,
3123 verify=False)
3124 else:
3125 url = "https://" + host + "/xyz/openbmc_project/certs/" + \
3126 args.type.lower() + "/" + args.service.lower()
3127 resp = session.put(url, headers=httpHeader, data=data, verify=False)
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05003128 except(requests.exceptions.Timeout):
3129 return(connectionErrHandler(args.json, "Timeout", None))
3130 except(requests.exceptions.ConnectionError) as err:
3131 return connectionErrHandler(args.json, "ConnectionError", err)
3132 if resp.status_code != 200:
3133 print(resp.text)
3134 return "Failed to update the certificate"
3135 else:
Marri Devender Rao82590dc2019-06-06 04:54:22 -05003136 print("Update complete.")
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05003137
3138def certificateDelete(host, args, session):
3139 """
3140 Called by certificate management function to delete certificate
3141 Example:
3142 certificate delete server https
3143 certificate delete authority ldap
3144 certificate delete client ldap
3145 @param host: string, the hostname or IP address of the bmc
3146 @param args: contains additional arguments used by the certificate delete sub command
3147 @param session: the active session to use
3148 """
Marri Devender Rao77e78682019-07-17 03:18:35 -05003149 if redfishSupportPresent(host, session):
3150 return "Not supported, please use certificate replace instead";
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05003151 httpHeader = {'Content-Type': 'multipart/form-data'}
Matt Spinler220c3c42019-01-04 15:09:29 -06003152 httpHeader.update(xAuthHeader)
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05003153 url = "https://" + host + "/xyz/openbmc_project/certs/" + args.type.lower() + "/" + args.service.lower()
3154 print("Deleting certificate url=" + url)
3155 try:
3156 resp = session.delete(url, headers=httpHeader)
3157 except(requests.exceptions.Timeout):
3158 return(connectionErrHandler(args.json, "Timeout", None))
3159 except(requests.exceptions.ConnectionError) as err:
3160 return connectionErrHandler(args.json, "ConnectionError", err)
3161 if resp.status_code != 200:
3162 print(resp.text)
3163 return "Failed to delete the certificate"
3164 else:
Marri Devender Rao77e78682019-07-17 03:18:35 -05003165 print("Delete complete.")
Deepak Kodihalli02d53282018-09-18 06:53:31 -05003166
Marri Devender Raodfe81ad2019-07-01 05:38:09 -05003167def certificateReplace(host, args, session):
3168 """
3169 Called by certificate management function. replace server/client/
3170 authority certificates
3171 Example:
3172 certificate replace server https -f cert.pem
3173 certificate replace authority ldap -f Root-CA.pem
3174 certificate replace client ldap -f cert.pem
3175 @param host: string, the hostname or IP address of the bmc
3176 @param args: contains additional arguments used by the certificate
3177 replace sub command
3178 @param session: the active session to use
3179 """
Brad Bishop5da038f2020-07-10 14:21:43 -04003180 cert = open(args.fileloc, 'r').read()
Marri Devender Raodfe81ad2019-07-01 05:38:09 -05003181 try:
3182 if redfishSupportPresent(host, session):
3183 httpHeader = {'Content-Type': 'application/json'}
3184 httpHeader.update(xAuthHeader)
3185 url = "";
Marri Devender Rao62db08a2019-08-22 03:16:02 -05003186 if(args.type.lower() == 'server' and args.service.lower() != "https"):
3187 return "Invalid service type"
3188 if(args.type.lower() == 'client' and args.service.lower() != "ldap"):
3189 return "Invalid service type"
3190 if(args.type.lower() == 'authority' and args.service.lower() != "ldap"):
3191 return "Invalid service type"
Marri Devender Raodfe81ad2019-07-01 05:38:09 -05003192 if(args.type.lower() == 'server'):
3193 url = "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/1"
3194 elif(args.type.lower() == 'client'):
3195 url = "/redfish/v1/AccountService/LDAP/Certificates/1"
3196 elif(args.type.lower() == 'authority'):
3197 url = "/redfish/v1/Managers/bmc/Truststore/Certificates/1"
3198 replaceUrl = "https://" + host + \
3199 "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate"
3200 data ={"CertificateUri":{"@odata.id":url}, "CertificateType":"PEM",
3201 "CertificateString":cert}
3202 resp = session.post(replaceUrl, headers=httpHeader, json=data, verify=False)
3203 else:
3204 httpHeader = {'Content-Type': 'application/octet-stream'}
3205 httpHeader.update(xAuthHeader)
3206 url = "https://" + host + "/xyz/openbmc_project/certs/" + \
3207 args.type.lower() + "/" + args.service.lower()
3208 resp = session.delete(url, headers=httpHeader)
3209 resp = session.put(url, headers=httpHeader, data=cert, verify=False)
3210 except(requests.exceptions.Timeout):
3211 return(connectionErrHandler(args.json, "Timeout", None))
3212 except(requests.exceptions.ConnectionError) as err:
3213 return connectionErrHandler(args.json, "ConnectionError", err)
3214 if resp.status_code != 200:
3215 print(resp.text)
3216 return "Failed to replace the certificate"
3217 else:
3218 print("Replace complete.")
3219 return resp.text
3220
Marri Devender Rao34646402019-07-01 05:46:03 -05003221def certificateDisplay(host, args, session):
3222 """
3223 Called by certificate management function. display server/client/
3224 authority certificates
3225 Example:
3226 certificate display server
3227 certificate display authority
3228 certificate display client
3229 @param host: string, the hostname or IP address of the bmc
3230 @param args: contains additional arguments used by the certificate
3231 display sub command
3232 @param session: the active session to use
3233 """
3234 if not redfishSupportPresent(host, session):
3235 return "Not supported";
3236
3237 httpHeader = {'Content-Type': 'application/octet-stream'}
3238 httpHeader.update(xAuthHeader)
3239 if(args.type.lower() == 'server'):
3240 url = "https://" + host + \
3241 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/1"
3242 elif(args.type.lower() == 'client'):
3243 url = "https://" + host + \
3244 "/redfish/v1/AccountService/LDAP/Certificates/1"
3245 elif(args.type.lower() == 'authority'):
3246 url = "https://" + host + \
3247 "/redfish/v1/Managers/bmc/Truststore/Certificates/1"
3248 try:
3249 resp = session.get(url, headers=httpHeader, verify=False)
3250 except(requests.exceptions.Timeout):
3251 return(connectionErrHandler(args.json, "Timeout", None))
3252 except(requests.exceptions.ConnectionError) as err:
3253 return connectionErrHandler(args.json, "ConnectionError", err)
3254 if resp.status_code != 200:
3255 print(resp.text)
3256 return "Failed to display the certificate"
3257 else:
3258 print("Display complete.")
3259 return resp.text
3260
Marri Devender Raoa208ff82019-07-01 05:51:27 -05003261def certificateList(host, args, session):
3262 """
3263 Called by certificate management function.
3264 Example:
3265 certificate list
3266 @param host: string, the hostname or IP address of the bmc
3267 @param args: contains additional arguments used by the certificate
3268 list sub command
3269 @param session: the active session to use
3270 """
3271 if not redfishSupportPresent(host, session):
3272 return "Not supported";
3273
3274 httpHeader = {'Content-Type': 'application/octet-stream'}
3275 httpHeader.update(xAuthHeader)
3276 url = "https://" + host + \
3277 "/redfish/v1/CertificateService/CertificateLocations/"
3278 try:
3279 resp = session.get(url, headers=httpHeader, verify=False)
3280 except(requests.exceptions.Timeout):
3281 return(connectionErrHandler(args.json, "Timeout", None))
3282 except(requests.exceptions.ConnectionError) as err:
3283 return connectionErrHandler(args.json, "ConnectionError", err)
3284 if resp.status_code != 200:
3285 print(resp.text)
3286 return "Failed to list certificates"
3287 else:
3288 print("List certificates complete.")
3289 return resp.text
3290
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05003291def certificateGenerateCSR(host, args, session):
3292 """
3293 Called by certificate management function. Generate CSR for server/
3294 client certificates
3295 Example:
Marri Devender Raodf0e1a42019-09-09 08:18:27 -05003296 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
3297 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 -05003298 @param host: string, the hostname or IP address of the bmc
3299 @param args: contains additional arguments used by the certificate replace sub command
3300 @param session: the active session to use
3301 """
3302 if not redfishSupportPresent(host, session):
3303 return "Not supported";
3304
3305 httpHeader = {'Content-Type': 'application/octet-stream'}
3306 httpHeader.update(xAuthHeader)
3307 url = "";
3308 if(args.type.lower() == 'server'):
3309 url = "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/"
Marri Devender Rao88064f02019-08-19 09:00:30 -05003310 usage_list = ["ServerAuthentication"]
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05003311 elif(args.type.lower() == 'client'):
3312 url = "/redfish/v1/AccountService/LDAP/Certificates/"
Marri Devender Rao88064f02019-08-19 09:00:30 -05003313 usage_list = ["ClientAuthentication"]
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05003314 elif(args.type.lower() == 'authority'):
3315 url = "/redfish/v1/Managers/bmc/Truststore/Certificates/"
3316 print("Generating CSR url=" + url)
3317 generateCSRUrl = "https://" + host + \
3318 "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR"
3319 try:
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05003320 alt_name_list = args.alternativeNames.split(",")
3321 data ={"CertificateCollection":{"@odata.id":url},
3322 "CommonName":args.commonName, "City":args.city,
3323 "Country":args.country, "Organization":args.organization,
3324 "OrganizationalUnit":args.organizationUnit, "State":args.state,
Marri Devender Raodf0e1a42019-09-09 08:18:27 -05003325 "KeyPairAlgorithm":args.keyPairAlgorithm, "KeyCurveId":args.keyCurveId,
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05003326 "AlternativeNames":alt_name_list, "ContactPerson":args.contactPerson,
3327 "Email":args.email, "GivenName":args.givenname, "Initials":args.initials,
3328 "KeyUsage":usage_list, "Surname":args.surname,
3329 "UnstructuredName":args.unstructuredname}
3330 resp = session.post(generateCSRUrl, headers=httpHeader,
3331 json=data, verify=False)
3332 except(requests.exceptions.Timeout):
3333 return(connectionErrHandler(args.json, "Timeout", None))
3334 except(requests.exceptions.ConnectionError) as err:
3335 return connectionErrHandler(args.json, "ConnectionError", err)
3336 if resp.status_code != 200:
3337 print(resp.text)
3338 return "Failed to generate CSR"
3339 else:
3340 print("GenerateCSR complete.")
3341 return resp.text
3342
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003343def enableLDAPConfig(host, args, session):
Ratan Gupta9166cd22018-10-01 18:09:40 +05303344 """
3345 Called by the ldap function. Configures LDAP.
3346
3347 @param host: string, the hostname or IP address of the bmc
3348 @param args: contains additional arguments used by the ldap subcommand
3349 @param session: the active session to use
3350 @param args.json: boolean, if this flag is set to true, the output will
3351 be provided in json format for programmatic consumption
3352 """
3353
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003354 if(isRedfishSupport):
3355 return enableLDAP(host, args, session)
3356 else:
3357 return enableLegacyLDAP(host, args, session)
3358
3359def enableLegacyLDAP(host, args, session):
3360 """
3361 Called by the ldap function. Configures LDAP on Lagecy systems.
3362
3363 @param host: string, the hostname or IP address of the bmc
3364 @param args: contains additional arguments used by the ldap subcommand
3365 @param session: the active session to use
3366 @param args.json: boolean, if this flag is set to true, the output will
3367 be provided in json format for programmatic consumption
3368 """
3369
Ratan Gupta9166cd22018-10-01 18:09:40 +05303370 url='https://'+host+'/xyz/openbmc_project/user/ldap/action/CreateConfig'
Ratan Gupta9166cd22018-10-01 18:09:40 +05303371 scope = {
3372 'sub' : 'xyz.openbmc_project.User.Ldap.Create.SearchScope.sub',
3373 'one' : 'xyz.openbmc_project.User.Ldap.Create.SearchScope.one',
3374 'base': 'xyz.openbmc_project.User.Ldap.Create.SearchScope.base'
3375 }
3376
3377 serverType = {
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003378 'ActiveDirectory' : 'xyz.openbmc_project.User.Ldap.Create.Type.ActiveDirectory',
3379 'OpenLDAP' : 'xyz.openbmc_project.User.Ldap.Create.Type.OpenLdap'
Ratan Gupta9166cd22018-10-01 18:09:40 +05303380 }
3381
3382 data = {"data": [args.uri, args.bindDN, args.baseDN, args.bindPassword, scope[args.scope], serverType[args.serverType]]}
3383
3384 try:
Justin Thaler27197622019-01-23 14:42:11 -06003385 res = session.post(url, headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
Ratan Gupta9166cd22018-10-01 18:09:40 +05303386 except(requests.exceptions.Timeout):
3387 return(connectionErrHandler(args.json, "Timeout", None))
3388 except(requests.exceptions.ConnectionError) as err:
3389 return connectionErrHandler(args.json, "ConnectionError", err)
3390
3391 return res.text
3392
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003393def enableLDAP(host, args, session):
3394 """
3395 Called by the ldap function. Configures LDAP for systems with latest user-manager design changes
3396
3397 @param host: string, the hostname or IP address of the bmc
3398 @param args: contains additional arguments used by the ldap subcommand
3399 @param session: the active session to use
3400 @param args.json: boolean, if this flag is set to true, the output will
3401 be provided in json format for programmatic consumption
3402 """
3403
3404 scope = {
3405 'sub' : 'xyz.openbmc_project.User.Ldap.Config.SearchScope.sub',
3406 'one' : 'xyz.openbmc_project.User.Ldap.Config.SearchScope.one',
3407 'base': 'xyz.openbmc_project.User.Ldap.Config.SearchScope.base'
3408 }
3409
3410 serverType = {
3411 'ActiveDirectory' : 'xyz.openbmc_project.User.Ldap.Config.Type.ActiveDirectory',
3412 'OpenLDAP' : 'xyz.openbmc_project.User.Ldap.Config.Type.OpenLdap'
3413 }
3414
3415 url = "https://"+host+"/xyz/openbmc_project/user/ldap/"
3416
3417 serverTypeEnabled = getLDAPTypeEnabled(host,session)
3418 serverTypeToBeEnabled = args.serverType
3419
3420 #If the given LDAP type is already enabled, then return
3421 if (serverTypeToBeEnabled == serverTypeEnabled):
3422 return("Server type " + serverTypeToBeEnabled + " is already enabled...")
3423
3424 try:
3425
3426 # Copy the role map from the currently enabled LDAP server type
3427 # to the newly enabled server type
3428 # Disable the currently enabled LDAP server type. Unless
3429 # it is disabled, we cannot enable a new LDAP server type
3430 if (serverTypeEnabled is not None):
3431
3432 if (serverTypeToBeEnabled != serverTypeEnabled):
3433 res = syncRoleMap(host,args,session,serverTypeEnabled,serverTypeToBeEnabled)
3434
3435 data = "{\"data\": 0 }"
3436 res = session.put(url + serverTypeMap[serverTypeEnabled] + '/attr/Enabled', headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
3437
3438 data = {"data": args.baseDN}
3439 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/LDAPBaseDN', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
3440 if (res.status_code != requests.codes.ok):
3441 print("Updates to the property LDAPBaseDN failed...")
3442 return(res.text)
3443
3444 data = {"data": args.bindDN}
3445 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/LDAPBindDN', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
3446 if (res.status_code != requests.codes.ok):
3447 print("Updates to the property LDAPBindDN failed...")
3448 return(res.text)
3449
3450 data = {"data": args.bindPassword}
3451 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/LDAPBindDNPassword', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
3452 if (res.status_code != requests.codes.ok):
3453 print("Updates to the property LDAPBindDNPassword failed...")
3454 return(res.text)
3455
3456 data = {"data": scope[args.scope]}
3457 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/LDAPSearchScope', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
3458 if (res.status_code != requests.codes.ok):
3459 print("Updates to the property LDAPSearchScope failed...")
3460 return(res.text)
3461
3462 data = {"data": args.uri}
3463 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/LDAPServerURI', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
3464 if (res.status_code != requests.codes.ok):
3465 print("Updates to the property LDAPServerURI failed...")
3466 return(res.text)
3467
3468 data = {"data": args.groupAttrName}
3469 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/GroupNameAttribute', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
3470 if (res.status_code != requests.codes.ok):
3471 print("Updates to the property GroupNameAttribute failed...")
3472 return(res.text)
3473
3474 data = {"data": args.userAttrName}
3475 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/UserNameAttribute', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
3476 if (res.status_code != requests.codes.ok):
3477 print("Updates to the property UserNameAttribute failed...")
3478 return(res.text)
3479
3480 #After updating the properties, enable the new server type
3481 data = "{\"data\": 1 }"
3482 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/Enabled', headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
3483
3484 except(requests.exceptions.Timeout):
3485 return(connectionErrHandler(args.json, "Timeout", None))
3486 except(requests.exceptions.ConnectionError) as err:
3487 return connectionErrHandler(args.json, "ConnectionError", err)
3488 return res.text
Ratan Gupta9166cd22018-10-01 18:09:40 +05303489
3490def disableLDAP(host, args, session):
3491 """
3492 Called by the ldap function. Deletes the LDAP Configuration.
3493
3494 @param host: string, the hostname or IP address of the bmc
3495 @param args: contains additional arguments used by the ldap subcommand
3496 @param session: the active session to use
3497 @param args.json: boolean, if this flag is set to true, the output
3498 will be provided in json format for programmatic consumption
3499 """
3500
Ratan Gupta9166cd22018-10-01 18:09:40 +05303501 try:
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003502 if (isRedfishSupport) :
3503
3504 url = "https://"+host+"/xyz/openbmc_project/user/ldap/"
3505
3506 serverTypeEnabled = getLDAPTypeEnabled(host,session)
3507
3508 if (serverTypeEnabled is not None):
3509 #To keep the role map in sync,
3510 #If the server type being disabled has role map, then
3511 # - copy the role map to the other server type(s)
3512 for serverType in serverTypeMap.keys():
3513 if (serverType != serverTypeEnabled):
3514 res = syncRoleMap(host,args,session,serverTypeEnabled,serverType)
3515
3516 #Disable the currently enabled LDAP server type
3517 data = "{\"data\": 0 }"
3518 res = session.put(url + serverTypeMap[serverTypeEnabled] + '/attr/Enabled', headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
3519
3520 else:
3521 return("LDAP server has not been enabled...")
3522
3523 else :
3524 url='https://'+host+'/xyz/openbmc_project/user/ldap/config/action/delete'
3525 data = {"data": []}
3526 res = session.post(url, headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
3527
Ratan Gupta9166cd22018-10-01 18:09:40 +05303528 except(requests.exceptions.Timeout):
3529 return(connectionErrHandler(args.json, "Timeout", None))
3530 except(requests.exceptions.ConnectionError) as err:
3531 return connectionErrHandler(args.json, "ConnectionError", err)
3532
3533 return res.text
3534
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003535def enableDHCP(host, args, session):
3536
3537 """
3538 Called by the network function. Enables DHCP.
3539
3540 @param host: string, the hostname or IP address of the bmc
3541 @param args: contains additional arguments used by the ldap subcommand
3542 args.json: boolean, if this flag is set to true, the output
3543 will be provided in json format for programmatic consumption
3544 @param session: the active session to use
3545 """
3546
3547 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3548 "/attr/DHCPEnabled"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003549 data = "{\"data\": 1 }"
3550 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003551 res = session.put(url, headers=jsonHeader, data=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003552 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003553
3554 except(requests.exceptions.Timeout):
3555 return(connectionErrHandler(args.json, "Timeout", None))
3556 except(requests.exceptions.ConnectionError) as err:
3557 return connectionErrHandler(args.json, "ConnectionError", err)
3558 if res.status_code == 403:
3559 return "The specified Interface"+"("+args.Interface+")"+\
3560 " doesn't exist"
3561
3562 return res.text
3563
3564
3565def disableDHCP(host, args, session):
3566 """
3567 Called by the network function. Disables DHCP.
3568
3569 @param host: string, the hostname or IP address of the bmc
3570 @param args: contains additional arguments used by the ldap subcommand
3571 args.json: boolean, if this flag is set to true, the output
3572 will be provided in json format for programmatic consumption
3573 @param session: the active session to use
3574 """
3575
3576 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3577 "/attr/DHCPEnabled"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003578 data = "{\"data\": 0 }"
3579 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003580 res = session.put(url, headers=jsonHeader, data=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003581 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003582 except(requests.exceptions.Timeout):
3583 return(connectionErrHandler(args.json, "Timeout", None))
3584 except(requests.exceptions.ConnectionError) as err:
3585 return connectionErrHandler(args.json, "ConnectionError", err)
3586 if res.status_code == 403:
3587 return "The specified Interface"+"("+args.Interface+")"+\
3588 " doesn't exist"
3589 return res.text
3590
3591
3592def getHostname(host, args, session):
3593
3594 """
3595 Called by the network function. Prints out the Hostname.
3596
3597 @param host: string, the hostname or IP address of the bmc
3598 @param args: contains additional arguments used by the ldap subcommand
3599 args.json: boolean, if this flag is set to true, the output
3600 will be provided in json format for programmatic consumption
3601 @param session: the active session to use
3602 """
3603
3604 url = "https://"+host+"/xyz/openbmc_project/network/config/attr/HostName"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003605
3606 try:
Justin Thaler27197622019-01-23 14:42:11 -06003607 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003608 except(requests.exceptions.Timeout):
3609 return(connectionErrHandler(args.json, "Timeout", None))
3610 except(requests.exceptions.ConnectionError) as err:
3611 return connectionErrHandler(args.json, "ConnectionError", err)
3612
3613 return res.text
3614
3615
3616def setHostname(host, args, session):
3617 """
3618 Called by the network function. Sets the Hostname.
3619
3620 @param host: string, the hostname or IP address of the bmc
3621 @param args: contains additional arguments used by the ldap subcommand
3622 args.json: boolean, if this flag is set to true, the output
3623 will be provided in json format for programmatic consumption
3624 @param session: the active session to use
3625 """
3626
3627 url = "https://"+host+"/xyz/openbmc_project/network/config/attr/HostName"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003628
3629 data = {"data": args.HostName}
3630
3631 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003632 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003633 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003634 except(requests.exceptions.Timeout):
3635 return(connectionErrHandler(args.json, "Timeout", None))
3636 except(requests.exceptions.ConnectionError) as err:
3637 return connectionErrHandler(args.json, "ConnectionError", err)
3638
3639 return res.text
3640
3641
3642def getDomainName(host, args, session):
3643
3644 """
3645 Called by the network function. Prints out the DomainName.
3646
3647 @param host: string, the hostname or IP address of the bmc
3648 @param args: contains additional arguments used by the ldap subcommand
3649 args.json: boolean, if this flag is set to true, the output
3650 will be provided in json format for programmatic consumption
3651 @param session: the active session to use
3652 """
3653
3654 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3655 "/attr/DomainName"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003656
3657 try:
Justin Thaler27197622019-01-23 14:42:11 -06003658 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003659 except(requests.exceptions.Timeout):
3660 return(connectionErrHandler(args.json, "Timeout", None))
3661 except(requests.exceptions.ConnectionError) as err:
3662 return connectionErrHandler(args.json, "ConnectionError", err)
3663 if res.status_code == 404:
Sunitha Harishf9bb2fa2019-09-19 01:48:00 -05003664 return "The DomainName is not configured on Interface"+"("+args.Interface+")"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003665
3666 return res.text
3667
3668
3669def setDomainName(host, args, session):
3670 """
3671 Called by the network function. Sets the DomainName.
3672
3673 @param host: string, the hostname or IP address of the bmc
3674 @param args: contains additional arguments used by the ldap subcommand
3675 args.json: boolean, if this flag is set to true, the output
3676 will be provided in json format for programmatic consumption
3677 @param session: the active session to use
3678 """
3679
3680 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3681 "/attr/DomainName"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003682
3683 data = {"data": args.DomainName.split(",")}
3684
3685 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003686 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003687 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003688 except(requests.exceptions.Timeout):
3689 return(connectionErrHandler(args.json, "Timeout", None))
3690 except(requests.exceptions.ConnectionError) as err:
3691 return connectionErrHandler(args.json, "ConnectionError", err)
3692 if res.status_code == 403:
Sunitha Harishca5c9572020-08-12 00:24:53 -05003693 return "Failed to set Domain Name"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003694
3695 return res.text
3696
3697
3698def getMACAddress(host, args, session):
3699
3700 """
3701 Called by the network function. Prints out the MACAddress.
3702
3703 @param host: string, the hostname or IP address of the bmc
3704 @param args: contains additional arguments used by the ldap subcommand
3705 args.json: boolean, if this flag is set to true, the output
3706 will be provided in json format for programmatic consumption
3707 @param session: the active session to use
3708 """
3709
3710 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3711 "/attr/MACAddress"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003712
3713 try:
Justin Thaler27197622019-01-23 14:42:11 -06003714 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003715 except(requests.exceptions.Timeout):
3716 return(connectionErrHandler(args.json, "Timeout", None))
3717 except(requests.exceptions.ConnectionError) as err:
3718 return connectionErrHandler(args.json, "ConnectionError", err)
3719 if res.status_code == 404:
Sunitha Harishca5c9572020-08-12 00:24:53 -05003720 return "Failed to get MACAddress"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003721
3722 return res.text
3723
3724
3725def setMACAddress(host, args, session):
3726 """
3727 Called by the network function. Sets the MACAddress.
3728
3729 @param host: string, the hostname or IP address of the bmc
3730 @param args: contains additional arguments used by the ldap subcommand
3731 args.json: boolean, if this flag is set to true, the output
3732 will be provided in json format for programmatic consumption
3733 @param session: the active session to use
3734 """
3735
3736 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3737 "/attr/MACAddress"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003738
3739 data = {"data": args.MACAddress}
3740
3741 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003742 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003743 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003744 except(requests.exceptions.Timeout):
3745 return(connectionErrHandler(args.json, "Timeout", None))
3746 except(requests.exceptions.ConnectionError) as err:
3747 return connectionErrHandler(args.json, "ConnectionError", err)
3748 if res.status_code == 403:
Sunitha Harishca5c9572020-08-12 00:24:53 -05003749 return "Failed to set MACAddress"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003750
3751 return res.text
3752
3753
3754def getDefaultGateway(host, args, session):
3755
3756 """
3757 Called by the network function. Prints out the DefaultGateway.
3758
3759 @param host: string, the hostname or IP address of the bmc
3760 @param args: contains additional arguments used by the ldap subcommand
3761 args.json: boolean, if this flag is set to true, the output
3762 will be provided in json format for programmatic consumption
3763 @param session: the active session to use
3764 """
3765
3766 url = "https://"+host+"/xyz/openbmc_project/network/config/attr/DefaultGateway"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003767
3768 try:
Justin Thaler27197622019-01-23 14:42:11 -06003769 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003770 except(requests.exceptions.Timeout):
3771 return(connectionErrHandler(args.json, "Timeout", None))
3772 except(requests.exceptions.ConnectionError) as err:
3773 return connectionErrHandler(args.json, "ConnectionError", err)
3774 if res.status_code == 404:
Sunitha Harishca5c9572020-08-12 00:24:53 -05003775 return "Failed to get Default Gateway info"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003776
3777 return res.text
3778
3779
3780def setDefaultGateway(host, args, session):
3781 """
3782 Called by the network function. Sets the DefaultGateway.
3783
3784 @param host: string, the hostname or IP address of the bmc
3785 @param args: contains additional arguments used by the ldap subcommand
3786 args.json: boolean, if this flag is set to true, the output
3787 will be provided in json format for programmatic consumption
3788 @param session: the active session to use
3789 """
3790
3791 url = "https://"+host+"/xyz/openbmc_project/network/config/attr/DefaultGateway"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003792
3793 data = {"data": args.DefaultGW}
3794
3795 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003796 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003797 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003798 except(requests.exceptions.Timeout):
3799 return(connectionErrHandler(args.json, "Timeout", None))
3800 except(requests.exceptions.ConnectionError) as err:
3801 return connectionErrHandler(args.json, "ConnectionError", err)
3802 if res.status_code == 403:
Sunitha Harishca5c9572020-08-12 00:24:53 -05003803 return "Failed to set Default Gateway"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003804
3805 return res.text
3806
3807
3808def viewNWConfig(host, args, session):
3809 """
3810 Called by the ldap function. Prints out network configured properties
3811
3812 @param host: string, the hostname or IP address of the bmc
3813 @param args: contains additional arguments used by the ldap subcommand
3814 args.json: boolean, if this flag is set to true, the output
3815 will be provided in json format for programmatic consumption
3816 @param session: the active session to use
3817 @return returns LDAP's configured properties.
3818 """
3819 url = "https://"+host+"/xyz/openbmc_project/network/enumerate"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003820 try:
Justin Thaler27197622019-01-23 14:42:11 -06003821 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003822 except(requests.exceptions.Timeout):
3823 return(connectionErrHandler(args.json, "Timeout", None))
3824 except(requests.exceptions.ConnectionError) as err:
3825 return connectionErrHandler(args.json, "ConnectionError", err)
3826 except(requests.exceptions.RequestException) as err:
3827 return connectionErrHandler(args.json, "RequestException", err)
3828 if res.status_code == 404:
3829 return "LDAP server config has not been created"
3830 return res.text
3831
3832
3833def getDNS(host, args, session):
3834
3835 """
3836 Called by the network function. Prints out DNS servers on the interface
3837
3838 @param host: string, the hostname or IP address of the bmc
3839 @param args: contains additional arguments used by the ldap subcommand
3840 args.json: boolean, if this flag is set to true, the output
3841 will be provided in json format for programmatic consumption
3842 @param session: the active session to use
3843 """
3844
3845 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
3846 + "/attr/Nameservers"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003847
3848 try:
Justin Thaler27197622019-01-23 14:42:11 -06003849 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003850 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 if res.status_code == 404:
Sunitha Harishf9bb2fa2019-09-19 01:48:00 -05003855 return "The NameServer is not configured on Interface"+"("+args.Interface+")"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003856
3857 return res.text
3858
3859
3860def setDNS(host, args, session):
3861 """
3862 Called by the network function. Sets DNS servers on the interface.
3863
3864 @param host: string, the hostname or IP address of the bmc
3865 @param args: contains additional arguments used by the ldap subcommand
3866 args.json: boolean, if this flag is set to true, the output
3867 will be provided in json format for programmatic consumption
3868 @param session: the active session to use
3869 """
3870
3871 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
3872 + "/attr/Nameservers"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003873
3874 data = {"data": args.DNSServers.split(",")}
3875
3876 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003877 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003878 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003879 except(requests.exceptions.Timeout):
3880 return(connectionErrHandler(args.json, "Timeout", None))
3881 except(requests.exceptions.ConnectionError) as err:
3882 return connectionErrHandler(args.json, "ConnectionError", err)
3883 if res.status_code == 403:
Sunitha Harishca5c9572020-08-12 00:24:53 -05003884 return "Failed to set DNS"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003885
3886 return res.text
3887
3888
3889def getNTP(host, args, session):
3890
3891 """
3892 Called by the network function. Prints out NTP servers on the interface
3893
3894 @param host: string, the hostname or IP address of the bmc
3895 @param args: contains additional arguments used by the ldap subcommand
3896 args.json: boolean, if this flag is set to true, the output
3897 will be provided in json format for programmatic consumption
3898 @param session: the active session to use
3899 """
3900
3901 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
3902 + "/attr/NTPServers"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003903 try:
Justin Thaler27197622019-01-23 14:42:11 -06003904 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003905 except(requests.exceptions.Timeout):
3906 return(connectionErrHandler(args.json, "Timeout", None))
3907 except(requests.exceptions.ConnectionError) as err:
3908 return connectionErrHandler(args.json, "ConnectionError", err)
3909 if res.status_code == 404:
Sunitha Harishf9bb2fa2019-09-19 01:48:00 -05003910 return "The NTPServer is not configured on Interface"+"("+args.Interface+")"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003911
3912 return res.text
3913
3914
3915def setNTP(host, args, session):
3916 """
3917 Called by the network function. Sets NTP servers on the interface.
3918
3919 @param host: string, the hostname or IP address of the bmc
3920 @param args: contains additional arguments used by the ldap subcommand
3921 args.json: boolean, if this flag is set to true, the output
3922 will be provided in json format for programmatic consumption
3923 @param session: the active session to use
3924 """
3925
3926 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
3927 + "/attr/NTPServers"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003928
3929 data = {"data": args.NTPServers.split(",")}
3930
3931 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003932 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003933 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003934 except(requests.exceptions.Timeout):
3935 return(connectionErrHandler(args.json, "Timeout", None))
3936 except(requests.exceptions.ConnectionError) as err:
3937 return connectionErrHandler(args.json, "ConnectionError", err)
3938 if res.status_code == 403:
Sunitha Harishca5c9572020-08-12 00:24:53 -05003939 return "Failed to set NTP"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003940
3941 return res.text
3942
3943
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003944def addIP(host, args, session):
3945 """
3946 Called by the network function. Configures IP address on given interface
3947
3948 @param host: string, the hostname or IP address of the bmc
3949 @param args: contains additional arguments used by the ldap subcommand
3950 args.json: boolean, if this flag is set to true, the output
3951 will be provided in json format for programmatic consumption
3952 @param session: the active session to use
3953 """
3954
3955 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
3956 + "/action/IP"
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003957 protocol = {
3958 'ipv4': 'xyz.openbmc_project.Network.IP.Protocol.IPv4',
3959 'ipv6': 'xyz.openbmc_project.Network.IP.Protocol.IPv6'
3960 }
3961
3962 data = {"data": [protocol[args.type], args.address, int(args.prefixLength),
3963 args.gateway]}
3964
3965 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003966 res = session.post(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003967 timeout=baseTimeout)
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003968 except(requests.exceptions.Timeout):
3969 return(connectionErrHandler(args.json, "Timeout", None))
3970 except(requests.exceptions.ConnectionError) as err:
3971 return connectionErrHandler(args.json, "ConnectionError", err)
3972 if res.status_code == 404:
3973 return "The specified Interface" + "(" + args.Interface + ")" +\
3974 " doesn't exist"
3975
3976 return res.text
3977
3978
3979def getIP(host, args, session):
3980 """
3981 Called by the network function. Prints out IP address of given interface
3982
3983 @param host: string, the hostname or IP address of the bmc
3984 @param args: contains additional arguments used by the ldap subcommand
3985 args.json: boolean, if this flag is set to true, the output
3986 will be provided in json format for programmatic consumption
3987 @param session: the active session to use
3988 """
3989
3990 url = "https://" + host+"/xyz/openbmc_project/network/" + args.Interface +\
3991 "/enumerate"
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003992 try:
Justin Thaler27197622019-01-23 14:42:11 -06003993 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003994 except(requests.exceptions.Timeout):
3995 return(connectionErrHandler(args.json, "Timeout", None))
3996 except(requests.exceptions.ConnectionError) as err:
3997 return connectionErrHandler(args.json, "ConnectionError", err)
3998 if res.status_code == 404:
3999 return "The specified Interface" + "(" + args.Interface + ")" +\
4000 " doesn't exist"
4001
4002 return res.text
4003
4004
4005def deleteIP(host, args, session):
4006 """
4007 Called by the network function. Deletes the IP address from given Interface
4008
4009 @param host: string, the hostname or IP address of the bmc
4010 @param args: contains additional arguments used by the ldap subcommand
4011 @param session: the active session to use
4012 @param args.json: boolean, if this flag is set to true, the output
4013 will be provided in json format for programmatic consumption
4014 """
4015
4016 url = "https://"+host+"/xyz/openbmc_project/network/" + args.Interface+\
4017 "/enumerate"
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004018 data = {"data": []}
4019 try:
Justin Thaler27197622019-01-23 14:42:11 -06004020 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004021 except(requests.exceptions.Timeout):
4022 return(connectionErrHandler(args.json, "Timeout", None))
4023 except(requests.exceptions.ConnectionError) as err:
4024 return connectionErrHandler(args.json, "ConnectionError", err)
4025 if res.status_code == 404:
4026 return "The specified Interface" + "(" + args.Interface + ")" +\
4027 " doesn't exist"
4028 objDict = json.loads(res.text)
4029 if not objDict['data']:
4030 return "No object found for given address on given Interface"
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004031 for obj in objDict['data']:
Sunitha Harish0baf6372019-07-31 03:59:03 -05004032 try:
4033 if args.address in objDict['data'][obj]['Address']:
4034 url = "https://"+host+obj+"/action/Delete"
4035 try:
4036 res = session.post(url, headers=jsonHeader, json=data,
4037 verify=False, timeout=baseTimeout)
4038 except(requests.exceptions.Timeout):
4039 return(connectionErrHandler(args.json, "Timeout", None))
4040 except(requests.exceptions.ConnectionError) as err:
4041 return connectionErrHandler(args.json, "ConnectionError", err)
4042 return res.text
4043 else:
4044 continue
4045 except KeyError:
Sunitha Harishf9bb2fa2019-09-19 01:48:00 -05004046 continue
4047 return "No object found for address " + args.address + \
4048 " on Interface(" + args.Interface + ")"
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004049
4050
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004051def addVLAN(host, args, session):
4052 """
4053 Called by the network function. Creates VLAN on given interface.
4054
4055 @param host: string, the hostname or IP address of the bmc
4056 @param args: contains additional arguments used by the ldap subcommand
4057 args.json: boolean, if this flag is set to true, the output
4058 will be provided in json format for programmatic consumption
4059 @param session: the active session to use
4060 """
4061
4062 url = "https://" + host+"/xyz/openbmc_project/network/action/VLAN"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004063
Sunitha Harish0baf6372019-07-31 03:59:03 -05004064 data = {"data": [args.Interface,int(args.Identifier)]}
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004065 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06004066 res = session.post(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06004067 timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004068 except(requests.exceptions.Timeout):
4069 return(connectionErrHandler(args.json, "Timeout", None))
4070 except(requests.exceptions.ConnectionError) as err:
4071 return connectionErrHandler(args.json, "ConnectionError", err)
4072 if res.status_code == 400:
Sunitha Harish0baf6372019-07-31 03:59:03 -05004073 return "Adding VLAN to interface" + "(" + args.Interface + ")" +\
4074 " failed"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004075
4076 return res.text
4077
4078
4079def deleteVLAN(host, args, session):
4080 """
4081 Called by the network function. Creates VLAN on given interface.
4082
4083 @param host: string, the hostname or IP address of the bmc
4084 @param args: contains additional arguments used by the ldap subcommand
4085 args.json: boolean, if this flag is set to true, the output
4086 will be provided in json format for programmatic consumption
4087 @param session: the active session to use
4088 """
4089
Sunitha Harish577a5032019-08-08 06:27:40 -05004090 url = "https://" + host+"/xyz/openbmc_project/network/"+args.Interface+"/action/Delete"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004091 data = {"data": []}
4092
4093 try:
Justin Thaler27197622019-01-23 14:42:11 -06004094 res = session.post(url, headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004095 except(requests.exceptions.Timeout):
4096 return(connectionErrHandler(args.json, "Timeout", None))
4097 except(requests.exceptions.ConnectionError) as err:
4098 return connectionErrHandler(args.json, "ConnectionError", err)
4099 if res.status_code == 404:
Sunitha Harish577a5032019-08-08 06:27:40 -05004100 return "The specified VLAN"+"("+args.Interface+")" +" doesn't exist"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004101
4102 return res.text
4103
4104
4105def viewDHCPConfig(host, args, session):
4106 """
4107 Called by the network function. Shows DHCP configured Properties.
4108
4109 @param host: string, the hostname or IP address of the bmc
4110 @param args: contains additional arguments used by the ldap subcommand
4111 args.json: boolean, if this flag is set to true, the output
4112 will be provided in json format for programmatic consumption
4113 @param session: the active session to use
4114 """
4115
4116 url="https://"+host+"/xyz/openbmc_project/network/config/dhcp"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004117
4118 try:
Justin Thaler27197622019-01-23 14:42:11 -06004119 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004120 except(requests.exceptions.Timeout):
4121 return(connectionErrHandler(args.json, "Timeout", None))
4122 except(requests.exceptions.ConnectionError) as err:
4123 return connectionErrHandler(args.json, "ConnectionError", err)
4124
4125 return res.text
4126
4127
4128def configureDHCP(host, args, session):
4129 """
4130 Called by the network function. Configures/updates DHCP Properties.
4131
4132 @param host: string, the hostname or IP address of the bmc
4133 @param args: contains additional arguments used by the ldap subcommand
4134 args.json: boolean, if this flag is set to true, the output
4135 will be provided in json format for programmatic consumption
4136 @param session: the active session to use
4137 """
4138
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004139
4140 try:
4141 url="https://"+host+"/xyz/openbmc_project/network/config/dhcp"
4142 if(args.DNSEnabled == True):
4143 data = '{"data": 1}'
4144 else:
4145 data = '{"data": 0}'
Matt Spinler220c3c42019-01-04 15:09:29 -06004146 res = session.put(url + '/attr/DNSEnabled', headers=jsonHeader,
Justin Thaler27197622019-01-23 14:42:11 -06004147 data=data, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004148 if(args.HostNameEnabled == True):
4149 data = '{"data": 1}'
4150 else:
4151 data = '{"data": 0}'
Matt Spinler220c3c42019-01-04 15:09:29 -06004152 res = session.put(url + '/attr/HostNameEnabled', headers=jsonHeader,
Justin Thaler27197622019-01-23 14:42:11 -06004153 data=data, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004154 if(args.NTPEnabled == True):
4155 data = '{"data": 1}'
4156 else:
4157 data = '{"data": 0}'
Matt Spinler220c3c42019-01-04 15:09:29 -06004158 res = session.put(url + '/attr/NTPEnabled', headers=jsonHeader,
Justin Thaler27197622019-01-23 14:42:11 -06004159 data=data, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004160 if(args.SendHostNameEnabled == True):
4161 data = '{"data": 1}'
4162 else:
4163 data = '{"data": 0}'
Matt Spinler220c3c42019-01-04 15:09:29 -06004164 res = session.put(url + '/attr/SendHostNameEnabled', headers=jsonHeader,
Justin Thaler27197622019-01-23 14:42:11 -06004165 data=data, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004166 except(requests.exceptions.Timeout):
4167 return(connectionErrHandler(args.json, "Timeout", None))
4168 except(requests.exceptions.ConnectionError) as err:
4169 return connectionErrHandler(args.json, "ConnectionError", err)
4170
4171 return res.text
4172
4173
4174def nwReset(host, args, session):
4175
4176 """
4177 Called by the network function. Resets networks setting to factory defaults.
4178
4179 @param host: string, the hostname or IP address of the bmc
4180 @param args: contains additional arguments used by the ldap subcommand
4181 args.json: boolean, if this flag is set to true, the output
4182 will be provided in json format for programmatic consumption
4183 @param session: the active session to use
4184 """
4185
4186 url = "https://"+host+"/xyz/openbmc_project/network/action/Reset"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004187 data = '{"data":[] }'
4188 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06004189 res = session.post(url, headers=jsonHeader, data=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06004190 timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004191
4192 except(requests.exceptions.Timeout):
4193 return(connectionErrHandler(args.json, "Timeout", None))
4194 except(requests.exceptions.ConnectionError) as err:
4195 return connectionErrHandler(args.json, "ConnectionError", err)
4196
4197 return res.text
4198
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004199def getLDAPTypeEnabled(host,session):
4200
4201 """
4202 Called by LDAP related functions to find the LDAP server type that has been enabled.
4203 Returns None if LDAP has not been configured.
4204
4205 @param host: string, the hostname or IP address of the bmc
4206 @param session: the active session to use
4207 """
4208
4209 enabled = False
4210 url = 'https://'+host+'/xyz/openbmc_project/user/ldap/'
4211 for key,value in serverTypeMap.items():
4212 data = {"data": []}
4213 try:
4214 res = session.get(url + value + '/attr/Enabled', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
4215 except(requests.exceptions.Timeout):
4216 print(connectionErrHandler(args.json, "Timeout", None))
4217 return
4218 except(requests.exceptions.ConnectionError) as err:
4219 print(connectionErrHandler(args.json, "ConnectionError", err))
4220 return
4221
4222 enabled = res.json()['data']
4223 if (enabled):
4224 return key
4225
4226def syncRoleMap(host,args,session,fromServerType,toServerType):
4227
4228 """
4229 Called by LDAP related functions to sync the role maps
4230 Returns False if LDAP has not been configured.
4231
4232 @param host: string, the hostname or IP address of the bmc
4233 @param session: the active session to use
4234 @param fromServerType : Server type whose role map has to be copied
4235 @param toServerType : Server type to which role map has to be copied
4236 """
4237
4238 url = "https://"+host+"/xyz/openbmc_project/user/ldap/"
4239
4240 try:
4241 #Note: If the fromServerType has no role map, then
4242 #the toServerType will not have any role map.
4243
4244 #delete the privilege mapping from the toServerType and
4245 #then copy the privilege mapping from fromServerType to
4246 #toServerType.
4247 args.serverType = toServerType
4248 res = deleteAllPrivilegeMapping(host, args, session)
4249
4250 data = {"data": []}
4251 res = session.get(url + serverTypeMap[fromServerType] + '/role_map/enumerate', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
4252 #Previously enabled server type has no role map
4253 if (res.status_code != requests.codes.ok):
4254
4255 #fromServerType has no role map; So, no need to copy
4256 #role map to toServerType.
4257 return
4258
4259 objDict = json.loads(res.text)
4260 dataDict = objDict['data']
4261 for key,value in dataDict.items():
4262 data = {"data": [value["GroupName"], value["Privilege"]]}
4263 res = session.post(url + serverTypeMap[toServerType] + '/action/Create', headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
4264
4265 except(requests.exceptions.Timeout):
4266 return(connectionErrHandler(args.json, "Timeout", None))
4267 except(requests.exceptions.ConnectionError) as err:
4268 return connectionErrHandler(args.json, "ConnectionError", err)
4269 return res.text
4270
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004271
Ratan Guptafeee6372018-10-17 23:25:51 +05304272def createPrivilegeMapping(host, args, session):
4273 """
4274 Called by the ldap function. Creates the group and the privilege mapping.
4275
4276 @param host: string, the hostname or IP address of the bmc
4277 @param args: contains additional arguments used by the ldap subcommand
4278 @param session: the active session to use
4279 @param args.json: boolean, if this flag is set to true, the output
4280 will be provided in json format for programmatic consumption
4281 """
4282
Ratan Guptafeee6372018-10-17 23:25:51 +05304283 try:
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004284 if (isRedfishSupport):
4285 url = 'https://'+host+'/xyz/openbmc_project/user/ldap/'
4286
4287 #To maintain the interface compatibility between op930 and op940, the server type has been made
4288 #optional. If the server type is not specified, then create the role-mapper for the currently
4289 #enabled server type.
4290 serverType = args.serverType
4291 if (serverType is None):
4292 serverType = getLDAPTypeEnabled(host,session)
4293 if (serverType is None):
4294 return("LDAP server has not been enabled. Please specify LDAP serverType to proceed further...")
4295
4296 data = {"data": [args.groupName,args.privilege]}
4297 res = session.post(url + serverTypeMap[serverType] + '/action/Create', headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
4298
4299 else:
4300 url = 'https://'+host+'/xyz/openbmc_project/user/ldap/action/Create'
4301 data = {"data": [args.groupName,args.privilege]}
4302 res = session.post(url, headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
4303
Ratan Guptafeee6372018-10-17 23:25:51 +05304304 except(requests.exceptions.Timeout):
4305 return(connectionErrHandler(args.json, "Timeout", None))
4306 except(requests.exceptions.ConnectionError) as err:
4307 return connectionErrHandler(args.json, "ConnectionError", err)
4308 return res.text
4309
4310def listPrivilegeMapping(host, args, session):
4311 """
4312 Called by the ldap function. Lists the group and the privilege mapping.
4313
4314 @param host: string, the hostname or IP address of the bmc
4315 @param args: contains additional arguments used by the ldap subcommand
4316 @param session: the active session to use
4317 @param args.json: boolean, if this flag is set to true, the output
4318 will be provided in json format for programmatic consumption
4319 """
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004320
4321 if (isRedfishSupport):
4322 serverType = args.serverType
4323 if (serverType is None):
4324 serverType = getLDAPTypeEnabled(host,session)
4325 if (serverType is None):
4326 return("LDAP has not been enabled. Please specify LDAP serverType to proceed further...")
4327
4328 url = 'https://'+host+'/xyz/openbmc_project/user/ldap/'+serverTypeMap[serverType]+'/role_map/enumerate'
4329
4330 else:
4331 url = 'https://'+host+'/xyz/openbmc_project/user/ldap/enumerate'
4332
Ratan Guptafeee6372018-10-17 23:25:51 +05304333 data = {"data": []}
4334
4335 try:
Justin Thaler27197622019-01-23 14:42:11 -06004336 res = session.get(url, headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
Ratan Guptafeee6372018-10-17 23:25:51 +05304337 except(requests.exceptions.Timeout):
4338 return(connectionErrHandler(args.json, "Timeout", None))
4339 except(requests.exceptions.ConnectionError) as err:
4340 return connectionErrHandler(args.json, "ConnectionError", err)
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004341
Ratan Guptafeee6372018-10-17 23:25:51 +05304342 return res.text
4343
4344def deletePrivilegeMapping(host, args, session):
4345 """
4346 Called by the ldap function. Deletes the mapping associated with the group.
4347
4348 @param host: string, the hostname or IP address of the bmc
4349 @param args: contains additional arguments used by the ldap subcommand
4350 @param session: the active session to use
4351 @param args.json: boolean, if this flag is set to true, the output
4352 will be provided in json format for programmatic consumption
4353 """
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004354
4355 ldapNameSpaceObjects = listPrivilegeMapping(host, args, session)
Ratan Guptafeee6372018-10-17 23:25:51 +05304356 ldapNameSpaceObjects = json.loads(ldapNameSpaceObjects)["data"]
4357 path = ''
Ratan Guptafeee6372018-10-17 23:25:51 +05304358 data = {"data": []}
4359
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004360 if (isRedfishSupport):
4361 if (args.serverType is None):
4362 serverType = getLDAPTypeEnabled(host,session)
4363 if (serverType is None):
4364 return("LDAP has not been enabled. Please specify LDAP serverType to proceed further...")
4365 # search for the object having the mapping for the given group
4366 for key,value in ldapNameSpaceObjects.items():
4367 if value['GroupName'] == args.groupName:
4368 path = key
4369 break
4370
4371 if path == '':
4372 return "No privilege mapping found for this group."
4373
4374 # delete the object
4375 url = 'https://'+host+path+'/action/Delete'
4376
4377 else:
4378 # not interested in the config objet
4379 ldapNameSpaceObjects.pop('/xyz/openbmc_project/user/ldap/config', None)
4380
4381 # search for the object having the mapping for the given group
4382 for key,value in ldapNameSpaceObjects.items():
4383 if value['GroupName'] == args.groupName:
4384 path = key
4385 break
4386
4387 if path == '':
4388 return "No privilege mapping found for this group."
4389
4390 # delete the object
4391 url = 'https://'+host+path+'/action/delete'
4392
Ratan Guptafeee6372018-10-17 23:25:51 +05304393 try:
Justin Thaler27197622019-01-23 14:42:11 -06004394 res = session.post(url, headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
Ratan Guptafeee6372018-10-17 23:25:51 +05304395 except(requests.exceptions.Timeout):
4396 return(connectionErrHandler(args.json, "Timeout", None))
4397 except(requests.exceptions.ConnectionError) as err:
4398 return connectionErrHandler(args.json, "ConnectionError", err)
4399 return res.text
Ratan Gupta9166cd22018-10-01 18:09:40 +05304400
Sivas SRR78835272018-11-27 05:27:19 -06004401def deleteAllPrivilegeMapping(host, args, session):
4402 """
4403 Called by the ldap function. Deletes all the privilege mapping and group defined.
4404 @param host: string, the hostname or IP address of the bmc
4405 @param args: contains additional arguments used by the ldap subcommand
4406 @param session: the active session to use
4407 @param args.json: boolean, if this flag is set to true, the output
4408 will be provided in json format for programmatic consumption
4409 """
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004410
Sivas SRR78835272018-11-27 05:27:19 -06004411 ldapNameSpaceObjects = listPrivilegeMapping(host, args, session)
4412 ldapNameSpaceObjects = json.loads(ldapNameSpaceObjects)["data"]
4413 path = ''
Sivas SRR78835272018-11-27 05:27:19 -06004414 data = {"data": []}
4415
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004416 if (isRedfishSupport):
4417 if (args.serverType is None):
4418 serverType = getLDAPTypeEnabled(host,session)
4419 if (serverType is None):
4420 return("LDAP has not been enabled. Please specify LDAP serverType to proceed further...")
4421
4422 else:
4423 # Remove the config object.
4424 ldapNameSpaceObjects.pop('/xyz/openbmc_project/user/ldap/config', None)
4425
Sivas SRR78835272018-11-27 05:27:19 -06004426 try:
4427 # search for GroupName property and delete if it is available.
4428 for path in ldapNameSpaceObjects.keys():
4429 # delete the object
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004430 url = 'https://'+host+path+'/action/Delete'
Justin Thaler27197622019-01-23 14:42:11 -06004431 res = session.post(url, headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004432
Sivas SRR78835272018-11-27 05:27:19 -06004433 except(requests.exceptions.Timeout):
4434 return(connectionErrHandler(args.json, "Timeout", None))
4435 except(requests.exceptions.ConnectionError) as err:
4436 return connectionErrHandler(args.json, "ConnectionError", err)
4437 return res.text
4438
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06004439def viewLDAPConfig(host, args, session):
4440 """
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004441 Called by the ldap function. Prints out active LDAP configuration properties
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06004442
4443 @param host: string, the hostname or IP address of the bmc
4444 @param args: contains additional arguments used by the ldap subcommand
4445 args.json: boolean, if this flag is set to true, the output
4446 will be provided in json format for programmatic consumption
4447 @param session: the active session to use
4448 @return returns LDAP's configured properties.
4449 """
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004450
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06004451 try:
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004452 if (isRedfishSupport):
4453
4454 url = "https://"+host+"/xyz/openbmc_project/user/ldap/"
4455
4456 serverTypeEnabled = getLDAPTypeEnabled(host,session)
4457
4458 if (serverTypeEnabled is not None):
4459 data = {"data": []}
4460 res = session.get(url + serverTypeMap[serverTypeEnabled], headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
4461 else:
4462 return("LDAP server has not been enabled...")
4463
4464 else :
4465 url = "https://"+host+"/xyz/openbmc_project/user/ldap/config"
4466 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
4467
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06004468 except(requests.exceptions.Timeout):
4469 return(connectionErrHandler(args.json, "Timeout", None))
4470 except(requests.exceptions.ConnectionError) as err:
4471 return connectionErrHandler(args.json, "ConnectionError", err)
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06004472 if res.status_code == 404:
4473 return "LDAP server config has not been created"
4474 return res.text
4475
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004476def str2bool(v):
4477 if v.lower() in ('yes', 'true', 't', 'y', '1'):
4478 return True
4479 elif v.lower() in ('no', 'false', 'f', 'n', '0'):
4480 return False
4481 else:
4482 raise argparse.ArgumentTypeError('Boolean value expected.')
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06004483
Matt Spinler7d426c22018-09-24 14:42:07 -05004484def localUsers(host, args, session):
4485 """
4486 Enables and disables local BMC users.
4487
4488 @param host: string, the hostname or IP address of the bmc
4489 @param args: contains additional arguments used by the logging sub command
4490 @param session: the active session to use
4491 """
4492
Matt Spinler7d426c22018-09-24 14:42:07 -05004493 url="https://{hostname}/xyz/openbmc_project/user/enumerate".format(hostname=host)
4494 try:
Justin Thaler27197622019-01-23 14:42:11 -06004495 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Matt Spinler7d426c22018-09-24 14:42:07 -05004496 except(requests.exceptions.Timeout):
4497 return(connectionErrHandler(args.json, "Timeout", None))
4498 usersDict = json.loads(res.text)
4499
4500 if not usersDict['data']:
4501 return "No users found"
4502
4503 output = ""
4504 for user in usersDict['data']:
Matt Spinler015adc22018-10-23 14:30:19 -05004505
4506 # Skip LDAP and another non-local users
4507 if 'UserEnabled' not in usersDict['data'][user]:
4508 continue
4509
Matt Spinler7d426c22018-09-24 14:42:07 -05004510 name = user.split('/')[-1]
4511 url = "https://{hostname}{user}/attr/UserEnabled".format(hostname=host, user=user)
4512
4513 if args.local_users == "queryenabled":
4514 try:
Justin Thaler27197622019-01-23 14:42:11 -06004515 res = session.get(url, headers=jsonHeader,verify=False, timeout=baseTimeout)
Matt Spinler7d426c22018-09-24 14:42:07 -05004516 except(requests.exceptions.Timeout):
4517 return(connectionErrHandler(args.json, "Timeout", None))
4518
4519 result = json.loads(res.text)
4520 output += ("User: {name} Enabled: {result}\n").format(name=name, result=result['data'])
4521
4522 elif args.local_users in ["enableall", "disableall"]:
4523 action = ""
4524 if args.local_users == "enableall":
4525 data = '{"data": true}'
4526 action = "Enabling"
4527 else:
4528 data = '{"data": false}'
4529 action = "Disabling"
4530
4531 output += "{action} {name}\n".format(action=action, name=name)
4532
4533 try:
Justin Thaler27197622019-01-23 14:42:11 -06004534 resp = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Matt Spinler7d426c22018-09-24 14:42:07 -05004535 except(requests.exceptions.Timeout):
4536 return connectionErrHandler(args.json, "Timeout", None)
4537 except(requests.exceptions.ConnectionError) as err:
4538 return connectionErrHandler(args.json, "ConnectionError", err)
4539 else:
4540 return "Invalid local users argument"
4541
4542 return output
4543
Marri Devender Rao2c2a5162018-11-05 08:57:11 -06004544def setPassword(host, args, session):
4545 """
4546 Set local user password
4547 @param host: string, the hostname or IP address of the bmc
4548 @param args: contains additional arguments used by the logging sub
4549 command
4550 @param session: the active session to use
4551 @param args.json: boolean, if this flag is set to true, the output
4552 will be provided in json format for programmatic consumption
4553 @return: Session object
4554 """
Marri Devender Rao2c2a5162018-11-05 08:57:11 -06004555 try:
Sunitha Harishc99faba2019-07-19 06:55:22 -05004556 if(isRedfishSupport):
4557 url = "https://" + host + "/redfish/v1/AccountService/Accounts/"+ \
4558 args.user
4559 data = {"Password":args.password}
4560 res = session.patch(url, headers=jsonHeader, json=data,
4561 verify=False, timeout=baseTimeout)
4562 else:
4563 url = "https://" + host + "/xyz/openbmc_project/user/" + args.user + \
4564 "/action/SetPassword"
4565 res = session.post(url, headers=jsonHeader,
Marri Devender Rao2c2a5162018-11-05 08:57:11 -06004566 json={"data": [args.password]}, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06004567 timeout=baseTimeout)
Marri Devender Rao2c2a5162018-11-05 08:57:11 -06004568 except(requests.exceptions.Timeout):
4569 return(connectionErrHandler(args.json, "Timeout", None))
4570 except(requests.exceptions.ConnectionError) as err:
4571 return connectionErrHandler(args.json, "ConnectionError", err)
4572 except(requests.exceptions.RequestException) as err:
4573 return connectionErrHandler(args.json, "RequestException", err)
Sunitha Harishc99faba2019-07-19 06:55:22 -05004574 return res.status_code
Matthew Barth368e83c2019-02-01 13:48:25 -06004575
4576def getThermalZones(host, args, session):
4577 """
4578 Get the available thermal control zones
4579 @param host: string, the hostname or IP address of the bmc
4580 @param args: contains additional arguments used to get the thermal
4581 control zones
4582 @param session: the active session to use
4583 @return: Session object
4584 """
4585 url = "https://" + host + "/xyz/openbmc_project/control/thermal/enumerate"
4586
4587 try:
4588 res = session.get(url, headers=jsonHeader, verify=False, timeout=30)
4589 except(requests.exceptions.Timeout):
4590 return(connectionErrHandler(args.json, "Timeout", None))
4591 except(requests.exceptions.ConnectionError) as err:
4592 return connectionErrHandler(args.json, "ConnectionError", err)
4593 except(requests.exceptions.RequestException) as err:
4594 return connectionErrHandler(args.json, "RequestException", err)
4595
4596 if (res.status_code == 404):
Matthew Barth0939e822019-09-27 15:47:50 -05004597 return "No thermal control zones found"
Matthew Barth368e83c2019-02-01 13:48:25 -06004598
4599 zonesDict = json.loads(res.text)
4600 if not zonesDict['data']:
4601 return "No thermal control zones found"
4602 for zone in zonesDict['data']:
4603 z = ",".join(str(zone.split('/')[-1]) for zone in zonesDict['data'])
4604
4605 return "Zones: [ " + z + " ]"
4606
4607
4608def getThermalMode(host, args, session):
4609 """
4610 Get thermal control mode
4611 @param host: string, the hostname or IP address of the bmc
4612 @param args: contains additional arguments used to get the thermal
4613 control mode
4614 @param session: the active session to use
4615 @param args.zone: the zone to get the mode on
4616 @return: Session object
4617 """
4618 url = "https://" + host + "/xyz/openbmc_project/control/thermal/" + \
4619 args.zone
4620
4621 try:
4622 res = session.get(url, headers=jsonHeader, verify=False, timeout=30)
4623 except(requests.exceptions.Timeout):
4624 return(connectionErrHandler(args.json, "Timeout", None))
4625 except(requests.exceptions.ConnectionError) as err:
4626 return connectionErrHandler(args.json, "ConnectionError", err)
4627 except(requests.exceptions.RequestException) as err:
4628 return connectionErrHandler(args.json, "RequestException", err)
4629
4630 if (res.status_code == 404):
Matthew Barth0939e822019-09-27 15:47:50 -05004631 return "Thermal control zone(" + args.zone + ") not found"
Matthew Barth368e83c2019-02-01 13:48:25 -06004632
4633 propsDict = json.loads(res.text)
4634 if not propsDict['data']:
4635 return "No thermal control properties found on zone(" + args.zone + ")"
4636 curMode = "Current"
4637 supModes = "Supported"
4638 result = "\n"
4639 for prop in propsDict['data']:
4640 if (prop.casefold() == curMode.casefold()):
4641 result += curMode + " Mode: " + propsDict['data'][curMode] + "\n"
4642 if (prop.casefold() == supModes.casefold()):
4643 s = ", ".join(str(sup) for sup in propsDict['data'][supModes])
4644 result += supModes + " Modes: [ " + s + " ]\n"
4645
4646 return result
4647
4648def setThermalMode(host, args, session):
4649 """
4650 Set thermal control mode
4651 @param host: string, the hostname or IP address of the bmc
4652 @param args: contains additional arguments used for setting the thermal
4653 control mode
4654 @param session: the active session to use
4655 @param args.zone: the zone to set the mode on
4656 @param args.mode: the mode to enable
4657 @return: Session object
4658 """
4659 url = "https://" + host + "/xyz/openbmc_project/control/thermal/" + \
4660 args.zone + "/attr/Current"
4661
4662 # Check args.mode against supported modes using `getThermalMode` output
4663 modes = getThermalMode(host, args, session)
4664 modes = os.linesep.join([m for m in modes.splitlines() if m])
4665 modes = modes.replace("\n", ";").strip()
4666 modesDict = dict(m.split(': ') for m in modes.split(';'))
4667 sModes = ''.join(s for s in modesDict['Supported Modes'] if s not in '[ ]')
4668 if args.mode.casefold() not in \
4669 (m.casefold() for m in sModes.split(',')) or not args.mode:
4670 result = ("Unsupported mode('" + args.mode + "') given, " +
4671 "select a supported mode: \n" +
4672 getThermalMode(host, args, session))
4673 return result
4674
4675 data = '{"data":"' + args.mode + '"}'
4676 try:
4677 res = session.get(url, headers=jsonHeader, verify=False, timeout=30)
4678 except(requests.exceptions.Timeout):
4679 return(connectionErrHandler(args.json, "Timeout", None))
4680 except(requests.exceptions.ConnectionError) as err:
4681 return connectionErrHandler(args.json, "ConnectionError", err)
4682 except(requests.exceptions.RequestException) as err:
4683 return connectionErrHandler(args.json, "RequestException", err)
4684
4685 if (data and res.status_code != 404):
4686 try:
4687 res = session.put(url, headers=jsonHeader,
4688 data=data, verify=False,
4689 timeout=30)
4690 except(requests.exceptions.Timeout):
4691 return(connectionErrHandler(args.json, "Timeout", None))
4692 except(requests.exceptions.ConnectionError) as err:
4693 return connectionErrHandler(args.json, "ConnectionError", err)
4694 except(requests.exceptions.RequestException) as err:
4695 return connectionErrHandler(args.json, "RequestException", err)
4696
4697 if res.status_code == 403:
4698 return "The specified thermal control zone(" + args.zone + ")" + \
4699 " does not exist"
4700
4701 return res.text
4702 else:
4703 return "Setting thermal control mode(" + args.mode + ")" + \
Matthew Barth0939e822019-09-27 15:47:50 -05004704 " not supported or operation not available"
Matthew Barth368e83c2019-02-01 13:48:25 -06004705
4706
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004707def createCommandParser():
Justin Thalere412dc22018-01-12 16:28:24 -06004708 """
4709 creates the parser for the command line along with help for each command and subcommand
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004710
Justin Thalere412dc22018-01-12 16:28:24 -06004711 @return: returns the parser for the command line
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004712 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004713 parser = argparse.ArgumentParser(description='Process arguments')
Justin Thalere412dc22018-01-12 16:28:24 -06004714 parser.add_argument("-H", "--host", help='A hostname or IP for the BMC')
4715 parser.add_argument("-U", "--user", help='The username to login with')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004716 group = parser.add_mutually_exclusive_group()
4717 group.add_argument("-A", "--askpw", action='store_true', help='prompt for password')
4718 group.add_argument("-P", "--PW", help='Provide the password in-line')
Joseph Reynoldsa2d54c52019-06-11 22:02:57 -05004719 group.add_argument("-E", "--PWenvvar", action='store_true', help='Get password from envvar OPENBMCTOOL_PASSWORD')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004720 parser.add_argument('-j', '--json', action='store_true', help='output json data only')
4721 parser.add_argument('-t', '--policyTableLoc', help='The location of the policy table to parse alerts')
4722 parser.add_argument('-c', '--CerFormat', action='store_true', help=argparse.SUPPRESS)
4723 parser.add_argument('-T', '--procTime', action='store_true', help= argparse.SUPPRESS)
Justin Thalere412dc22018-01-12 16:28:24 -06004724 parser.add_argument('-V', '--version', action='store_true', help='Display the version number of the openbmctool')
4725 subparsers = parser.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004726
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004727 #fru command
4728 parser_inv = subparsers.add_parser("fru", help='Work with platform inventory')
Justin Thalere412dc22018-01-12 16:28:24 -06004729 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 -05004730 inv_subparser.required = True
4731 #fru print
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004732 inv_print = inv_subparser.add_parser("print", help="prints out a list of all FRUs")
4733 inv_print.set_defaults(func=fruPrint)
4734 #fru list [0....n]
4735 inv_list = inv_subparser.add_parser("list", help="print out details on selected FRUs. Specifying no items will list the entire inventory")
4736 inv_list.add_argument('items', nargs='?', help="print out details on selected FRUs. Specifying no items will list the entire inventory")
4737 inv_list.set_defaults(func=fruList)
4738 #fru status
4739 inv_status = inv_subparser.add_parser("status", help="prints out the status of all FRUs")
Justin Thalere412dc22018-01-12 16:28:24 -06004740 inv_status.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004741 inv_status.set_defaults(func=fruStatus)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004742
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004743 #sensors command
4744 parser_sens = subparsers.add_parser("sensors", help="Work with platform sensors")
Justin Thalere412dc22018-01-12 16:28:24 -06004745 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 -05004746 sens_subparser.required = True
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004747 #sensor print
4748 sens_print= sens_subparser.add_parser('print', help="prints out a list of all Sensors.")
4749 sens_print.set_defaults(func=sensor)
4750 #sensor list[0...n]
4751 sens_list=sens_subparser.add_parser("list", help="Lists all Sensors in the platform. Specify a sensor for full details. ")
4752 sens_list.add_argument("sensNum", nargs='?', help="The Sensor number to get full details on" )
4753 sens_list.set_defaults(func=sensor)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004754
Matthew Barth368e83c2019-02-01 13:48:25 -06004755 #thermal control commands
4756 parser_therm = subparsers.add_parser("thermal", help="Work with thermal control parameters")
4757 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')
4758 #thermal control zones
4759 parser_thermZones = therm_subparser.add_parser("zones", help="Get a list of available thermal control zones")
4760 parser_thermZones.set_defaults(func=getThermalZones)
4761 #thermal control modes
4762 parser_thermMode = therm_subparser.add_parser("modes", help="Work with thermal control modes")
4763 thermMode_sub = parser_thermMode.add_subparsers(title='subactions', description='Work with thermal control modes', help="Work with thermal control modes")
4764 #get thermal control mode
4765 parser_getThermMode = thermMode_sub.add_parser("get", help="Get current and supported thermal control modes")
4766 parser_getThermMode.add_argument('-z', '--zone', required=True, help='Thermal zone to work with')
4767 parser_getThermMode.set_defaults(func=getThermalMode)
4768 #set thermal control mode
4769 parser_setThermMode = thermMode_sub.add_parser("set", help="Set the thermal control mode")
4770 parser_setThermMode.add_argument('-z', '--zone', required=True, help='Thermal zone to work with')
4771 parser_setThermMode.add_argument('-m', '--mode', required=True, help='The supported thermal control mode')
4772 parser_setThermMode.set_defaults(func=setThermalMode)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004773
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004774 #sel command
4775 parser_sel = subparsers.add_parser("sel", help="Work with platform alerts")
Justin Thalere412dc22018-01-12 16:28:24 -06004776 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 -05004777 sel_subparser.required = True
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004778 #sel print
4779 sel_print = sel_subparser.add_parser("print", help="prints out a list of all sels in a condensed list")
4780 sel_print.add_argument('-d', '--devdebug', action='store_true', help=argparse.SUPPRESS)
4781 sel_print.add_argument('-v', '--verbose', action='store_true', help="Changes the output to being very verbose")
4782 sel_print.add_argument('-f', '--fileloc', help='Parse a file instead of the BMC output')
4783 sel_print.set_defaults(func=selPrint)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004784
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004785 #sel list
4786 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")
4787 sel_list.add_argument("selNum", nargs='?', type=int, help="The SEL entry to get details on")
4788 sel_list.set_defaults(func=selList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004789
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004790 sel_get = sel_subparser.add_parser("get", help="Gets the verbose details of a specified SEL entry")
4791 sel_get.add_argument('selNum', type=int, help="the number of the SEL entry to get")
4792 sel_get.set_defaults(func=selList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004793
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004794 sel_clear = sel_subparser.add_parser("clear", help="Clears all entries from the SEL")
4795 sel_clear.set_defaults(func=selClear)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004796
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004797 sel_setResolved = sel_subparser.add_parser("resolve", help="Sets the sel entry to resolved")
Justin Thalere412dc22018-01-12 16:28:24 -06004798 sel_setResolved.add_argument('-n', '--selNum', type=int, help="the number of the SEL entry to resolve")
4799 sel_ResolveAll_sub = sel_setResolved.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
4800 sel_ResolveAll = sel_ResolveAll_sub.add_parser('all', help='Resolve all SEL entries')
4801 sel_ResolveAll.set_defaults(func=selResolveAll)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004802 sel_setResolved.set_defaults(func=selSetResolved)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004803
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004804 parser_chassis = subparsers.add_parser("chassis", help="Work with chassis power and status")
Justin Thalere412dc22018-01-12 16:28:24 -06004805 chas_sub = parser_chassis.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004806
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004807 parser_chassis.add_argument('status', action='store_true', help='Returns the current status of the platform')
4808 parser_chassis.set_defaults(func=chassis)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004809
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004810 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 -06004811 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 -06004812 parser_chasPower.set_defaults(func=chassisPower)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004813
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004814 #control the chassis identify led
4815 parser_chasIdent = chas_sub.add_parser("identify", help="Control the chassis identify led")
4816 parser_chasIdent.add_argument('identcmd', choices=['on', 'off', 'status'], help='The control option for the led: on, off, blink, status')
4817 parser_chasIdent.set_defaults(func=chassisIdent)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004818
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004819 #collect service data
4820 parser_servData = subparsers.add_parser("collect_service_data", help="Collect all bmc data needed for service")
4821 parser_servData.add_argument('-d', '--devdebug', action='store_true', help=argparse.SUPPRESS)
4822 parser_servData.set_defaults(func=collectServiceData)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004823
Justin Thalere412dc22018-01-12 16:28:24 -06004824 #system quick health check
4825 parser_healthChk = subparsers.add_parser("health_check", help="Work with platform sensors")
4826 parser_healthChk.set_defaults(func=healthCheck)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004827
Asmitha Karunanithi4e178112020-10-01 08:18:21 -05004828 #tasks
4829 parser_tasks = subparsers.add_parser("task", help="Work with tasks")
4830 tasks_sub = parser_tasks.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
4831 tasks_sub.required = True
4832 get_Task = tasks_sub.add_parser('get', help="Get on Task Monitor URL")
4833 get_Task.add_argument("-u", "--taskURI", help="Task Monitor URI")
4834 get_Task.set_defaults(func=getTask)
4835
Ravi Tejad8be0b42020-03-18 14:31:46 -05004836 #work with dumps
4837 parser_bmcdump = subparsers.add_parser("dump", help="Work with dumps")
4838 parser_bmcdump.add_argument("-t", "--dumpType", default='bmc', choices=['bmc','SystemDump'],help="Type of dump")
Justin Thalere412dc22018-01-12 16:28:24 -06004839 bmcDump_sub = parser_bmcdump.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Justin Thaler53bf2f12018-07-16 14:05:32 -05004840 bmcDump_sub.required = True
Ravi Tejad8be0b42020-03-18 14:31:46 -05004841 dump_Create = bmcDump_sub.add_parser('create', help="Create a dump of given type")
4842 dump_Create.set_defaults(func=dumpCreate)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004843
Ravi Tejad8be0b42020-03-18 14:31:46 -05004844 dump_list = bmcDump_sub.add_parser('list', help="list all dumps")
4845 dump_list.set_defaults(func=dumpList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004846
Ravi Tejad8be0b42020-03-18 14:31:46 -05004847 parserdumpdelete = bmcDump_sub.add_parser('delete', help="Delete dump")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004848 parserdumpdelete.add_argument("-n", "--dumpNum", nargs='*', type=int, help="The Dump entry to delete")
Ravi Tejad8be0b42020-03-18 14:31:46 -05004849 parserdumpdelete.set_defaults(func=dumpDelete)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004850
Justin Thalere412dc22018-01-12 16:28:24 -06004851 bmcDumpDelsub = parserdumpdelete.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Ravi Tejad8be0b42020-03-18 14:31:46 -05004852 deleteAllDumps = bmcDumpDelsub.add_parser('all', help='Delete all dumps')
4853 deleteAllDumps.set_defaults(func=dumpDeleteAll)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004854
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004855 parser_dumpretrieve = bmcDump_sub.add_parser('retrieve', help='Retrieve a dump file')
Ravi Tejad8be0b42020-03-18 14:31:46 -05004856 parser_dumpretrieve.add_argument("-n,", "--dumpNum", help="The Dump entry to retrieve")
4857 parser_dumpretrieve.add_argument("-s", "--dumpSaveLoc", help="The location to save the bmc dump file or file path for system dump")
4858 parser_dumpretrieve.set_defaults(func=dumpRetrieve)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004859
Justin Thaler22b1bb52018-03-15 13:31:32 -05004860 #bmc command for reseting the bmc
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004861 parser_bmc = subparsers.add_parser('bmc', help="Work with the bmc")
Justin Thalere412dc22018-01-12 16:28:24 -06004862 bmc_sub = parser_bmc.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004863 parser_BMCReset = bmc_sub.add_parser('reset', help='Reset the bmc' )
4864 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 -06004865 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.")
4866 parser_bmc.set_defaults(func=bmc)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004867
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004868 #add alias to the bmc command
4869 parser_mc = subparsers.add_parser('mc', help="Work with the management controller")
Justin Thalere412dc22018-01-12 16:28:24 -06004870 mc_sub = parser_mc.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004871 parser_MCReset = mc_sub.add_parser('reset', help='Reset the bmc' )
4872 parser_MCReset.add_argument('type', choices=['warm','cold'], help="Reboot the BMC")
4873 #parser_MCReset.add_argument('cold', action='store_true', help="Reboot the BMC and CLEAR the configuration")
4874 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 -06004875 parser_MCReset.set_defaults(func=bmcReset)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004876 parser_mc.set_defaults(func=bmc)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004877
Justin Thalere412dc22018-01-12 16:28:24 -06004878 #gard clear
4879 parser_gc = subparsers.add_parser("gardclear", help="Used to clear gard records")
4880 parser_gc.set_defaults(func=gardClear)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004881
Justin Thalere412dc22018-01-12 16:28:24 -06004882 #firmware_flash
4883 parser_fw = subparsers.add_parser("firmware", help="Work with the system firmware")
4884 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 -05004885 fwflash_subproc.required = True
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004886
Justin Thalere412dc22018-01-12 16:28:24 -06004887 fwflash = fwflash_subproc.add_parser('flash', help="Flash the system firmware")
4888 fwflash.add_argument('type', choices=['bmc', 'pnor'], help="image type to flash")
4889 fwflash.add_argument('-f', '--fileloc', required=True, help="The absolute path to the firmware image")
4890 fwflash.set_defaults(func=fwFlash)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004891
Justin Thaler22b1bb52018-03-15 13:31:32 -05004892 fwActivate = fwflash_subproc.add_parser('activate', help="Activate existing image on the bmc")
Justin Thalere412dc22018-01-12 16:28:24 -06004893 fwActivate.add_argument('imageID', help="The image ID to activate from the firmware list. Ex: 63c95399")
4894 fwActivate.set_defaults(func=activateFWImage)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004895
Justin Thaler22b1bb52018-03-15 13:31:32 -05004896 fwActivateStatus = fwflash_subproc.add_parser('activation_status', help="Check Status of activations")
4897 fwActivateStatus.set_defaults(func=activateStatus)
4898
Justin Thaler3d71d402018-07-24 14:35:39 -05004899 fwList = fwflash_subproc.add_parser('list', help="List all of the installed firmware")
4900 fwList.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
4901 fwList.set_defaults(func=firmwareList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004902
Justin Thaler3d71d402018-07-24 14:35:39 -05004903 fwprint = fwflash_subproc.add_parser('print', help="List all of the installed firmware")
4904 fwprint.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
4905 fwprint.set_defaults(func=firmwareList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004906
Adriana Kobylak5af2fad2018-11-08 12:33:43 -06004907 fwDelete = fwflash_subproc.add_parser('delete', help="Delete an existing firmware version")
4908 fwDelete.add_argument('versionID', help="The version ID to delete from the firmware list. Ex: 63c95399")
4909 fwDelete.set_defaults(func=deleteFWVersion)
4910
Klaus Heinrich Kiwi0b5b2042020-12-03 14:20:27 -03004911 fwDeleteAll = fwflash_subproc.add_parser('deleteAll', help="Delete ALL firmware versions")
4912 fwDeleteAll.set_defaults(func=deleteFWAll)
4913
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05004914 #logging
4915 parser_logging = subparsers.add_parser("logging", help="logging controls")
4916 logging_sub = parser_logging.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004917
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05004918 #turn rest api logging on/off
4919 parser_rest_logging = logging_sub.add_parser("rest_api", help="turn rest api logging on/off")
4920 parser_rest_logging.add_argument('rest_logging', choices=['on', 'off'], help='The control option for rest logging: on, off')
4921 parser_rest_logging.set_defaults(func=restLogging)
Deepak Kodihalli02d53282018-09-18 06:53:31 -05004922
4923 #remote logging
4924 parser_remote_logging = logging_sub.add_parser("remote_logging", help="Remote logging (rsyslog) commands")
4925 parser_remote_logging.add_argument('remote_logging', choices=['view', 'disable'], help='Remote logging (rsyslog) commands')
4926 parser_remote_logging.set_defaults(func=remoteLogging)
4927
4928 #configure remote logging
4929 parser_remote_logging_config = logging_sub.add_parser("remote_logging_config", help="Configure remote logging (rsyslog)")
4930 parser_remote_logging_config.add_argument("-a", "--address", required=True, help="Set IP address of rsyslog server")
4931 parser_remote_logging_config.add_argument("-p", "--port", required=True, type=int, help="Set Port of rsyslog server")
4932 parser_remote_logging_config.set_defaults(func=remoteLoggingConfig)
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05004933
4934 #certificate management
4935 parser_cert = subparsers.add_parser("certificate", help="Certificate management")
4936 certMgmt_subproc = parser_cert.add_subparsers(title='subcommands', description='valid certificate commands', help='sub-command help', dest='command')
4937
4938 certUpdate = certMgmt_subproc.add_parser('update', help="Update the certificate")
4939 certUpdate.add_argument('type', choices=['server', 'client', 'authority'], help="certificate type to update")
4940 certUpdate.add_argument('service', choices=['https', 'ldap'], help="Service to update")
4941 certUpdate.add_argument('-f', '--fileloc', required=True, help="The absolute path to the certificate file")
4942 certUpdate.set_defaults(func=certificateUpdate)
4943
4944 certDelete = certMgmt_subproc.add_parser('delete', help="Delete the certificate")
4945 certDelete.add_argument('type', choices=['server', 'client', 'authority'], help="certificate type to delete")
4946 certDelete.add_argument('service', choices=['https', 'ldap'], help="Service to delete the certificate")
4947 certDelete.set_defaults(func=certificateDelete)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004948
Marri Devender Raodfe81ad2019-07-01 05:38:09 -05004949 certReplace = certMgmt_subproc.add_parser('replace',
4950 help="Replace the certificate")
4951 certReplace.add_argument('type', choices=['server', 'client', 'authority'],
4952 help="certificate type to replace")
4953 certReplace.add_argument('service', choices=['https', 'ldap'],
4954 help="Service to replace the certificate")
4955 certReplace.add_argument('-f', '--fileloc', required=True,
4956 help="The absolute path to the certificate file")
4957 certReplace.set_defaults(func=certificateReplace)
4958
Marri Devender Rao34646402019-07-01 05:46:03 -05004959 certDisplay = certMgmt_subproc.add_parser('display',
4960 help="Print the certificate")
4961 certDisplay.add_argument('type', choices=['server', 'client', 'authority'],
4962 help="certificate type to display")
4963 certDisplay.set_defaults(func=certificateDisplay)
4964
Marri Devender Raoa208ff82019-07-01 05:51:27 -05004965 certList = certMgmt_subproc.add_parser('list',
4966 help="Certificate list")
4967 certList.set_defaults(func=certificateList)
4968
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05004969 certGenerateCSR = certMgmt_subproc.add_parser('generatecsr', help="Generate CSR")
4970 certGenerateCSR.add_argument('type', choices=['server', 'client', 'authority'],
4971 help="Generate CSR")
4972 certGenerateCSR.add_argument('city',
4973 help="The city or locality of the organization making the request")
4974 certGenerateCSR.add_argument('commonName',
4975 help="The fully qualified domain name of the component that is being secured.")
4976 certGenerateCSR.add_argument('country',
4977 help="The country of the organization making the request")
4978 certGenerateCSR.add_argument('organization',
4979 help="The name of the organization making the request.")
4980 certGenerateCSR.add_argument('organizationUnit',
4981 help="The name of the unit or division of the organization making the request.")
4982 certGenerateCSR.add_argument('state',
4983 help="The state, province, or region of the organization making the request.")
4984 certGenerateCSR.add_argument('keyPairAlgorithm', choices=['RSA', 'EC'],
4985 help="The type of key pair for use with signing algorithms.")
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05004986 certGenerateCSR.add_argument('keyCurveId',
4987 help="The curve ID to be used with the key, if needed based on the value of the 'KeyPairAlgorithm' parameter.")
4988 certGenerateCSR.add_argument('contactPerson',
4989 help="The name of the user making the request")
4990 certGenerateCSR.add_argument('email',
4991 help="The email address of the contact within the organization")
4992 certGenerateCSR.add_argument('alternativeNames',
4993 help="Additional hostnames of the component that is being secured")
4994 certGenerateCSR.add_argument('givenname',
4995 help="The given name of the user making the request")
4996 certGenerateCSR.add_argument('surname',
4997 help="The surname of the user making the request")
4998 certGenerateCSR.add_argument('unstructuredname',
4999 help="he unstructured name of the subject")
5000 certGenerateCSR.add_argument('initials',
5001 help="The initials of the user making the request")
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05005002 certGenerateCSR.set_defaults(func=certificateGenerateCSR)
5003
Matt Spinler7d426c22018-09-24 14:42:07 -05005004 # local users
5005 parser_users = subparsers.add_parser("local_users", help="Work with local users")
5006 parser_users.add_argument('local_users', choices=['disableall','enableall', 'queryenabled'], help="Disable, enable or query local user accounts")
5007 parser_users.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
5008 parser_users.set_defaults(func=localUsers)
5009
Ratan Gupta9166cd22018-10-01 18:09:40 +05305010 #LDAP
5011 parser_ldap = subparsers.add_parser("ldap", help="LDAP controls")
5012 ldap_sub = parser_ldap.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
5013
5014 #configure and enable LDAP
5015 parser_ldap_config = ldap_sub.add_parser("enable", help="Configure and enables the LDAP")
5016 parser_ldap_config.add_argument("-a", "--uri", required=True, help="Set LDAP server URI")
5017 parser_ldap_config.add_argument("-B", "--bindDN", required=True, help="Set the bind DN of the LDAP server")
5018 parser_ldap_config.add_argument("-b", "--baseDN", required=True, help="Set the base DN of the LDAP server")
5019 parser_ldap_config.add_argument("-p", "--bindPassword", required=True, help="Set the bind password of the LDAP server")
5020 parser_ldap_config.add_argument("-S", "--scope", choices=['sub','one', 'base'],
5021 help='Specifies the search scope:subtree, one level or base object.')
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05005022 parser_ldap_config.add_argument("-t", "--serverType", required=True, choices=['ActiveDirectory','OpenLDAP'],
Ratan Gupta9166cd22018-10-01 18:09:40 +05305023 help='Specifies the configured server is ActiveDirectory(AD) or OpenLdap')
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05005024 parser_ldap_config.add_argument("-g","--groupAttrName", required=False, default='', help="Group Attribute Name")
5025 parser_ldap_config.add_argument("-u","--userAttrName", required=False, default='', help="User Attribute Name")
5026 parser_ldap_config.set_defaults(func=enableLDAPConfig)
Ratan Gupta9166cd22018-10-01 18:09:40 +05305027
5028 # disable LDAP
5029 parser_disable_ldap = ldap_sub.add_parser("disable", help="disables the LDAP")
5030 parser_disable_ldap.set_defaults(func=disableLDAP)
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06005031 # view-config
5032 parser_ldap_config = \
5033 ldap_sub.add_parser("view-config", help="prints out a list of all \
5034 LDAPS's configured properties")
5035 parser_ldap_config.set_defaults(func=viewLDAPConfig)
Ratan Gupta9166cd22018-10-01 18:09:40 +05305036
Ratan Guptafeee6372018-10-17 23:25:51 +05305037 #create group privilege mapping
5038 parser_ldap_mapper = ldap_sub.add_parser("privilege-mapper", help="LDAP group privilege controls")
5039 parser_ldap_mapper_sub = parser_ldap_mapper.add_subparsers(title='subcommands', description='valid subcommands',
5040 help="sub-command help", dest='command')
5041
5042 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 -05005043 parser_ldap_mapper_create.add_argument("-t", "--serverType", choices=['ActiveDirectory','OpenLDAP'],
5044 help='Specifies the configured server is ActiveDirectory(AD) or OpenLdap')
Ratan Guptafeee6372018-10-17 23:25:51 +05305045 parser_ldap_mapper_create.add_argument("-g","--groupName",required=True,help="Group Name")
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05005046 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 +05305047 parser_ldap_mapper_create.set_defaults(func=createPrivilegeMapping)
5048
5049 #list group privilege mapping
5050 parser_ldap_mapper_list = parser_ldap_mapper_sub.add_parser("list",help="List privilege mapping")
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05005051 parser_ldap_mapper_list.add_argument("-t", "--serverType", choices=['ActiveDirectory','OpenLDAP'],
5052 help='Specifies the configured server is ActiveDirectory(AD) or OpenLdap')
Ratan Guptafeee6372018-10-17 23:25:51 +05305053 parser_ldap_mapper_list.set_defaults(func=listPrivilegeMapping)
5054
5055 #delete group privilege mapping
5056 parser_ldap_mapper_delete = parser_ldap_mapper_sub.add_parser("delete",help="Delete privilege mapping")
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05005057 parser_ldap_mapper_delete.add_argument("-t", "--serverType", choices=['ActiveDirectory','OpenLDAP'],
5058 help='Specifies the configured server is ActiveDirectory(AD) or OpenLdap')
Ratan Guptafeee6372018-10-17 23:25:51 +05305059 parser_ldap_mapper_delete.add_argument("-g","--groupName",required=True,help="Group Name")
5060 parser_ldap_mapper_delete.set_defaults(func=deletePrivilegeMapping)
5061
Sivas SRR78835272018-11-27 05:27:19 -06005062 #deleteAll group privilege mapping
5063 parser_ldap_mapper_delete = parser_ldap_mapper_sub.add_parser("purge",help="Delete All privilege mapping")
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05005064 parser_ldap_mapper_delete.add_argument("-t", "--serverType", choices=['ActiveDirectory','OpenLDAP'],
5065 help='Specifies the configured server is ActiveDirectory(AD) or OpenLdap')
Sivas SRR78835272018-11-27 05:27:19 -06005066 parser_ldap_mapper_delete.set_defaults(func=deleteAllPrivilegeMapping)
5067
Marri Devender Rao2c2a5162018-11-05 08:57:11 -06005068 # set local user password
5069 parser_set_password = subparsers.add_parser("set_password",
5070 help="Set password of local user")
5071 parser_set_password.add_argument( "-p", "--password", required=True,
5072 help="Password of local user")
5073 parser_set_password.set_defaults(func=setPassword)
5074
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06005075 # network
5076 parser_nw = subparsers.add_parser("network", help="network controls")
5077 nw_sub = parser_nw.add_subparsers(title='subcommands',
5078 description='valid subcommands',
5079 help="sub-command help",
5080 dest='command')
5081
5082 # enable DHCP
5083 parser_enable_dhcp = nw_sub.add_parser("enableDHCP",
5084 help="enables the DHCP on given "
5085 "Interface")
5086 parser_enable_dhcp.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06005087 help="Name of the ethernet interface(it can"
5088 "be obtained by the "
5089 "command:network view-config)"
5090 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06005091 parser_enable_dhcp.set_defaults(func=enableDHCP)
5092
5093 # disable DHCP
5094 parser_disable_dhcp = nw_sub.add_parser("disableDHCP",
5095 help="disables the DHCP on given "
5096 "Interface")
5097 parser_disable_dhcp.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06005098 help="Name of the ethernet interface(it can"
5099 "be obtained by the "
5100 "command:network view-config)"
5101 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06005102 parser_disable_dhcp.set_defaults(func=disableDHCP)
5103
5104 # get HostName
5105 parser_gethostname = nw_sub.add_parser("getHostName",
5106 help="prints out HostName")
5107 parser_gethostname.set_defaults(func=getHostname)
5108
5109 # set HostName
5110 parser_sethostname = nw_sub.add_parser("setHostName", help="sets HostName")
5111 parser_sethostname.add_argument("-H", "--HostName", required=True,
5112 help="A HostName for the BMC")
5113 parser_sethostname.set_defaults(func=setHostname)
5114
5115 # get domainname
5116 parser_getdomainname = nw_sub.add_parser("getDomainName",
5117 help="prints out DomainName of "
5118 "given Interface")
5119 parser_getdomainname.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06005120 help="Name of the ethernet interface(it "
5121 "can be obtained by the "
5122 "command:network view-config)"
5123 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06005124 parser_getdomainname.set_defaults(func=getDomainName)
5125
5126 # set domainname
5127 parser_setdomainname = nw_sub.add_parser("setDomainName",
5128 help="sets DomainName of given "
5129 "Interface")
5130 parser_setdomainname.add_argument("-D", "--DomainName", required=True,
5131 help="Ex: DomainName=Domain1,Domain2,...")
5132 parser_setdomainname.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06005133 help="Name of the ethernet interface(it "
5134 "can be obtained by the "
5135 "command:network view-config)"
5136 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06005137 parser_setdomainname.set_defaults(func=setDomainName)
5138
5139 # get MACAddress
5140 parser_getmacaddress = nw_sub.add_parser("getMACAddress",
5141 help="prints out MACAddress the "
5142 "given Interface")
5143 parser_getmacaddress.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06005144 help="Name of the ethernet interface(it "
5145 "can be obtained by the "
5146 "command:network view-config)"
5147 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06005148 parser_getmacaddress.set_defaults(func=getMACAddress)
5149
5150 # set MACAddress
5151 parser_setmacaddress = nw_sub.add_parser("setMACAddress",
5152 help="sets MACAddress")
5153 parser_setmacaddress.add_argument("-MA", "--MACAddress", required=True,
5154 help="A MACAddress for the given "
5155 "Interface")
5156 parser_setmacaddress.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06005157 help="Name of the ethernet interface(it can"
5158 "be obtained by the "
5159 "command:network view-config)"
5160 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06005161 parser_setmacaddress.set_defaults(func=setMACAddress)
5162
5163 # get DefaultGW
5164 parser_getdefaultgw = nw_sub.add_parser("getDefaultGW",
5165 help="prints out DefaultGateway "
5166 "the BMC")
5167 parser_getdefaultgw.set_defaults(func=getDefaultGateway)
5168
5169 # set DefaultGW
5170 parser_setdefaultgw = nw_sub.add_parser("setDefaultGW",
5171 help="sets DefaultGW")
5172 parser_setdefaultgw.add_argument("-GW", "--DefaultGW", required=True,
5173 help="A DefaultGateway for the BMC")
5174 parser_setdefaultgw.set_defaults(func=setDefaultGateway)
5175
5176 # view network Config
5177 parser_ldap_config = nw_sub.add_parser("view-config", help="prints out a "
5178 "list of all network's configured "
5179 "properties")
5180 parser_ldap_config.set_defaults(func=viewNWConfig)
5181
5182 # get DNS
5183 parser_getDNS = nw_sub.add_parser("getDNS",
5184 help="prints out DNS servers on the "
5185 "given interface")
5186 parser_getDNS.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06005187 help="Name of the ethernet interface(it can"
5188 "be obtained by the "
5189 "command:network view-config)"
5190 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06005191 parser_getDNS.set_defaults(func=getDNS)
5192
5193 # set DNS
5194 parser_setDNS = nw_sub.add_parser("setDNS",
5195 help="sets DNS servers on the given "
5196 "interface")
5197 parser_setDNS.add_argument("-d", "--DNSServers", required=True,
5198 help="Ex: DNSSERVERS=DNS1,DNS2,...")
5199 parser_setDNS.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06005200 help="Name of the ethernet interface(it can"
5201 "be obtained by the "
5202 "command:network view-config)"
5203 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06005204 parser_setDNS.set_defaults(func=setDNS)
5205
5206 # get NTP
5207 parser_getNTP = nw_sub.add_parser("getNTP",
5208 help="prints out NTP servers on the "
5209 "given interface")
5210 parser_getNTP.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06005211 help="Name of the ethernet interface(it can"
5212 "be obtained by the "
5213 "command:network view-config)"
5214 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06005215 parser_getNTP.set_defaults(func=getNTP)
5216
5217 # set NTP
5218 parser_setNTP = nw_sub.add_parser("setNTP",
5219 help="sets NTP servers on the given "
5220 "interface")
5221 parser_setNTP.add_argument("-N", "--NTPServers", required=True,
5222 help="Ex: NTPSERVERS=NTP1,NTP2,...")
5223 parser_setNTP.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06005224 help="Name of the ethernet interface(it can"
5225 "be obtained by the "
5226 "command:network view-config)"
5227 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06005228 parser_setNTP.set_defaults(func=setNTP)
5229
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06005230 # configure IP
5231 parser_ip_config = nw_sub.add_parser("addIP", help="Sets IP address to"
5232 "given interface")
5233 parser_ip_config.add_argument("-a", "--address", required=True,
5234 help="IP address of given interface")
5235 parser_ip_config.add_argument("-gw", "--gateway", required=False, default='',
5236 help="The gateway for given interface")
5237 parser_ip_config.add_argument("-l", "--prefixLength", required=True,
5238 help="The prefixLength of IP address")
Sunitha Harish0baf6372019-07-31 03:59:03 -05005239 parser_ip_config.add_argument("-p", "--type", required=True,
5240 choices=['ipv4', 'ipv6'],
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06005241 help="The protocol type of the given"
5242 "IP address")
5243 parser_ip_config.add_argument("-I", "--Interface", required=True,
5244 help="Name of the ethernet interface(it can"
5245 "be obtained by the "
5246 "command:network view-config)"
5247 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
5248 parser_ip_config.set_defaults(func=addIP)
5249
5250 # getIP
5251 parser_getIP = nw_sub.add_parser("getIP", help="prints out IP address"
5252 "of given interface")
5253 parser_getIP.add_argument("-I", "--Interface", required=True,
5254 help="Name of the ethernet interface(it can"
5255 "be obtained by the command:network view-config)"
5256 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
5257 parser_getIP.set_defaults(func=getIP)
5258
5259 # rmIP
5260 parser_rmIP = nw_sub.add_parser("rmIP", help="deletes IP address"
5261 "of given interface")
5262 parser_rmIP.add_argument("-a", "--address", required=True,
5263 help="IP address to remove form given Interface")
5264 parser_rmIP.add_argument("-I", "--Interface", required=True,
5265 help="Name of the ethernet interface(it can"
5266 "be obtained by the command:network view-config)"
5267 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
5268 parser_rmIP.set_defaults(func=deleteIP)
5269
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06005270 # add VLAN
5271 parser_create_vlan = nw_sub.add_parser("addVLAN", help="enables VLAN "
5272 "on given interface with given "
5273 "VLAN Identifier")
5274 parser_create_vlan.add_argument("-I", "--Interface", required=True,
5275 choices=['eth0', 'eth1'],
5276 help="Name of the ethernet interface")
5277 parser_create_vlan.add_argument("-n", "--Identifier", required=True,
5278 help="VLAN Identifier")
5279 parser_create_vlan.set_defaults(func=addVLAN)
5280
5281 # delete VLAN
5282 parser_delete_vlan = nw_sub.add_parser("deleteVLAN", help="disables VLAN "
5283 "on given interface with given "
5284 "VLAN Identifier")
5285 parser_delete_vlan.add_argument("-I", "--Interface", required=True,
5286 help="Name of the ethernet interface(it can"
5287 "be obtained by the "
5288 "command:network view-config)"
5289 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
5290 parser_delete_vlan.set_defaults(func=deleteVLAN)
5291
5292 # viewDHCPConfig
5293 parser_viewDHCPConfig = nw_sub.add_parser("viewDHCPConfig",
5294 help="Shows DHCP configured "
5295 "Properties")
5296 parser_viewDHCPConfig.set_defaults(func=viewDHCPConfig)
5297
5298 # configureDHCP
5299 parser_configDHCP = nw_sub.add_parser("configureDHCP",
5300 help="Configures/updates DHCP "
5301 "Properties")
5302 parser_configDHCP.add_argument("-d", "--DNSEnabled", type=str2bool,
5303 required=True, help="Sets DNSEnabled property")
5304 parser_configDHCP.add_argument("-n", "--HostNameEnabled", type=str2bool,
5305 required=True,
5306 help="Sets HostNameEnabled property")
5307 parser_configDHCP.add_argument("-t", "--NTPEnabled", type=str2bool,
5308 required=True,
5309 help="Sets NTPEnabled property")
5310 parser_configDHCP.add_argument("-s", "--SendHostNameEnabled", type=str2bool,
5311 required=True,
5312 help="Sets SendHostNameEnabled property")
5313 parser_configDHCP.set_defaults(func=configureDHCP)
5314
5315 # network factory reset
5316 parser_nw_reset = nw_sub.add_parser("nwReset",
5317 help="Resets networks setting to "
5318 "factory defaults. "
5319 "note:Reset settings will be applied "
5320 "after BMC reboot")
5321 parser_nw_reset.set_defaults(func=nwReset)
5322
Justin Thalerf9aee3e2017-12-05 12:11:09 -06005323 return parser
5324
Justin Thalerf9aee3e2017-12-05 12:11:09 -06005325def main(argv=None):
Justin Thalere412dc22018-01-12 16:28:24 -06005326 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06005327 main function for running the command line utility as a sub application
5328 """
5329 global toolVersion
Justin Thalerc42e4e52020-05-13 12:04:24 -05005330 toolVersion = "1.19"
Sunitha Harishc99faba2019-07-19 06:55:22 -05005331 global isRedfishSupport
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05005332
Justin Thalerf9aee3e2017-12-05 12:11:09 -06005333 parser = createCommandParser()
Justin Thalerf9aee3e2017-12-05 12:11:09 -06005334 args = parser.parse_args(argv)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06005335
Justin Thalerf9aee3e2017-12-05 12:11:09 -06005336 totTimeStart = int(round(time.time()*1000))
5337
5338 if(sys.version_info < (3,0)):
5339 urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
5340 if sys.version_info >= (3,0):
5341 requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)
Justin Thalere412dc22018-01-12 16:28:24 -06005342 if (args.version):
Justin Thaler22b1bb52018-03-15 13:31:32 -05005343 print("Version: "+ toolVersion)
Justin Thalere412dc22018-01-12 16:28:24 -06005344 sys.exit(0)
5345 if (hasattr(args, 'fileloc') and args.fileloc is not None and 'print' in args.command):
Justin Thalerf9aee3e2017-12-05 12:11:09 -06005346 mysess = None
Justin Thalere412dc22018-01-12 16:28:24 -06005347 print(selPrint('N/A', args, mysess))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06005348 else:
Justin Thalere412dc22018-01-12 16:28:24 -06005349 if(hasattr(args, 'host') and hasattr(args,'user')):
5350 if (args.askpw):
5351 pw = getpass.getpass()
5352 elif(args.PW is not None):
5353 pw = args.PW
Joseph Reynoldsa2d54c52019-06-11 22:02:57 -05005354 elif(args.PWenvvar):
5355 pw = os.environ['OPENBMCTOOL_PASSWORD']
Justin Thalere412dc22018-01-12 16:28:24 -06005356 else:
5357 print("You must specify a password")
5358 sys.exit()
5359 logintimeStart = int(round(time.time()*1000))
Joy Onyerikwu182c3a32019-10-15 08:33:59 -05005360 mysess = login(args.host, args.user, pw, args.json,
5361 args.command == 'set_password')
Sunitha Harish336cda22019-07-23 02:02:52 -05005362 if(mysess == None):
5363 print("Login Failed!")
5364 sys.exit()
Justin Thalera9415b42018-05-25 19:40:13 -05005365 if(sys.version_info < (3,0)):
5366 if isinstance(mysess, basestring):
5367 print(mysess)
5368 sys.exit(1)
5369 elif sys.version_info >= (3,0):
5370 if isinstance(mysess, str):
5371 print(mysess)
5372 sys.exit(1)
Justin Thalere412dc22018-01-12 16:28:24 -06005373 logintimeStop = int(round(time.time()*1000))
Sunitha Harishc99faba2019-07-19 06:55:22 -05005374 isRedfishSupport = redfishSupportPresent(args.host,mysess)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06005375 commandTimeStart = int(round(time.time()*1000))
Justin Thalere412dc22018-01-12 16:28:24 -06005376 output = args.func(args.host, args, mysess)
5377 commandTimeStop = int(round(time.time()*1000))
Justin Thaler761484a2019-03-26 19:20:23 -05005378 if isinstance(output, dict):
5379 print(json.dumps(output, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False))
5380 else:
5381 print(output)
Justin Thalere412dc22018-01-12 16:28:24 -06005382 if (mysess is not None):
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06005383 logout(args.host, args.user, pw, mysess, args.json)
5384 if(args.procTime):
Justin Thalere412dc22018-01-12 16:28:24 -06005385 print("Total time: " + str(int(round(time.time()*1000))- totTimeStart))
5386 print("loginTime: " + str(logintimeStop - logintimeStart))
5387 print("command Time: " + str(commandTimeStop - commandTimeStart))
5388 else:
Joseph Reynoldsa2d54c52019-06-11 22:02:57 -05005389 print("usage:\n"
5390 " OPENBMCTOOL_PASSWORD=secret # if using -E\n"
5391 " openbmctool.py [-h] -H HOST -U USER {-A | -P PW | -E} [-j]\n" +
Justin Thalere412dc22018-01-12 16:28:24 -06005392 "\t[-t POLICYTABLELOC] [-V]\n" +
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05005393 "\t{fru,sensors,sel,chassis,collect_service_data, \
5394 health_check,dump,bmc,mc,gardclear,firmware,logging}\n" +
Justin Thalere412dc22018-01-12 16:28:24 -06005395 "\t...\n" +
5396 "openbmctool.py: error: the following arguments are required: -H/--host, -U/--user")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06005397 sys.exit()
Justin Thalerf9aee3e2017-12-05 12:11:09 -06005398
Justin Thalerf9aee3e2017-12-05 12:11:09 -06005399if __name__ == '__main__':
Justin Thalere412dc22018-01-12 16:28:24 -06005400 """
5401 main function when called from the command line
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06005402
5403 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06005404 import sys
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06005405
Justin Thalerf9aee3e2017-12-05 12:11:09 -06005406 isTTY = sys.stdout.isatty()
5407 assert sys.version_info >= (2,7)
5408 main()