blob: 834a2d62da9458bbf81f2d68d305366afe804766 [file] [log] [blame]
Justin Thalerb8807ce2018-05-25 19:16:20 -05001#!/usr/bin/python3
Justin Thalere412dc22018-01-12 16:28:24 -06002"""
Joseph Reynoldsa2d54c52019-06-11 22:02:57 -05003 Copyright 2017,2019 IBM Corporation
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004
Justin Thalere412dc22018-01-12 16:28:24 -06005 Licensed under the Apache License, Version 2.0 (the "License");
6 you may not use this file except in compliance with the License.
7 You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16"""
Justin Thalerf9aee3e2017-12-05 12:11:09 -060017import argparse
18import requests
Alvin Wangbf99c582019-10-29 16:40:05 +080019import simplejson
Justin Thalerf9aee3e2017-12-05 12:11:09 -060020import getpass
21import json
22import os
23import urllib3
24import time, datetime
Justin Thalerf9aee3e2017-12-05 12:11:09 -060025import binascii
26import subprocess
27import platform
28import zipfile
Justin Thaler22b1bb52018-03-15 13:31:32 -050029import tarfile
30import tempfile
31import hashlib
Justin Thalera6b5df72018-07-16 11:10:07 -050032import re
Justin Thaler24d4efa2018-11-08 22:48:10 -060033import uuid
Ravi Tejad8be0b42020-03-18 14:31:46 -050034import ssl
35import socket
36import select
37import http.client
38from subprocess import check_output
Justin Thalerb4256672020-04-07 19:38:26 -050039import traceback
Justin Thalerf9aee3e2017-12-05 12:11:09 -060040
Ravi Tejad8be0b42020-03-18 14:31:46 -050041
42MAX_NBD_PACKET_SIZE = 131088
Matt Spinler220c3c42019-01-04 15:09:29 -060043jsonHeader = {'Content-Type' : 'application/json'}
44xAuthHeader = {}
Justin Thaler27197622019-01-23 14:42:11 -060045baseTimeout = 60
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -050046serverTypeMap = {
47 'ActiveDirectory' : 'active_directory',
48 'OpenLDAP' : 'openldap'
49 }
Matt Spinler220c3c42019-01-04 15:09:29 -060050
Ravi Tejad8be0b42020-03-18 14:31:46 -050051class NBDPipe:
52
53 def openHTTPSocket(self,args):
54
55 try:
56 _create_unverified_https_context = ssl._create_unverified_context
57 except AttributeError:
58 # Legacy Python that doesn't verify HTTPS certificates by default
59 pass
60 else:
61 # Handle target environment that doesn't support HTTPS verification
62 ssl._create_default_https_context = _create_unverified_https_context
63
64
65 token = gettoken(args)
66 self.conn = http.client.HTTPSConnection(args.host,port=443)
67 URI = "/redfish/v1/Systems/system/LogServices/SystemDump/Entries/"+str(args.dumpNum)+"/Actions/Oem/OpenBmc/LogEntry.DownloadLog"
68 self.conn.request("POST",URI, headers={"X-Auth-Token":token})
69
70 def openTCPSocket(self):
71 # Create a TCP/IP socket
72 self.tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
73 # Connect the socket to the port where the server is listening
74 server_address = ('localhost', 1043)
75 self.tcp.connect(server_address)
76
77 def waitformessage(self):
78 inputs = [self.conn.sock,self.tcp]
79 outputs = []
80 message_queues = {}
81 while True:
82 readable, writable, exceptional = select.select(
83 inputs, outputs, inputs)
84
85 for s in readable:
86 if s is self.conn.sock:
87
88 data = self.conn.sock.recv(MAX_NBD_PACKET_SIZE)
89 print("<<HTTP")
90 #print(len(data))
91 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")
101 #print(len(data));
102 if data:
103 self.conn.sock.send(data)
104 else:
105 print("NBD server closed the connection")
106 self.conn.sock.close()
107 self.tcp.close()
108 sys.exit(1)
109 for s in exceptional:
110 inputs.remove(s)
111 print("Exceptional closing the socket")
112 s.close()
113
114def getsize(host,args,session):
115 url = "https://"+host+"/redfish/v1/Systems/system/LogServices/SystemDump/Entries/"+str(args.dumpNum)
116 print(url)
117 try:
118 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
119 if resp.status_code==200:
120 size = resp.json()["Oem"]["OpenBmc"]['SizeInB']
121 print(size)
122 return size
123 else:
124 return "Failed get Size"
125 except(requests.exceptions.Timeout):
126 return connectionErrHandler(args.json, "Timeout", None)
127
128 except(requests.exceptions.ConnectionError) as err:
129 return connectionErrHandler(args.json, "ConnectionError", err)
130
131def gettoken(args):
132 mysess = requests.session()
133 resp = mysess.post('https://'+args.host+'/login', headers=jsonHeader,json={"data":[args.user,args.PW]},verify=False)
134 if resp.status_code == 200:
135 cookie = resp.headers['Set-Cookie']
136 match = re.search('SESSION=(\w+);', cookie)
137 return match.group(1)
138
139
140
141def get_pid(name):
142 try:
143 pid = map(int, check_output(["pidof", "-s",name]))
144 except Exception:
145 pid = 0
146
147 return pid
148
149def findThisProcess( process_name ):
150 ps = subprocess.Popen("ps -eaf | grep "+process_name, shell=True, stdout=subprocess.PIPE)
151 output = ps.stdout.read()
152 ps.stdout.close()
153 ps.wait()
154 pid = get_pid(process_name)
155 print(pid)
156 return output
157
158def isThisProcessRunning( process_name ):
159 pid = get_pid(process_name)
160 if (pid == 0 ):
161 return False
162 else:
163 return True
164
165def NBDSetup(host,args,session):
166 user=os.getenv("SUDO_USER")
167 if user is None:
168 path = os.getcwd()
169 nbdServerPath = path + "/nbd-server"
170 print(nbdServerPath,os.path.exists(nbdServerPath))
171 if not os.path.exists(nbdServerPath):
172 print("Error: this program did not run as sudo!\nplease copy nbd-server to current directory and run script again")
173 exit()
174
175 if isThisProcessRunning('nbd-server') == True:
176 print("nbd-server already Running! killing the nbd-server")
177 os.system('killall nbd-server')
178
179 if (args.dumpSaveLoc is not None):
180 if(os.path.exists(args.dumpSaveLoc)):
181 print("Error: File already exists.")
182 exit()
183
184 fp= open(args.dumpSaveLoc,"w")
185 sizeInBytes = getsize(host,args,session)
186 #Round off size to mutiples of 1024
187 size = int(sizeInBytes)
188 print(size)
189 mod = size % 1024
190 if mod :
191 roundoff = 1024 - mod
192 size = size + roundoff
193
194 cmd = 'chmod 777 ' + args.dumpSaveLoc
195 os.system(cmd)
196
197 #Run truncate to create file with given size
198 cmd = 'truncate -s ' + str(size) + ' '+ args.dumpSaveLoc
199 os.system(cmd)
200
201 if user is None:
202 cmd = './nbd-server 1043 '+ args.dumpSaveLoc
203 else:
204 cmd = 'nbd-server 1043 '+ args.dumpSaveLoc
205 os.system(cmd)
206
207
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600208def hilight(textToColor, color, bold):
Justin Thalere412dc22018-01-12 16:28:24 -0600209 """
210 Used to add highlights to various text for displaying in a terminal
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600211
Justin Thalere412dc22018-01-12 16:28:24 -0600212 @param textToColor: string, the text to be colored
213 @param color: string, used to color the text red or green
214 @param bold: boolean, used to bold the textToColor
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600215 @return: Buffered reader containing the modified string.
216 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600217 if(sys.platform.__contains__("win")):
218 if(color == "red"):
219 os.system('color 04')
220 elif(color == "green"):
221 os.system('color 02')
222 else:
223 os.system('color') #reset to default
224 return textToColor
225 else:
226 attr = []
227 if(color == "red"):
228 attr.append('31')
229 elif(color == "green"):
230 attr.append('32')
231 else:
232 attr.append('0')
233 if bold:
234 attr.append('1')
235 else:
236 attr.append('0')
237 return '\x1b[%sm%s\x1b[0m' % (';'.join(attr),textToColor)
238
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600239def connectionErrHandler(jsonFormat, errorStr, err):
Justin Thalere412dc22018-01-12 16:28:24 -0600240 """
241 Error handler various connection errors to bmcs
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600242
243 @param jsonFormat: boolean, used to output in json format with an error code.
Justin Thalere412dc22018-01-12 16:28:24 -0600244 @param errorStr: string, used to color the text red or green
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600245 @param err: string, the text from the exception
246 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600247 if errorStr == "Timeout":
248 if not jsonFormat:
249 return("FQPSPIN0000M: Connection timed out. Ensure you have network connectivity to the bmc")
250 else:
Justin Thaler115bca72018-05-25 19:29:08 -0500251 conerror = {}
252 conerror['CommonEventID'] = 'FQPSPIN0000M'
253 conerror['sensor']="N/A"
254 conerror['state']="N/A"
255 conerror['additionalDetails'] = "N/A"
256 conerror['Message']="Connection timed out. Ensure you have network connectivity to the BMC"
257 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."
258 conerror['Serviceable']="Yes"
259 conerror['CallHomeCandidate']= "No"
260 conerror['Severity'] = "Critical"
261 conerror['EventType'] = "Communication Failure/Timeout"
262 conerror['VMMigrationFlag'] = "Yes"
263 conerror["AffectedSubsystem"] = "Interconnect (Networking)"
264 conerror["timestamp"] = str(int(time.time()))
265 conerror["UserAction"] = "Verify network connectivity between the two systems and the bmc is functional."
266 eventdict = {}
267 eventdict['event0'] = conerror
268 eventdict['numAlerts'] = '1'
Justin Thaler115bca72018-05-25 19:29:08 -0500269 errorMessageStr = errorMessageStr = json.dumps(eventdict, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600270 return(errorMessageStr)
271 elif errorStr == "ConnectionError":
272 if not jsonFormat:
273 return("FQPSPIN0001M: " + str(err))
274 else:
Justin Thaler115bca72018-05-25 19:29:08 -0500275 conerror = {}
276 conerror['CommonEventID'] = 'FQPSPIN0001M'
277 conerror['sensor']="N/A"
278 conerror['state']="N/A"
279 conerror['additionalDetails'] = str(err)
280 conerror['Message']="Connection Error. View additional details for more information"
281 conerror['LengthyDescription'] = "A connection error to the specified BMC occurred and additional details are provided. Review these details to resolve the issue."
282 conerror['Serviceable']="Yes"
283 conerror['CallHomeCandidate']= "No"
284 conerror['Severity'] = "Critical"
285 conerror['EventType'] = "Communication Failure/Timeout"
286 conerror['VMMigrationFlag'] = "Yes"
287 conerror["AffectedSubsystem"] = "Interconnect (Networking)"
288 conerror["timestamp"] = str(int(time.time()))
289 conerror["UserAction"] = "Correct the issue highlighted in additional details and try again"
290 eventdict = {}
291 eventdict['event0'] = conerror
292 eventdict['numAlerts'] = '1'
Justin Thaler115bca72018-05-25 19:29:08 -0500293 errorMessageStr = json.dumps(eventdict, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600294 return(errorMessageStr)
Justin Thaler115bca72018-05-25 19:29:08 -0500295
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600296 else:
297 return("Unknown Error: "+ str(err))
298
Justin Thalere412dc22018-01-12 16:28:24 -0600299
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600300def setColWidth(keylist, numCols, dictForOutput, colNames):
Justin Thalere412dc22018-01-12 16:28:24 -0600301 """
302 Sets the output width of the columns to display
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600303
304 @param keylist: list, list of strings representing the keys for the dictForOutput
Justin Thalere412dc22018-01-12 16:28:24 -0600305 @param numcols: the total number of columns in the final output
306 @param dictForOutput: dictionary, contains the information to print to the screen
307 @param colNames: list, The strings to use for the column headings, in order of the keylist
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600308 @return: A list of the column widths for each respective column.
Justin Thalere412dc22018-01-12 16:28:24 -0600309 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600310 colWidths = []
311 for x in range(0, numCols):
312 colWidths.append(0)
313 for key in dictForOutput:
314 for x in range(0, numCols):
315 colWidths[x] = max(colWidths[x], len(str(dictForOutput[key][keylist[x]])))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600316
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600317 for x in range(0, numCols):
318 colWidths[x] = max(colWidths[x], len(colNames[x])) +2
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600319
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600320 return colWidths
321
322def loadPolicyTable(pathToPolicyTable):
Justin Thalere412dc22018-01-12 16:28:24 -0600323 """
324 loads a json based policy table into a dictionary
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600325
Justin Thalere412dc22018-01-12 16:28:24 -0600326 @param value: boolean, the value to convert
327 @return: A string of "Yes" or "No"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600328 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600329 policyTable = {}
330 if(os.path.exists(pathToPolicyTable)):
331 with open(pathToPolicyTable, 'r') as stream:
332 try:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600333 contents =json.load(stream)
334 policyTable = contents['events']
Justin Thalere412dc22018-01-12 16:28:24 -0600335 except Exception as err:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600336 print(err)
337 return policyTable
338
Justin Thalere412dc22018-01-12 16:28:24 -0600339
340def boolToString(value):
341 """
342 converts a boolean value to a human readable string value
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600343
Justin Thalere412dc22018-01-12 16:28:24 -0600344 @param value: boolean, the value to convert
345 @return: A string of "Yes" or "No"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600346 """
Justin Thalere412dc22018-01-12 16:28:24 -0600347 if(value):
348 return "Yes"
349 else:
350 return "No"
351
Justin Thalera6b5df72018-07-16 11:10:07 -0500352def stringToInt(text):
353 """
354 returns an integer if the string can be converted, otherwise returns the string
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600355
Justin Thalera6b5df72018-07-16 11:10:07 -0500356 @param text: the string to try to convert to an integer
357 """
358 if text.isdigit():
359 return int(text)
360 else:
361 return text
Justin Thalere412dc22018-01-12 16:28:24 -0600362
Justin Thalera6b5df72018-07-16 11:10:07 -0500363def naturalSort(text):
364 """
365 provides a way to naturally sort a list
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600366
Justin Thalera6b5df72018-07-16 11:10:07 -0500367 @param text: the key to convert for sorting
368 @return list containing the broken up string parts by integers and strings
369 """
370 stringPartList = []
371 for c in re.split('(\d+)', text):
372 stringPartList.append(stringToInt(c))
373 return stringPartList
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600374
Justin Thalere412dc22018-01-12 16:28:24 -0600375def tableDisplay(keylist, colNames, output):
376 """
377 Logs into the BMC and creates a session
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600378
Justin Thalere412dc22018-01-12 16:28:24 -0600379 @param keylist: list, keys for the output dictionary, ordered by colNames
380 @param colNames: Names for the Table of the columns
381 @param output: The dictionary of data to display
382 @return: Session object
383 """
384 colWidth = setColWidth(keylist, len(colNames), output, colNames)
385 row = ""
386 outputText = ""
387 for i in range(len(colNames)):
388 if (i != 0): row = row + "| "
389 row = row + colNames[i].ljust(colWidth[i])
390 outputText += row + "\n"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600391
Justin Thalera6b5df72018-07-16 11:10:07 -0500392 output_keys = list(output.keys())
393 output_keys.sort(key=naturalSort)
394 for key in output_keys:
Justin Thalere412dc22018-01-12 16:28:24 -0600395 row = ""
Justin Thaler8fe0c732018-07-24 14:32:35 -0500396 for i in range(len(keylist)):
Justin Thalere412dc22018-01-12 16:28:24 -0600397 if (i != 0): row = row + "| "
398 row = row + output[key][keylist[i]].ljust(colWidth[i])
399 outputText += row + "\n"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600400
Justin Thalere412dc22018-01-12 16:28:24 -0600401 return outputText
402
Justin Thaler22b1bb52018-03-15 13:31:32 -0500403def checkFWactivation(host, args, session):
404 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600405 Checks the software inventory for an image that is being activated.
406
Justin Thaler22b1bb52018-03-15 13:31:32 -0500407 @return: True if an image is being activated, false is no activations are happening
408 """
409 url="https://"+host+"/xyz/openbmc_project/software/enumerate"
Justin Thaler22b1bb52018-03-15 13:31:32 -0500410 try:
Justin Thaler27197622019-01-23 14:42:11 -0600411 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thaler22b1bb52018-03-15 13:31:32 -0500412 except(requests.exceptions.Timeout):
413 print(connectionErrHandler(args.json, "Timeout", None))
414 return(True)
415 except(requests.exceptions.ConnectionError) as err:
416 print( connectionErrHandler(args.json, "ConnectionError", err))
417 return True
Justin Thaler3a5771b2019-01-23 14:31:52 -0600418 fwInfo = resp.json()['data']
Justin Thaler22b1bb52018-03-15 13:31:32 -0500419 for key in fwInfo:
420 if 'Activation' in fwInfo[key]:
421 if 'Activating' in fwInfo[key]['Activation'] or 'Activating' in fwInfo[key]['RequestedActivation']:
422 return True
423 return False
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600424
Joy Onyerikwu182c3a32019-10-15 08:33:59 -0500425def login(host, username, pw,jsonFormat, allowExpiredPassword):
Justin Thalere412dc22018-01-12 16:28:24 -0600426 """
427 Logs into the BMC and creates a session
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600428
Justin Thalere412dc22018-01-12 16:28:24 -0600429 @param host: string, the hostname or IP address of the bmc to log into
430 @param username: The user name for the bmc to log into
431 @param pw: The password for the BMC to log into
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600432 @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 -0500433 @param allowExpiredPassword: true, if the requested operation should
434 be allowed when the password is expired
Justin Thalere412dc22018-01-12 16:28:24 -0600435 @return: Session object
436 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600437 if(jsonFormat==False):
438 print("Attempting login...")
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600439 mysess = requests.session()
440 try:
Justin Thaler27197622019-01-23 14:42:11 -0600441 r = mysess.post('https://'+host+'/login', headers=jsonHeader, json = {"data": [username, pw]}, verify=False, timeout=baseTimeout)
Sunitha Harish336cda22019-07-23 02:02:52 -0500442 if r.status_code == 200:
443 cookie = r.headers['Set-Cookie']
444 match = re.search('SESSION=(\w+);', cookie)
445 if match:
446 xAuthHeader['X-Auth-Token'] = match.group(1)
447 jsonHeader.update(xAuthHeader)
448 loginMessage = json.loads(r.text)
449 if (loginMessage['status'] != "ok"):
450 print(loginMessage["data"]["description"].encode('utf-8'))
451 sys.exit(1)
Joy Onyerikwu182c3a32019-10-15 08:33:59 -0500452 if (('extendedMessage' in r.json()) and
453 ('The password for this account must be changed' in r.json()['extendedMessage'])):
454 if not allowExpiredPassword:
455 print("The password for this system has expired and must be changed"+
456 "\nsee openbmctool.py set_password --help")
457 logout(host, username, pw, mysess, jsonFormat)
458 sys.exit(1)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600459# if(sys.version_info < (3,0)):
460# urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
461# if sys.version_info >= (3,0):
462# requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)
Sunitha Harish336cda22019-07-23 02:02:52 -0500463 return mysess
464 else:
465 return None
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600466 except(requests.exceptions.Timeout):
Justin Thaler115bca72018-05-25 19:29:08 -0500467 return (connectionErrHandler(jsonFormat, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600468 except(requests.exceptions.ConnectionError) as err:
Justin Thaler115bca72018-05-25 19:29:08 -0500469 return (connectionErrHandler(jsonFormat, "ConnectionError", err))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600470
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600471
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600472def logout(host, username, pw, session, jsonFormat):
Justin Thalere412dc22018-01-12 16:28:24 -0600473 """
474 Logs out of the bmc and terminates the session
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600475
Justin Thalere412dc22018-01-12 16:28:24 -0600476 @param host: string, the hostname or IP address of the bmc to log out of
477 @param username: The user name for the bmc to log out of
478 @param pw: The password for the BMC to log out of
479 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600480 @param jsonFormat: boolean, flag that will only allow relevant data from user command to be display. This function becomes silent when set to true.
481 """
Justin Thalere412dc22018-01-12 16:28:24 -0600482 try:
Justin Thaler27197622019-01-23 14:42:11 -0600483 r = session.post('https://'+host+'/logout', headers=jsonHeader,json = {"data": [username, pw]}, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600484 except(requests.exceptions.Timeout):
485 print(connectionErrHandler(jsonFormat, "Timeout", None))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600486
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600487 if(jsonFormat==False):
Matt Spinlereae05b02019-01-24 12:59:34 -0600488 if r.status_code == 200:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600489 print('User ' +username + ' has been logged out')
490
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600491
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600492def fru(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -0600493 """
494 prints out the system inventory. deprecated see fruPrint and fruList
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600495
Justin Thalere412dc22018-01-12 16:28:24 -0600496 @param host: string, the hostname or IP address of the bmc
497 @param args: contains additional arguments used by the fru sub command
498 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600499 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
500 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600501 #url="https://"+host+"/org/openbmc/inventory/system/chassis/enumerate"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600502
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600503 #print(url)
504 #res = session.get(url, headers=httpHeader, verify=False)
505 #print(res.text)
506 #sample = res.text
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600507
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600508 #inv_list = json.loads(sample)["data"]
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600509
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600510 url="https://"+host+"/xyz/openbmc_project/inventory/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600511 try:
Justin Thaler27197622019-01-23 14:42:11 -0600512 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600513 except(requests.exceptions.Timeout):
514 return(connectionErrHandler(args.json, "Timeout", None))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600515
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600516 sample = res.text
517# inv_list.update(json.loads(sample)["data"])
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600518#
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600519# #determine column width's
520# colNames = ["FRU Name", "FRU Type", "Has Fault", "Is FRU", "Present", "Version"]
521# colWidths = setColWidth(["FRU Name", "fru_type", "fault", "is_fru", "present", "version"], 6, inv_list, colNames)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600522#
523# 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 -0600524# "Present".ljust(colWidths[4]) + "Version".ljust(colWidths[5]))
525# format the output
526# for key in sorted(inv_list.keys()):
527# keyParts = key.split("/")
528# isFRU = "True" if (inv_list[key]["is_fru"]==1) else "False"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600529#
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600530# fruEntry = (keyParts[len(keyParts) - 1].ljust(colWidths[0]) + inv_list[key]["fru_type"].ljust(colWidths[1])+
531# inv_list[key]["fault"].ljust(colWidths[2])+isFRU.ljust(colWidths[3])+
532# inv_list[key]["present"].ljust(colWidths[4])+ inv_list[key]["version"].ljust(colWidths[5]))
533# if(isTTY):
534# if(inv_list[key]["is_fru"] == 1):
535# color = "green"
536# bold = True
537# else:
538# color='black'
539# bold = False
540# fruEntry = hilight(fruEntry, color, bold)
541# print (fruEntry)
542 return sample
Justin Thalere412dc22018-01-12 16:28:24 -0600543
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600544def fruPrint(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -0600545 """
546 prints out all inventory
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600547
Justin Thalere412dc22018-01-12 16:28:24 -0600548 @param host: string, the hostname or IP address of the bmc
549 @param args: contains additional arguments used by the fru sub command
550 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600551 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
552 @return returns the total fru list.
553 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600554 url="https://"+host+"/xyz/openbmc_project/inventory/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600555 try:
Justin Thaler27197622019-01-23 14:42:11 -0600556 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600557 except(requests.exceptions.Timeout):
558 return(connectionErrHandler(args.json, "Timeout", None))
559
Justin Thaler3a5771b2019-01-23 14:31:52 -0600560 frulist={}
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600561# print(res.text)
Justin Thaler3a5771b2019-01-23 14:31:52 -0600562 if res.status_code==200:
563 frulist['Hardware'] = res.json()['data']
564 else:
565 if not args.json:
566 return "Error retrieving the system inventory. BMC message: {msg}".format(msg=res.json()['message'])
567 else:
568 return res.json()
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600569 url="https://"+host+"/xyz/openbmc_project/software/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600570 try:
Justin Thaler27197622019-01-23 14:42:11 -0600571 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600572 except(requests.exceptions.Timeout):
573 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600574# print(res.text)
Justin Thaler3a5771b2019-01-23 14:31:52 -0600575 if res.status_code==200:
576 frulist['Software'] = res.json()['data']
577 else:
578 if not args.json():
579 return "Error retrieving the system inventory. BMC message: {msg}".format(msg=res.json()['message'])
580 else:
581 return res.json()
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600582 return frulist
583
Justin Thalere412dc22018-01-12 16:28:24 -0600584
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600585def fruList(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -0600586 """
587 prints out all inventory or only a specific specified item
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600588
Justin Thalere412dc22018-01-12 16:28:24 -0600589 @param host: string, the hostname or IP address of the bmc
590 @param args: contains additional arguments used by the fru sub command
591 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600592 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
593 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600594 if(args.items==True):
595 return fruPrint(host, args, session)
596 else:
Justin Thalere412dc22018-01-12 16:28:24 -0600597 return fruPrint(host, args, session)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600598
599
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600600
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600601def fruStatus(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -0600602 """
603 prints out the status of all FRUs
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600604
Justin Thalere412dc22018-01-12 16:28:24 -0600605 @param host: string, the hostname or IP address of the bmc
606 @param args: contains additional arguments used by the fru sub command
607 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600608 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
609 """
Justin Thalere412dc22018-01-12 16:28:24 -0600610 url="https://"+host+"/xyz/openbmc_project/inventory/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600611 try:
Matt Spinler220c3c42019-01-04 15:09:29 -0600612 res = session.get(url, headers=jsonHeader, verify=False)
Justin Thalere412dc22018-01-12 16:28:24 -0600613 except(requests.exceptions.Timeout):
614 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600615# print(res.text)
Justin Thaler3a5771b2019-01-23 14:31:52 -0600616 frulist = res.json()['data']
Justin Thalere412dc22018-01-12 16:28:24 -0600617 frus = {}
618 for key in frulist:
619 component = frulist[key]
620 isFru = False
621 present = False
622 func = False
623 hasSels = False
624 keyPieces = key.split('/')
625 fruName = keyPieces[-1]
626 if 'core' in fruName: #associate cores to cpus
627 fruName = keyPieces[-2] + '-' + keyPieces[-1]
628 if 'Functional' in component:
629 if('Present' in component):
Justin Thalere412dc22018-01-12 16:28:24 -0600630 if 'FieldReplaceable' in component:
631 if component['FieldReplaceable'] == 1:
632 isFru = True
633 if "fan" in fruName:
634 isFru = True;
635 if component['Present'] == 1:
636 present = True
637 if component['Functional'] == 1:
638 func = True
639 if ((key + "/fault") in frulist):
640 hasSels = True;
641 if args.verbose:
642 if hasSels:
643 loglist = []
644 faults = frulist[key+"/fault"]['endpoints']
645 for item in faults:
646 loglist.append(item.split('/')[-1])
647 frus[fruName] = {"compName": fruName, "Functional": boolToString(func), "Present":boolToString(present), "IsFru": boolToString(isFru), "selList": ', '.join(loglist).strip() }
648 else:
649 frus[fruName] = {"compName": fruName, "Functional": boolToString(func), "Present":boolToString(present), "IsFru": boolToString(isFru), "selList": "None" }
650 else:
651 frus[fruName] = {"compName": fruName, "Functional": boolToString(func), "Present":boolToString(present), "IsFru": boolToString(isFru), "hasSEL": boolToString(hasSels) }
Justin Thalerfb9c81c2018-07-16 11:14:37 -0500652 elif "power_supply" in fruName or "powersupply" in fruName:
Justin Thalere412dc22018-01-12 16:28:24 -0600653 if component['Present'] ==1:
654 present = True
655 isFru = True
656 if ((key + "/fault") in frulist):
657 hasSels = True;
658 if args.verbose:
659 if hasSels:
660 loglist = []
661 faults = frulist[key+"/fault"]['endpoints']
Obihörnchenff8035f2018-12-05 21:07:37 +0100662 for item in faults:
663 loglist.append(item.split('/')[-1])
Justin Thalere412dc22018-01-12 16:28:24 -0600664 frus[fruName] = {"compName": fruName, "Functional": "No", "Present":boolToString(present), "IsFru": boolToString(isFru), "selList": ', '.join(loglist).strip() }
665 else:
666 frus[fruName] = {"compName": fruName, "Functional": "Yes", "Present":boolToString(present), "IsFru": boolToString(isFru), "selList": "None" }
667 else:
668 frus[fruName] = {"compName": fruName, "Functional": boolToString(not hasSels), "Present":boolToString(present), "IsFru": boolToString(isFru), "hasSEL": boolToString(hasSels) }
669 if not args.json:
670 if not args.verbose:
671 colNames = ["Component", "Is a FRU", "Present", "Functional", "Has Logs"]
672 keylist = ["compName", "IsFru", "Present", "Functional", "hasSEL"]
673 else:
674 colNames = ["Component", "Is a FRU", "Present", "Functional", "Assoc. Log Number(s)"]
675 keylist = ["compName", "IsFru", "Present", "Functional", "selList"]
676 return tableDisplay(keylist, colNames, frus)
677 else:
678 return str(json.dumps(frus, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600679
Justin Thalere412dc22018-01-12 16:28:24 -0600680def sensor(host, args, session):
681 """
682 prints out all sensors
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600683
Justin Thalere412dc22018-01-12 16:28:24 -0600684 @param host: string, the hostname or IP address of the bmc
685 @param args: contains additional arguments used by the sensor sub command
686 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600687 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
688 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600689 url="https://"+host+"/xyz/openbmc_project/sensors/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600690 try:
Justin Thaler27197622019-01-23 14:42:11 -0600691 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600692 except(requests.exceptions.Timeout):
693 return(connectionErrHandler(args.json, "Timeout", None))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600694
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600695 #Get OCC status
696 url="https://"+host+"/org/open_power/control/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600697 try:
Justin Thaler27197622019-01-23 14:42:11 -0600698 occres = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600699 except(requests.exceptions.Timeout):
700 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600701 if not args.json:
702 colNames = ['sensor', 'type', 'units', 'value', 'target']
Justin Thaler3a5771b2019-01-23 14:31:52 -0600703 sensors = res.json()["data"]
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600704 output = {}
705 for key in sensors:
706 senDict = {}
707 keyparts = key.split("/")
Matt Spinler596ef742019-09-20 08:54:36 -0500708
709 # Associations like the following also show up here:
710 # /xyz/openbmc_project/sensors/<type>/<name>/<assoc-name>
711 # Skip them.
712 # Note: keyparts[0] = '' which is why there are 7 segments.
713 if len(keyparts) > 6:
714 continue
715
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600716 senDict['sensorName'] = keyparts[-1]
717 senDict['type'] = keyparts[-2]
Justin Thalere412dc22018-01-12 16:28:24 -0600718 try:
719 senDict['units'] = sensors[key]['Unit'].split('.')[-1]
720 except KeyError:
Justin Thaler22b1bb52018-03-15 13:31:32 -0500721 senDict['units'] = "N/A"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600722 if('Scale' in sensors[key]):
723 scale = 10 ** sensors[key]['Scale']
724 else:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600725 scale = 1
Justin Thaler22b1bb52018-03-15 13:31:32 -0500726 try:
727 senDict['value'] = str(sensors[key]['Value'] * scale)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600728 except KeyError:
Justin Thaler22b1bb52018-03-15 13:31:32 -0500729 if 'value' in sensors[key]:
730 senDict['value'] = sensors[key]['value']
731 else:
732 senDict['value'] = "N/A"
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600733 if 'Target' in sensors[key]:
734 senDict['target'] = str(sensors[key]['Target'])
735 else:
736 senDict['target'] = 'N/A'
737 output[senDict['sensorName']] = senDict
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600738
Justin Thaler3a5771b2019-01-23 14:31:52 -0600739 occstatus = occres.json()["data"]
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600740 if '/org/open_power/control/occ0' in occstatus:
741 occ0 = occstatus["/org/open_power/control/occ0"]['OccActive']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600742 if occ0 == 1:
743 occ0 = 'Active'
744 else:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600745 occ0 = 'Inactive'
746 output['OCC0'] = {'sensorName':'OCC0', 'type': 'Discrete', 'units': 'N/A', 'value': occ0, 'target': 'Active'}
747 occ1 = occstatus["/org/open_power/control/occ1"]['OccActive']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600748 if occ1 == 1:
749 occ1 = 'Active'
750 else:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600751 occ1 = 'Inactive'
752 output['OCC1'] = {'sensorName':'OCC1', 'type': 'Discrete', 'units': 'N/A', 'value': occ0, 'target': 'Active'}
753 else:
754 output['OCC0'] = {'sensorName':'OCC0', 'type': 'Discrete', 'units': 'N/A', 'value': 'Inactive', 'target': 'Inactive'}
755 output['OCC1'] = {'sensorName':'OCC1', 'type': 'Discrete', 'units': 'N/A', 'value': 'Inactive', 'target': 'Inactive'}
756 keylist = ['sensorName', 'type', 'units', 'value', 'target']
Justin Thalere412dc22018-01-12 16:28:24 -0600757
758 return tableDisplay(keylist, colNames, output)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600759 else:
760 return res.text + occres.text
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600761
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600762def sel(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -0600763 """
764 prints out the bmc alerts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600765
Justin Thalere412dc22018-01-12 16:28:24 -0600766 @param host: string, the hostname or IP address of the bmc
767 @param args: contains additional arguments used by the sel sub command
768 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600769 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
770 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600771
772 url="https://"+host+"/xyz/openbmc_project/logging/entry/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600773 try:
Justin Thaler27197622019-01-23 14:42:11 -0600774 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600775 except(requests.exceptions.Timeout):
776 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600777 return res.text
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600778
779
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600780def parseESEL(args, eselRAW):
Justin Thalere412dc22018-01-12 16:28:24 -0600781 """
782 parses the esel data and gets predetermined search terms
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600783
Justin Thalere412dc22018-01-12 16:28:24 -0600784 @param eselRAW: string, the raw esel string from the bmc
785 @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 -0600786 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600787 eselParts = {}
788 esel_bin = binascii.unhexlify(''.join(eselRAW.split()[16:]))
789 #search terms contains the search term as the key and the return dictionary key as it's value
790 searchTerms = { 'Signature Description':'signatureDescription', 'devdesc':'devdesc',
Justin Thaler22b1bb52018-03-15 13:31:32 -0500791 'Callout type': 'calloutType', 'Procedure':'procedure', 'Sensor Type': 'sensorType'}
Justin Thaler24d4efa2018-11-08 22:48:10 -0600792 uniqueID = str(uuid.uuid4())
793 eselBinPath = tempfile.gettempdir() + os.sep + uniqueID + 'esel.bin'
Justin Thalercf1deae2018-05-25 19:35:21 -0500794 with open(eselBinPath, 'wb') as f:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600795 f.write(esel_bin)
796 errlPath = ""
797 #use the right errl file for the machine architecture
798 arch = platform.machine()
799 if(arch =='x86_64' or arch =='AMD64'):
800 if os.path.exists('/opt/ibm/ras/bin/x86_64/errl'):
801 errlPath = '/opt/ibm/ras/bin/x86_64/errl'
802 elif os.path.exists('errl/x86_64/errl'):
803 errlPath = 'errl/x86_64/errl'
804 else:
805 errlPath = 'x86_64/errl'
806 elif (platform.machine()=='ppc64le'):
807 if os.path.exists('/opt/ibm/ras/bin/ppc64le/errl'):
808 errlPath = '/opt/ibm/ras/bin/ppc64le/errl'
809 elif os.path.exists('errl/ppc64le/errl'):
810 errlPath = 'errl/ppc64le/errl'
811 else:
812 errlPath = 'ppc64le/errl'
813 else:
814 print("machine architecture not supported for parsing eSELs")
815 return eselParts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600816
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600817 if(os.path.exists(errlPath)):
Justin Thalercf1deae2018-05-25 19:35:21 -0500818 output= subprocess.check_output([errlPath, '-d', '--file='+eselBinPath]).decode('utf-8')
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600819# output = proc.communicate()[0]
820 lines = output.split('\n')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600821
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600822 if(hasattr(args, 'fullEsel')):
823 return output
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600824
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600825 for i in range(0, len(lines)):
826 lineParts = lines[i].split(':')
827 if(len(lineParts)>1): #ignore multi lines, output formatting lines, and other information
828 for term in searchTerms:
829 if(term in lineParts[0]):
830 temp = lines[i][lines[i].find(':')+1:].strip()[:-1].strip()
831 if lines[i+1].find(':') != -1:
832 if (len(lines[i+1].split(':')[0][1:].strip())==0):
833 while(len(lines[i][:lines[i].find(':')].strip())>2):
Justin Thaler43030422018-11-08 22:50:21 -0600834 #has multiple lines, process and update line counter
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600835 if((i+1) <= len(lines)):
836 i+=1
837 else:
838 i=i-1
839 break
Justin Thaler43030422018-11-08 22:50:21 -0600840 #Append the content from the next line removing the pretty display characters
841 #Finds the first colon then starts 2 characters after, then removes all whitespace
842 temp = temp + lines[i][lines[i].find(':')+2:].strip()[:-1].strip()[:-1].strip()
Justin Thaler22b1bb52018-03-15 13:31:32 -0500843 if(searchTerms[term] in eselParts):
844 eselParts[searchTerms[term]] = eselParts[searchTerms[term]] + ", " + temp
845 else:
846 eselParts[searchTerms[term]] = temp
Justin Thalercf1deae2018-05-25 19:35:21 -0500847 os.remove(eselBinPath)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600848 else:
849 print("errl file cannot be found")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600850
851 return eselParts
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600852
Justin Thalere412dc22018-01-12 16:28:24 -0600853
Matt Spinler02d0dff2018-08-29 13:19:25 -0500854def getESELSeverity(esel):
855 """
856 Finds the severity type in an eSEL from the User Header section.
857 @param esel - the eSEL data
858 @return severity - e.g. 'Critical'
859 """
860
861 # everything but 1 and 2 are Critical
862 # '1': 'recovered',
863 # '2': 'predictive',
864 # '4': 'unrecoverable',
865 # '5': 'critical',
866 # '6': 'diagnostic',
867 # '7': 'symptom'
868 severities = {
869 '1': 'Informational',
870 '2': 'Warning'
871 }
872
873 try:
874 headerPosition = esel.index('55 48') # 'UH'
875 # The severity is the last byte in the 8 byte section (a byte is ' bb')
876 severity = esel[headerPosition:headerPosition+32].split(' ')[-1]
877 type = severity[0]
878 except ValueError:
879 print("Could not find severity value in UH section in eSEL")
880 type = 'x';
881
882 return severities.get(type, 'Critical')
883
884
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600885def sortSELs(events):
Justin Thalere412dc22018-01-12 16:28:24 -0600886 """
887 sorts the sels by timestamp, then log entry number
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600888
Justin Thalere412dc22018-01-12 16:28:24 -0600889 @param events: Dictionary containing events
890 @return: list containing a list of the ordered log entries, and dictionary of keys
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600891 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600892 logNumList = []
893 timestampList = []
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600894 eventKeyDict = {}
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600895 eventsWithTimestamp = {}
896 logNum2events = {}
897 for key in events:
898 if key == 'numAlerts': continue
899 if 'callout' in key: continue
900 timestamp = (events[key]['timestamp'])
901 if timestamp not in timestampList:
902 eventsWithTimestamp[timestamp] = [events[key]['logNum']]
903 else:
904 eventsWithTimestamp[timestamp].append(events[key]['logNum'])
905 #map logNumbers to the event dictionary keys
906 eventKeyDict[str(events[key]['logNum'])] = key
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600907
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600908 timestampList = list(eventsWithTimestamp.keys())
909 timestampList.sort()
910 for ts in timestampList:
911 if len(eventsWithTimestamp[ts]) > 1:
912 tmplist = eventsWithTimestamp[ts]
913 tmplist.sort()
914 logNumList = logNumList + tmplist
915 else:
916 logNumList = logNumList + eventsWithTimestamp[ts]
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600917
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600918 return [logNumList, eventKeyDict]
919
Justin Thalere412dc22018-01-12 16:28:24 -0600920
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600921def parseAlerts(policyTable, selEntries, args):
Justin Thalere412dc22018-01-12 16:28:24 -0600922 """
923 parses alerts in the IBM CER format, using an IBM policy Table
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600924
Justin Thalere412dc22018-01-12 16:28:24 -0600925 @param policyTable: dictionary, the policy table entries
926 @param selEntries: dictionary, the alerts retrieved from the bmc
927 @return: A dictionary of the parsed entries, in chronological order
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600928 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600929 eventDict = {}
930 eventNum =""
931 count = 0
932 esel = ""
933 eselParts = {}
934 i2cdevice= ""
Matt Spinler02d0dff2018-08-29 13:19:25 -0500935 eselSeverity = None
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600936
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600937 'prepare and sort the event entries'
Justin Thaler667f87c2020-04-06 16:13:12 -0500938 sels = {}
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600939 for key in selEntries:
Justin Thaler667f87c2020-04-06 16:13:12 -0500940 if '/xyz/openbmc_project/logging/entry/' not in key: continue
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600941 if 'callout' not in key:
Justin Thaler667f87c2020-04-06 16:13:12 -0500942 sels[key] = selEntries[key]
943 sels[key]['logNum'] = key.split('/')[-1]
944 sels[key]['timestamp'] = selEntries[key]['Timestamp']
945 sortedEntries = sortSELs(sels)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600946 logNumList = sortedEntries[0]
947 eventKeyDict = sortedEntries[1]
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600948
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600949 for logNum in logNumList:
950 key = eventKeyDict[logNum]
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600951 hasEsel=False
952 i2creadFail = False
953 if 'callout' in key:
954 continue
955 else:
956 messageID = str(selEntries[key]['Message'])
957 addDataPiece = selEntries[key]['AdditionalData']
958 calloutIndex = 0
959 calloutFound = False
960 for i in range(len(addDataPiece)):
961 if("CALLOUT_INVENTORY_PATH" in addDataPiece[i]):
962 calloutIndex = i
963 calloutFound = True
964 fruCallout = str(addDataPiece[calloutIndex]).split('=')[1]
965 if("CALLOUT_DEVICE_PATH" in addDataPiece[i]):
966 i2creadFail = True
Matt Spinlerd178a472018-08-31 09:48:52 -0500967
968 fruCallout = str(addDataPiece[calloutIndex]).split('=')[1]
969
970 # Fall back to "I2C"/"FSI" if dev path isn't in policy table
971 if (messageID + '||' + fruCallout) not in policyTable:
972 i2cdevice = str(addDataPiece[i]).strip().split('=')[1]
973 i2cdevice = '/'.join(i2cdevice.split('/')[-4:])
974 if 'fsi' in str(addDataPiece[calloutIndex]).split('=')[1]:
975 fruCallout = 'FSI'
976 else:
977 fruCallout = 'I2C'
Justin Thalere34c43a2018-05-25 19:37:55 -0500978 calloutFound = True
979 if("CALLOUT_GPIO_NUM" in addDataPiece[i]):
980 if not calloutFound:
981 fruCallout = 'GPIO'
982 calloutFound = True
983 if("CALLOUT_IIC_BUS" in addDataPiece[i]):
984 if not calloutFound:
985 fruCallout = "I2C"
986 calloutFound = True
987 if("CALLOUT_IPMI_SENSOR_NUM" in addDataPiece[i]):
988 if not calloutFound:
989 fruCallout = "IPMI"
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600990 calloutFound = True
991 if("ESEL" in addDataPiece[i]):
992 esel = str(addDataPiece[i]).strip().split('=')[1]
Matt Spinler02d0dff2018-08-29 13:19:25 -0500993 eselSeverity = getESELSeverity(esel)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600994 if args.devdebug:
995 eselParts = parseESEL(args, esel)
996 hasEsel=True
997 if("GPU" in addDataPiece[i]):
998 fruCallout = '/xyz/openbmc_project/inventory/system/chassis/motherboard/gpu' + str(addDataPiece[i]).strip()[-1]
999 calloutFound = True
1000 if("PROCEDURE" in addDataPiece[i]):
1001 fruCallout = str(hex(int(str(addDataPiece[i]).split('=')[1])))[2:]
1002 calloutFound = True
Justin Thalere412dc22018-01-12 16:28:24 -06001003 if("RAIL_NAME" in addDataPiece[i]):
1004 calloutFound=True
1005 fruCallout = str(addDataPiece[i]).split('=')[1].strip()
1006 if("INPUT_NAME" in addDataPiece[i]):
1007 calloutFound=True
1008 fruCallout = str(addDataPiece[i]).split('=')[1].strip()
1009 if("SENSOR_TYPE" in addDataPiece[i]):
1010 calloutFound=True
1011 fruCallout = str(addDataPiece[i]).split('=')[1].strip()
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001012
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001013 if(calloutFound):
Justin Thaler667f87c2020-04-06 16:13:12 -05001014 if fruCallout.strip() != "":
Justin Thaler22b1bb52018-03-15 13:31:32 -05001015 policyKey = messageID +"||" + fruCallout
Matt Spinler02d0dff2018-08-29 13:19:25 -05001016
1017 # Also use the severity for hostboot errors
1018 if eselSeverity and messageID == 'org.open_power.Host.Error.Event':
1019 policyKey += '||' + eselSeverity
1020
1021 # if not in the table, fall back to the original key
1022 if policyKey not in policyTable:
1023 policyKey = policyKey.replace('||'+eselSeverity, '')
1024
Justin Thalere34c43a2018-05-25 19:37:55 -05001025 if policyKey not in policyTable:
1026 policyKey = messageID
Justin Thaler22b1bb52018-03-15 13:31:32 -05001027 else:
1028 policyKey = messageID
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001029 else:
1030 policyKey = messageID
1031 event = {}
1032 eventNum = str(count)
1033 if policyKey in policyTable:
1034 for pkey in policyTable[policyKey]:
1035 if(type(policyTable[policyKey][pkey])== bool):
1036 event[pkey] = boolToString(policyTable[policyKey][pkey])
1037 else:
1038 if (i2creadFail and pkey == 'Message'):
1039 event[pkey] = policyTable[policyKey][pkey] + ' ' +i2cdevice
1040 else:
1041 event[pkey] = policyTable[policyKey][pkey]
1042 event['timestamp'] = selEntries[key]['Timestamp']
1043 event['resolved'] = bool(selEntries[key]['Resolved'])
1044 if(hasEsel):
1045 if args.devdebug:
1046 event['eselParts'] = eselParts
1047 event['raweSEL'] = esel
1048 event['logNum'] = key.split('/')[-1]
1049 eventDict['event' + eventNum] = event
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001050
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001051 else:
1052 severity = str(selEntries[key]['Severity']).split('.')[-1]
1053 if severity == 'Error':
1054 severity = 'Critical'
1055 eventDict['event'+eventNum] = {}
1056 eventDict['event' + eventNum]['error'] = "error: Not found in policy table: " + policyKey
1057 eventDict['event' + eventNum]['timestamp'] = selEntries[key]['Timestamp']
1058 eventDict['event' + eventNum]['Severity'] = severity
1059 if(hasEsel):
1060 if args.devdebug:
1061 eventDict['event' +eventNum]['eselParts'] = eselParts
1062 eventDict['event' +eventNum]['raweSEL'] = esel
1063 eventDict['event' +eventNum]['logNum'] = key.split('/')[-1]
1064 eventDict['event' +eventNum]['resolved'] = bool(selEntries[key]['Resolved'])
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001065 count += 1
1066 return eventDict
1067
1068
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001069def selDisplay(events, args):
Justin Thalere412dc22018-01-12 16:28:24 -06001070 """
1071 displays alerts in human readable format
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001072
Justin Thalere412dc22018-01-12 16:28:24 -06001073 @param events: Dictionary containing events
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001074 @return:
1075 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001076 activeAlerts = []
1077 historyAlerts = []
1078 sortedEntries = sortSELs(events)
1079 logNumList = sortedEntries[0]
1080 eventKeyDict = sortedEntries[1]
1081 keylist = ['Entry', 'ID', 'Timestamp', 'Serviceable', 'Severity','Message']
1082 if(args.devdebug):
1083 colNames = ['Entry', 'ID', 'Timestamp', 'Serviceable', 'Severity','Message', 'eSEL contents']
1084 keylist.append('eSEL')
1085 else:
1086 colNames = ['Entry', 'ID', 'Timestamp', 'Serviceable', 'Severity', 'Message']
1087 for log in logNumList:
1088 selDict = {}
1089 alert = events[eventKeyDict[str(log)]]
1090 if('error' in alert):
1091 selDict['Entry'] = alert['logNum']
1092 selDict['ID'] = 'Unknown'
1093 selDict['Timestamp'] = datetime.datetime.fromtimestamp(int(alert['timestamp']/1000)).strftime("%Y-%m-%d %H:%M:%S")
1094 msg = alert['error']
1095 polMsg = msg.split("policy table:")[0]
1096 msg = msg.split("policy table:")[1]
1097 msgPieces = msg.split("||")
1098 err = msgPieces[0]
1099 if(err.find("org.open_power.")!=-1):
1100 err = err.split("org.open_power.")[1]
1101 elif(err.find("xyz.openbmc_project.")!=-1):
1102 err = err.split("xyz.openbmc_project.")[1]
1103 else:
1104 err = msgPieces[0]
1105 callout = ""
1106 if len(msgPieces) >1:
1107 callout = msgPieces[1]
1108 if(callout.find("/org/open_power/")!=-1):
1109 callout = callout.split("/org/open_power/")[1]
1110 elif(callout.find("/xyz/openbmc_project/")!=-1):
1111 callout = callout.split("/xyz/openbmc_project/")[1]
1112 else:
1113 callout = msgPieces[1]
1114 selDict['Message'] = polMsg +"policy table: "+ err + "||" + callout
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001115 selDict['Serviceable'] = 'Unknown'
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001116 selDict['Severity'] = alert['Severity']
1117 else:
1118 selDict['Entry'] = alert['logNum']
1119 selDict['ID'] = alert['CommonEventID']
1120 selDict['Timestamp'] = datetime.datetime.fromtimestamp(int(alert['timestamp']/1000)).strftime("%Y-%m-%d %H:%M:%S")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001121 selDict['Message'] = alert['Message']
1122 selDict['Serviceable'] = alert['Serviceable']
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001123 selDict['Severity'] = alert['Severity']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001124
1125
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001126 eselOrder = ['refCode','signatureDescription', 'eselType', 'devdesc', 'calloutType', 'procedure']
1127 if ('eselParts' in alert and args.devdebug):
1128 eselOutput = ""
1129 for item in eselOrder:
1130 if item in alert['eselParts']:
1131 eselOutput = eselOutput + item + ": " + alert['eselParts'][item] + " | "
1132 selDict['eSEL'] = eselOutput
1133 else:
1134 if args.devdebug:
1135 selDict['eSEL'] = "None"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001136
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001137 if not alert['resolved']:
1138 activeAlerts.append(selDict)
1139 else:
1140 historyAlerts.append(selDict)
1141 mergedOutput = activeAlerts + historyAlerts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001142 colWidth = setColWidth(keylist, len(colNames), dict(enumerate(mergedOutput)), colNames)
1143
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001144 output = ""
1145 if(len(activeAlerts)>0):
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001146 row = ""
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001147 output +="----Active Alerts----\n"
1148 for i in range(0, len(colNames)):
1149 if i!=0: row =row + "| "
1150 row = row + colNames[i].ljust(colWidth[i])
1151 output += row + "\n"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001152
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001153 for i in range(0,len(activeAlerts)):
1154 row = ""
1155 for j in range(len(activeAlerts[i])):
1156 if (j != 0): row = row + "| "
1157 row = row + activeAlerts[i][keylist[j]].ljust(colWidth[j])
1158 output += row + "\n"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001159
1160 if(len(historyAlerts)>0):
1161 row = ""
1162 output+= "----Historical Alerts----\n"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001163 for i in range(len(colNames)):
1164 if i!=0: row =row + "| "
1165 row = row + colNames[i].ljust(colWidth[i])
1166 output += row + "\n"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001167
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001168 for i in range(0, len(historyAlerts)):
1169 row = ""
1170 for j in range(len(historyAlerts[i])):
1171 if (j != 0): row = row + "| "
1172 row = row + historyAlerts[i][keylist[j]].ljust(colWidth[j])
1173 output += row + "\n"
1174# print(events[eventKeyDict[str(log)]])
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001175 return output
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001176
Justin Thalere412dc22018-01-12 16:28:24 -06001177
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001178def selPrint(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001179 """
1180 prints out all bmc alerts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001181
Justin Thalere412dc22018-01-12 16:28:24 -06001182 @param host: string, the hostname or IP address of the bmc
1183 @param args: contains additional arguments used by the fru sub command
1184 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001185 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1186 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001187 if(args.policyTableLoc is None):
1188 if os.path.exists('policyTable.json'):
1189 ptableLoc = "policyTable.json"
1190 elif os.path.exists('/opt/ibm/ras/lib/policyTable.json'):
1191 ptableLoc = '/opt/ibm/ras/lib/policyTable.json'
1192 else:
1193 ptableLoc = 'lib/policyTable.json'
1194 else:
1195 ptableLoc = args.policyTableLoc
1196 policyTable = loadPolicyTable(ptableLoc)
1197 rawselEntries = ""
1198 if(hasattr(args, 'fileloc') and args.fileloc is not None):
1199 if os.path.exists(args.fileloc):
1200 with open(args.fileloc, 'r') as selFile:
1201 selLines = selFile.readlines()
1202 rawselEntries = ''.join(selLines)
1203 else:
1204 print("Error: File not found")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001205 sys.exit(1)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001206 else:
1207 rawselEntries = sel(host, args, session)
1208 loadFailed = False
1209 try:
1210 selEntries = json.loads(rawselEntries)
1211 except ValueError:
1212 loadFailed = True
1213 if loadFailed:
1214 cleanSels = json.dumps(rawselEntries).replace('\\n', '')
1215 #need to load json twice as original content was string escaped a second time
1216 selEntries = json.loads(json.loads(cleanSels))
1217 selEntries = selEntries['data']
Justin Thalere412dc22018-01-12 16:28:24 -06001218
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001219 if 'description' in selEntries:
1220 if(args.json):
1221 return("{\n\t\"numAlerts\": 0\n}")
1222 else:
1223 return("No log entries found")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001224
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001225 else:
1226 if(len(policyTable)>0):
1227 events = parseAlerts(policyTable, selEntries, args)
1228 if(args.json):
1229 events["numAlerts"] = len(events)
1230 retValue = str(json.dumps(events, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False))
1231 return retValue
1232 elif(hasattr(args, 'fullSel')):
1233 return events
1234 else:
1235 #get log numbers to order event entries sequentially
1236 return selDisplay(events, args)
1237 else:
1238 if(args.json):
1239 return selEntries
1240 else:
1241 print("error: Policy Table not found.")
1242 return selEntries
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001243
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001244def selList(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001245 """
1246 prints out all all bmc alerts, or only prints out the specified alerts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001247
Justin Thalere412dc22018-01-12 16:28:24 -06001248 @param host: string, the hostname or IP address of the bmc
1249 @param args: contains additional arguments used by the fru sub command
1250 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001251 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1252 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001253 return(sel(host, args, session))
1254
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001255
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001256def selClear(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001257 """
1258 clears all alerts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001259
Justin Thalere412dc22018-01-12 16:28:24 -06001260 @param host: string, the hostname or IP address of the bmc
1261 @param args: contains additional arguments used by the fru sub command
1262 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001263 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1264 """
Matt Spinler47b13e92019-01-04 14:58:53 -06001265 url="https://"+host+"/xyz/openbmc_project/logging/action/DeleteAll"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001266 data = "{\"data\": [] }"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001267
Justin Thalere412dc22018-01-12 16:28:24 -06001268 try:
Justin Thaler27197622019-01-23 14:42:11 -06001269 res = session.post(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001270 except(requests.exceptions.Timeout):
1271 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001272 if res.status_code == 200:
1273 return "The Alert Log has been cleared. Please allow a few minutes for the action to complete."
1274 else:
1275 print("Unable to clear the logs, trying to clear 1 at a time")
1276 sels = json.loads(sel(host, args, session))['data']
1277 for key in sels:
1278 if 'callout' not in key:
1279 logNum = key.split('/')[-1]
1280 url = "https://"+ host+ "/xyz/openbmc_project/logging/entry/"+logNum+"/action/Delete"
1281 try:
Justin Thaler27197622019-01-23 14:42:11 -06001282 session.post(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001283 except(requests.exceptions.Timeout):
1284 return connectionErrHandler(args.json, "Timeout", None)
1285 sys.exit(1)
1286 except(requests.exceptions.ConnectionError) as err:
1287 return connectionErrHandler(args.json, "ConnectionError", err)
1288 sys.exit(1)
1289 return ('Sel clearing complete')
1290
1291def selSetResolved(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001292 """
1293 sets a sel entry to resolved
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001294
Justin Thalere412dc22018-01-12 16:28:24 -06001295 @param host: string, the hostname or IP address of the bmc
1296 @param args: contains additional arguments used by the fru sub command
1297 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001298 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1299 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001300 url="https://"+host+"/xyz/openbmc_project/logging/entry/" + str(args.selNum) + "/attr/Resolved"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001301 data = "{\"data\": 1 }"
Justin Thalere412dc22018-01-12 16:28:24 -06001302 try:
Justin Thaler27197622019-01-23 14:42:11 -06001303 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001304 except(requests.exceptions.Timeout):
1305 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001306 if res.status_code == 200:
1307 return "Sel entry "+ str(args.selNum) +" is now set to resolved"
1308 else:
1309 return "Unable to set the alert to resolved"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001310
Justin Thalere412dc22018-01-12 16:28:24 -06001311def selResolveAll(host, args, session):
1312 """
1313 sets a sel entry to resolved
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001314
Justin Thalere412dc22018-01-12 16:28:24 -06001315 @param host: string, the hostname or IP address of the bmc
1316 @param args: contains additional arguments used by the fru sub command
1317 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001318 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1319 """
Justin Thalere412dc22018-01-12 16:28:24 -06001320 rawselEntries = sel(host, args, session)
1321 loadFailed = False
1322 try:
1323 selEntries = json.loads(rawselEntries)
1324 except ValueError:
1325 loadFailed = True
1326 if loadFailed:
1327 cleanSels = json.dumps(rawselEntries).replace('\\n', '')
1328 #need to load json twice as original content was string escaped a second time
1329 selEntries = json.loads(json.loads(cleanSels))
1330 selEntries = selEntries['data']
1331
1332 if 'description' in selEntries:
1333 if(args.json):
1334 return("{\n\t\"selsResolved\": 0\n}")
1335 else:
1336 return("No log entries found")
1337 else:
1338 d = vars(args)
1339 successlist = []
1340 failedlist = []
1341 for key in selEntries:
1342 if 'callout' not in key:
1343 d['selNum'] = key.split('/')[-1]
1344 resolved = selSetResolved(host,args,session)
1345 if 'Sel entry' in resolved:
1346 successlist.append(d['selNum'])
1347 else:
1348 failedlist.append(d['selNum'])
1349 output = ""
1350 successlist.sort()
1351 failedlist.sort()
1352 if len(successlist)>0:
1353 output = "Successfully resolved: " +', '.join(successlist) +"\n"
1354 if len(failedlist)>0:
1355 output += "Failed to resolve: " + ', '.join(failedlist) + "\n"
1356 return output
1357
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001358def chassisPower(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001359 """
1360 called by the chassis function. Controls the power state of the chassis, or gets the status
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001361
Justin Thalere412dc22018-01-12 16:28:24 -06001362 @param host: string, the hostname or IP address of the bmc
1363 @param args: contains additional arguments used by the fru sub command
1364 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001365 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1366 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001367 if(args.powcmd == 'on'):
Justin Thaler22b1bb52018-03-15 13:31:32 -05001368 if checkFWactivation(host, args, session):
1369 return ("Chassis Power control disabled during firmware activation")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001370 print("Attempting to Power on...:")
1371 url="https://"+host+"/xyz/openbmc_project/state/host0/attr/RequestedHostTransition"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001372 data = '{"data":"xyz.openbmc_project.State.Host.Transition.On"}'
Justin Thalere412dc22018-01-12 16:28:24 -06001373 try:
Justin Thaler27197622019-01-23 14:42:11 -06001374 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001375 except(requests.exceptions.Timeout):
1376 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001377 return res.text
Justin Thalere412dc22018-01-12 16:28:24 -06001378 elif(args.powcmd == 'softoff'):
Justin Thaler22b1bb52018-03-15 13:31:32 -05001379 if checkFWactivation(host, args, session):
1380 return ("Chassis Power control disabled during firmware activation")
Justin Thalere412dc22018-01-12 16:28:24 -06001381 print("Attempting to Power off gracefully...:")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001382 url="https://"+host+"/xyz/openbmc_project/state/host0/attr/RequestedHostTransition"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001383 data = '{"data":"xyz.openbmc_project.State.Host.Transition.Off"}'
Justin Thalere412dc22018-01-12 16:28:24 -06001384 try:
Justin Thaler27197622019-01-23 14:42:11 -06001385 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001386 except(requests.exceptions.Timeout):
1387 return(connectionErrHandler(args.json, "Timeout", None))
1388 return res.text
1389 elif(args.powcmd == 'hardoff'):
Justin Thaler22b1bb52018-03-15 13:31:32 -05001390 if checkFWactivation(host, args, session):
1391 return ("Chassis Power control disabled during firmware activation")
Justin Thalere412dc22018-01-12 16:28:24 -06001392 print("Attempting to Power off immediately...:")
1393 url="https://"+host+"/xyz/openbmc_project/state/chassis0/attr/RequestedPowerTransition"
Justin Thalere412dc22018-01-12 16:28:24 -06001394 data = '{"data":"xyz.openbmc_project.State.Chassis.Transition.Off"}'
1395 try:
Justin Thaler27197622019-01-23 14:42:11 -06001396 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001397 except(requests.exceptions.Timeout):
1398 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001399 return res.text
1400 elif(args.powcmd == 'status'):
1401 url="https://"+host+"/xyz/openbmc_project/state/chassis0/attr/CurrentPowerState"
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 chassisState = json.loads(res.text)['data'].split('.')[-1]
1407 url="https://"+host+"/xyz/openbmc_project/state/host0/attr/CurrentHostState"
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 hostState = json.loads(res.text)['data'].split('.')[-1]
1413 url="https://"+host+"/xyz/openbmc_project/state/bmc0/attr/CurrentBMCState"
Justin Thalere412dc22018-01-12 16:28:24 -06001414 try:
Justin Thaler27197622019-01-23 14:42:11 -06001415 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001416 except(requests.exceptions.Timeout):
1417 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001418 bmcState = json.loads(res.text)['data'].split('.')[-1]
1419 if(args.json):
1420 outDict = {"Chassis Power State" : chassisState, "Host Power State" : hostState, "BMC Power State":bmcState}
1421 return json.dumps(outDict, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False)
1422 else:
1423 return "Chassis Power State: " +chassisState + "\nHost Power State: " + hostState + "\nBMC Power State: " + bmcState
1424 else:
1425 return "Invalid chassis power command"
1426
Justin Thalere412dc22018-01-12 16:28:24 -06001427
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001428def chassisIdent(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001429 """
1430 called by the chassis function. Controls the identify led of the chassis. Sets or gets the state
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001431
Justin Thalere412dc22018-01-12 16:28:24 -06001432 @param host: string, the hostname or IP address of the bmc
1433 @param args: contains additional arguments used by the fru sub command
1434 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001435 @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 -06001436 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001437 if(args.identcmd == 'on'):
1438 print("Attempting to turn identify light on...:")
1439 url="https://"+host+"/xyz/openbmc_project/led/groups/enclosure_identify/attr/Asserted"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001440 data = '{"data":true}'
Justin Thalere412dc22018-01-12 16:28:24 -06001441 try:
Justin Thaler27197622019-01-23 14:42:11 -06001442 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001443 except(requests.exceptions.Timeout):
1444 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001445 return res.text
1446 elif(args.identcmd == 'off'):
1447 print("Attempting to turn identify light off...:")
1448 url="https://"+host+"/xyz/openbmc_project/led/groups/enclosure_identify/attr/Asserted"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001449 data = '{"data":false}'
Justin Thalere412dc22018-01-12 16:28:24 -06001450 try:
Justin Thaler27197622019-01-23 14:42:11 -06001451 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001452 except(requests.exceptions.Timeout):
1453 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001454 return res.text
1455 elif(args.identcmd == 'status'):
1456 url="https://"+host+"/xyz/openbmc_project/led/groups/enclosure_identify"
Justin Thalere412dc22018-01-12 16:28:24 -06001457 try:
Justin Thaler27197622019-01-23 14:42:11 -06001458 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001459 except(requests.exceptions.Timeout):
1460 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001461 status = json.loads(res.text)['data']
1462 if(args.json):
1463 return status
1464 else:
1465 if status['Asserted'] == 0:
1466 return "Identify light is off"
1467 else:
1468 return "Identify light is blinking"
1469 else:
1470 return "Invalid chassis identify command"
1471
Justin Thalere412dc22018-01-12 16:28:24 -06001472
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001473def chassis(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001474 """
1475 controls the different chassis commands
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001476
Justin Thalere412dc22018-01-12 16:28:24 -06001477 @param host: string, the hostname or IP address of the bmc
1478 @param args: contains additional arguments used by the fru sub command
1479 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001480 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1481 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001482 if(hasattr(args, 'powcmd')):
1483 result = chassisPower(host,args,session)
1484 elif(hasattr(args, 'identcmd')):
1485 result = chassisIdent(host, args, session)
1486 else:
Justin Thaler22b1bb52018-03-15 13:31:32 -05001487 return "This feature is not yet implemented"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001488 return result
Justin Thalere412dc22018-01-12 16:28:24 -06001489
Ravi Tejad8be0b42020-03-18 14:31:46 -05001490def dumpRetrieve(host, args, session):
1491 """
1492 Downloads dump of given dump type
1493
1494 @param host: string, the hostname or IP address of the bmc
1495 @param args: contains additional arguments used by the collectServiceData sub command
1496 @param session: the active session to use
1497 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1498 """
1499 dumpType = args.dumpType
1500 if (args.dumpType=="SystemDump"):
1501 dumpResp=systemDumpRetrieve(host,args,session)
1502 elif(args.dumpType=="bmc"):
1503 dumpResp=bmcDumpRetrieve(host,args,session)
1504 return dumpResp
1505
1506def dumpList(host, args, session):
1507 """
1508 Lists dump of the given dump type
1509
1510 @param host: string, the hostname or IP address of the bmc
1511 @param args: contains additional arguments used by the collectServiceData sub command
1512 @param session: the active session to use
1513 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1514 """
1515 if (args.dumpType=="SystemDump"):
1516 dumpResp=systemDumpList(host,args,session)
1517 elif(args.dumpType=="bmc"):
1518 dumpResp=bmcDumpList(host,args,session)
1519 return dumpResp
1520
1521def dumpDelete(host, args, session):
1522 """
1523 Deletes dump of the given dump type
1524
1525 @param host: string, the hostname or IP address of the bmc
1526 @param args: contains additional arguments used by the collectServiceData sub command
1527 @param session: the active session to use
1528 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1529 """
1530 if (args.dumpType=="SystemDump"):
1531 dumpResp=systemDumpDelete(host,args,session)
1532 elif(args.dumpType=="bmc"):
1533 dumpResp=bmcDumpDelete(host,args,session)
1534 return dumpResp
1535
1536def dumpDeleteAll(host, args, session):
1537 """
1538 Deletes all dumps of the given dump type
1539
1540 @param host: string, the hostname or IP address of the bmc
1541 @param args: contains additional arguments used by the collectServiceData sub command
1542 @param session: the active session to use
1543 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1544 """
1545 if (args.dumpType=="SystemDump"):
1546 dumpResp=systemDumpDeleteAll(host,args,session)
1547 elif(args.dumpType=="bmc"):
1548 dumpResp=bmcDumpDeleteAll(host,args,session)
1549 return dumpResp
1550
1551def dumpCreate(host, args, session):
1552 """
1553 Creates dump for the given dump type
1554
1555 @param host: string, the hostname or IP address of the bmc
1556 @param args: contains additional arguments used by the collectServiceData sub command
1557 @param session: the active session to use
1558 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1559 """
1560 if (args.dumpType=="SystemDump"):
1561 dumpResp=systemDumpCreate(host,args,session)
1562 elif(args.dumpType=="bmc"):
Justin Thaler0a3e1692020-04-07 19:10:40 -05001563 dumpResp=bmcDumpCreate(host,args,session)
Ravi Tejad8be0b42020-03-18 14:31:46 -05001564 return dumpResp
1565
1566
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001567def bmcDumpRetrieve(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001568 """
1569 Downloads a dump file from the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001570
Justin Thalere412dc22018-01-12 16:28:24 -06001571 @param host: string, the hostname or IP address of the bmc
1572 @param args: contains additional arguments used by the collectServiceData sub command
1573 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001574 @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 -06001575 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001576 dumpNum = args.dumpNum
1577 if (args.dumpSaveLoc is not None):
1578 saveLoc = args.dumpSaveLoc
1579 else:
Justin Thalercf1deae2018-05-25 19:35:21 -05001580 saveLoc = tempfile.gettempdir()
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001581 url ='https://'+host+'/download/dump/' + str(dumpNum)
1582 try:
Justin Thaler27197622019-01-23 14:42:11 -06001583 r = session.get(url, headers=jsonHeader, stream=True, verify=False, timeout=baseTimeout)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001584 if (args.dumpSaveLoc is not None):
1585 if os.path.exists(saveLoc):
1586 if saveLoc[-1] != os.path.sep:
1587 saveLoc = saveLoc + os.path.sep
1588 filename = saveLoc + host+'-dump' + str(dumpNum) + '.tar.xz'
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001589
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001590 else:
1591 return 'Invalid save location specified'
1592 else:
Justin Thalercf1deae2018-05-25 19:35:21 -05001593 filename = tempfile.gettempdir()+os.sep + host+'-dump' + str(dumpNum) + '.tar.xz'
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001594
1595 with open(filename, 'wb') as f:
1596 for chunk in r.iter_content(chunk_size =1024):
1597 if chunk:
1598 f.write(chunk)
1599 return 'Saved as ' + filename
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001600
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001601 except(requests.exceptions.Timeout):
1602 return connectionErrHandler(args.json, "Timeout", None)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001603
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001604 except(requests.exceptions.ConnectionError) as err:
1605 return connectionErrHandler(args.json, "ConnectionError", err)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001606
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001607def bmcDumpList(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001608 """
1609 Lists the number of dump files on the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001610
Justin Thalere412dc22018-01-12 16:28:24 -06001611 @param host: string, the hostname or IP address of the bmc
1612 @param args: contains additional arguments used by the collectServiceData sub command
1613 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001614 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1615 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001616 url ='https://'+host+'/xyz/openbmc_project/dump/list'
1617 try:
Justin Thaler27197622019-01-23 14:42:11 -06001618 r = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thaler3a5771b2019-01-23 14:31:52 -06001619 dumpList = r.json()
Justin Thaler3b3c6582020-04-07 19:17:36 -05001620 formattedList = []
1621 #remove items that aren't dump entries 'entry, internal, manager endpoints'
1622 if 'data' in dumpList:
1623 for entry in dumpList['data']:
1624 if 'entry' in entry:
1625 if entry.split('/')[-1].isnumeric():
1626 formattedList.append(entry)
1627 dumpList['data']= formattedList
Justin Thaler3a5771b2019-01-23 14:31:52 -06001628 return dumpList
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001629 except(requests.exceptions.Timeout):
1630 return connectionErrHandler(args.json, "Timeout", None)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001631
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001632 except(requests.exceptions.ConnectionError) as err:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001633 return connectionErrHandler(args.json, "ConnectionError", err)
1634
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001635def bmcDumpDelete(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001636 """
1637 Deletes BMC dump files from the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001638
Justin Thalere412dc22018-01-12 16:28:24 -06001639 @param host: string, the hostname or IP address of the bmc
1640 @param args: contains additional arguments used by the collectServiceData sub command
1641 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001642 @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 -06001643 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001644 dumpList = []
1645 successList = []
1646 failedList = []
1647 if args.dumpNum is not None:
1648 if isinstance(args.dumpNum, list):
1649 dumpList = args.dumpNum
1650 else:
1651 dumpList.append(args.dumpNum)
1652 for dumpNum in dumpList:
1653 url ='https://'+host+'/xyz/openbmc_project/dump/entry/'+str(dumpNum)+'/action/Delete'
1654 try:
Justin Thaler27197622019-01-23 14:42:11 -06001655 r = session.post(url, headers=jsonHeader, json = {"data": []}, verify=False, timeout=baseTimeout)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001656 if r.status_code == 200:
1657 successList.append(str(dumpNum))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001658 else:
1659 failedList.append(str(dumpNum))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001660 except(requests.exceptions.Timeout):
1661 return connectionErrHandler(args.json, "Timeout", None)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001662 except(requests.exceptions.ConnectionError) as err:
1663 return connectionErrHandler(args.json, "ConnectionError", err)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001664 output = "Successfully deleted dumps: " + ', '.join(successList)
1665 if(len(failedList)>0):
1666 output+= '\nFailed to delete dumps: ' + ', '.join(failedList)
1667 return output
1668 else:
1669 return 'You must specify an entry number to delete'
1670
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001671def bmcDumpDeleteAll(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001672 """
1673 Deletes All BMC dump files from the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001674
Justin Thalere412dc22018-01-12 16:28:24 -06001675 @param host: string, the hostname or IP address of the bmc
1676 @param args: contains additional arguments used by the collectServiceData sub command
1677 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001678 @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 -06001679 """
1680 dumpResp = bmcDumpList(host, args, session)
1681 if 'FQPSPIN0000M' in dumpResp or 'FQPSPIN0001M'in dumpResp:
1682 return dumpResp
Justin Thaler3a5771b2019-01-23 14:31:52 -06001683 dumpList = dumpResp['data']
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001684 d = vars(args)
1685 dumpNums = []
1686 for dump in dumpList:
Alvin Wang28bd09d2019-10-28 13:23:58 +08001687 dumpNum = dump.strip().split('/')[-1]
1688 if dumpNum.isdigit():
1689 dumpNums.append(int(dumpNum))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001690 d['dumpNum'] = dumpNums
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001691
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001692 return bmcDumpDelete(host, args, session)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001693
Justin Thalere412dc22018-01-12 16:28:24 -06001694
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001695def bmcDumpCreate(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001696 """
1697 Creates a bmc dump file
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001698
Justin Thalere412dc22018-01-12 16:28:24 -06001699 @param host: string, the hostname or IP address of the bmc
1700 @param args: contains additional arguments used by the collectServiceData sub command
1701 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001702 @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 -06001703 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001704 url = 'https://'+host+'/xyz/openbmc_project/dump/action/CreateDump'
1705 try:
Justin Thaler27197622019-01-23 14:42:11 -06001706 r = session.post(url, headers=jsonHeader, json = {"data": []}, verify=False, timeout=baseTimeout)
Justin Thaler2f59aea2020-04-07 19:27:01 -05001707 info = r.json()
Matt Spinlereae05b02019-01-24 12:59:34 -06001708 if(r.status_code == 200 and not args.json):
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001709 return ('Dump successfully created')
Justin Thaler3a5771b2019-01-23 14:31:52 -06001710 elif(args.json):
Justin Thaler2f59aea2020-04-07 19:27:01 -05001711 return info
1712 elif 'data' in info:
1713 if 'QuotaExceeded' in info['data']['description']:
1714 return 'BMC dump space is full. Please delete at least one existing dump entry and try again.'
1715 else:
1716 return "Failed to create a BMC dump. BMC Response:\n {resp}".format(resp=info)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001717 else:
Justin Thaler2f59aea2020-04-07 19:27:01 -05001718 return "Failed to create a BMC dump. BMC Response:\n {resp}".format(resp=info)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001719 except(requests.exceptions.Timeout):
1720 return connectionErrHandler(args.json, "Timeout", None)
1721 except(requests.exceptions.ConnectionError) as err:
1722 return connectionErrHandler(args.json, "ConnectionError", err)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001723
Justin Thaler2f59aea2020-04-07 19:27:01 -05001724
Ravi Tejad8be0b42020-03-18 14:31:46 -05001725def systemDumpRetrieve(host, args, session):
1726 """
1727 Downloads system dump
1728
1729 @param host: string, the hostname or IP address of the bmc
1730 @param args: contains additional arguments used by the collectServiceData sub command
1731 @param session: the active session to use
1732 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1733 """
1734 NBDSetup(host,args,session)
1735 pipe = NBDPipe()
1736 pipe.openHTTPSocket(args)
1737 pipe.openTCPSocket()
1738 pipe.waitformessage()
1739
1740def systemDumpList(host, args, session):
1741 """
1742 Lists system dumps
1743
1744 @param host: string, the hostname or IP address of the bmc
1745 @param args: contains additional arguments used by the collectServiceData sub command
1746 @param session: the active session to use
1747 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1748 """
1749 print("in systemDumpList")
1750 url = "https://"+host+"/redfish/v1/Systems/system/LogServices/"+args.dumpType+"/Entries"
1751 try:
1752 r = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
1753 dumpList = r.json()
1754 return dumpList
1755 except(requests.exceptions.Timeout):
1756 return connectionErrHandler(args.json, "Timeout", None)
1757
1758 except(requests.exceptions.ConnectionError) as err:
1759 return connectionErrHandler(args.json, "ConnectionError", err)
1760
1761
1762def systemDumpDelete(host, args, session):
1763 """
1764 Deletes system dump
1765
1766 @param host: string, the hostname or IP address of the bmc
1767 @param args: contains additional arguments used by the collectServiceData sub command
1768 @param session: the active session to use
1769 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1770 """
1771 dumpList = []
1772 successList = []
1773 failedList = []
1774 if args.dumpNum is not None:
1775 if isinstance(args.dumpNum, list):
1776 dumpList = args.dumpNum
1777 else:
1778 dumpList.append(args.dumpNum)
1779 for dumpNum in dumpList:
1780 url = 'https://'+host+'/redfish/v1/Systems/system/LogServices/'+args.dumpType+'/Entries/'+ str(dumpNum)
1781 try:
1782 r = session.delete(url, headers=jsonHeader, json = {"data": []}, verify=False, timeout=baseTimeout)
1783 if r.status_code == 200:
1784 successList.append(str(dumpNum))
1785 else:
1786 failedList.append(str(dumpNum))
1787 except(requests.exceptions.Timeout):
1788 return connectionErrHandler(args.json, "Timeout", None)
1789 except(requests.exceptions.ConnectionError) as err:
1790 return connectionErrHandler(args.json, "ConnectionError", err)
1791 output = "Successfully deleted dumps: " + ', '.join(successList)
1792 if(len(failedList)>0):
1793 output+= '\nFailed to delete dumps: ' + ', '.join(failedList)
1794 return output
1795 else:
1796 return 'You must specify an entry number to delete'
1797
1798def systemDumpDeleteAll(host, args, session):
1799 """
1800 Deletes All system dumps
1801
1802 @param host: string, the hostname or IP address of the bmc
1803 @param args: contains additional arguments used by the collectServiceData sub command
1804 @param session: the active session to use
1805 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1806 """
1807 url = 'https://'+host+'/redfish/v1/Systems/system/LogServices/'+args.dumpType+'/Actions/LogService.ClearLog'
1808 try:
1809 r = session.post(url, headers=jsonHeader, json = {"data": []}, verify=False, timeout=baseTimeout)
1810 if(r.status_code == 200 and not args.json):
1811 return ('Dumps successfully cleared')
1812 elif(args.json):
1813 return r.json()
1814 else:
1815 return ('Failed to clear dumps')
1816 except(requests.exceptions.Timeout):
1817 return connectionErrHandler(args.json, "Timeout", None)
1818 except(requests.exceptions.ConnectionError) as err:
1819 return connectionErrHandler(args.json, "ConnectionError", err)
1820
1821def systemDumpCreate(host, args, session):
1822 """
1823 Creates a system dump
1824
1825 @param host: string, the hostname or IP address of the bmc
1826 @param args: contains additional arguments used by the collectServiceData sub command
1827 @param session: the active session to use
1828 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1829 """
1830 url = 'https://'+host+'/redfish/v1/Systems/system/LogServices/'+args.dumpType+'/Actions/Oem/Openbmc/LogService.CreateLog'
1831 try:
1832 r = session.post(url, headers=jsonHeader, json = {"data": []}, verify=False, timeout=baseTimeout)
1833 if(r.status_code == 200 and not args.json):
1834 return ('Dump successfully created')
1835 elif(args.json):
1836 return r.json()
1837 else:
1838 return ('Failed to create dump')
1839 except(requests.exceptions.Timeout):
1840 return connectionErrHandler(args.json, "Timeout", None)
1841 except(requests.exceptions.ConnectionError) as err:
1842 return connectionErrHandler(args.json, "ConnectionError", err)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001843
Justin Thaler666cf342019-01-23 14:44:27 -06001844def csdDumpInitiate(host, args, session):
1845 """
1846 Starts the process of getting the current list of dumps then initiates the creation of one.
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001847
Justin Thaler666cf342019-01-23 14:44:27 -06001848 @param host: string, the hostname or IP address of the bmc
1849 @param args: contains additional arguments used by the collectServiceData sub command
1850 @param session: the active session to use
1851 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1852 """
1853 errorInfo = ""
1854 dumpcount = 0
1855 try:
1856 d = vars(args)
1857 d['json'] = True
1858 except Exception as e:
1859 errorInfo += "Failed to set the json flag to True \n Exception: {eInfo}\n".format(eInfo=e)
Justin Thalerb4256672020-04-07 19:38:26 -05001860 exc_type, exc_obj, exc_tb = sys.exc_info()
1861 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
1862 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
1863 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06001864
1865 try:
1866 for i in range(3):
1867 dumpInfo = bmcDumpList(host, args, session)
1868 if 'data' in dumpInfo:
1869 dumpcount = len(dumpInfo['data'])
1870 break
1871 else:
1872 errorInfo+= "Dump List Message returned: " + json.dumps(dumpInfo,indent=0, separators=(',', ':')).replace('\n','') +"\n"
1873 except Exception as e:
1874 errorInfo+= "Failed to collect the list of dumps.\nException: {eInfo}\n".format(eInfo=e)
Justin Thalerb4256672020-04-07 19:38:26 -05001875 exc_type, exc_obj, exc_tb = sys.exc_info()
1876 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
1877 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
1878 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06001879
1880 #Create a user initiated dump
Justin Thalerb4256672020-04-07 19:38:26 -05001881 dumpFailure = True
Justin Thaler666cf342019-01-23 14:44:27 -06001882 try:
1883 for i in range(3):
1884 dumpcreated = bmcDumpCreate(host, args, session)
1885 if 'message' in dumpcreated:
1886 if 'ok' in dumpcreated['message'].lower():
Justin Thalerb4256672020-04-07 19:38:26 -05001887 dumpFailure = False
Justin Thaler666cf342019-01-23 14:44:27 -06001888 break
Justin Thalerb4256672020-04-07 19:38:26 -05001889 elif 'data' in dumpcreated:
1890 if 'QuotaExceeded' in dumpcreated['data']['description']:
1891 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.')
1892 errorInfo+='Dump Space is full. No new dump was created with this collection'
1893 break
1894 else:
1895 errorInfo+= "Dump create message returned: " + json.dumps(dumpcreated,indent=0, separators=(',', ':')).replace('\n','') +"\n"
Justin Thaler666cf342019-01-23 14:44:27 -06001896 else:
Justin Thalerb4256672020-04-07 19:38:26 -05001897 errorInfo+= "Dump create message returned: " + json.dumps(dumpcreated,indent=0, separators=(',', ':')).replace('\n','') +"\n"
Justin Thaler666cf342019-01-23 14:44:27 -06001898 else:
Justin Thalerb4256672020-04-07 19:38:26 -05001899 errorInfo+= "Dump create message returned: " + json.dumps(dumpcreated,indent=0, separators=(',', ':')).replace('\n','') +"\n"
Justin Thaler666cf342019-01-23 14:44:27 -06001900 except Exception as e:
1901 errorInfo+= "Dump create exception encountered: {eInfo}\n".format(eInfo=e)
Justin Thalerb4256672020-04-07 19:38:26 -05001902 exc_type, exc_obj, exc_tb = sys.exc_info()
1903 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
1904 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
1905 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06001906
1907 output = {}
1908 output['errors'] = errorInfo
1909 output['dumpcount'] = dumpcount
Justin Thalerb4256672020-04-07 19:38:26 -05001910 if dumpFailure: output['dumpFailure'] = True
Justin Thaler666cf342019-01-23 14:44:27 -06001911 return output
1912
1913def csdInventory(host, args,session, fileDir):
1914 """
1915 Collects the BMC inventory, retrying if necessary
1916
1917 @param host: string, the hostname or IP address of the bmc
1918 @param args: contains additional arguments used by the collectServiceData sub command
1919 @param session: the active session to use
1920 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1921 @param fileDir: string representation of the path to use for putting files created
1922 """
1923 errorInfo = "===========Inventory =============\n"
1924 output={}
1925 inventoryCollected = False
1926 try:
1927 for i in range(3):
1928 frulist = fruPrint(host, args, session)
1929 if 'Hardware' in frulist:
1930 inventoryCollected = True
1931 break
1932 else:
1933 errorInfo += json.dumps(frulist, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n'
1934 except Exception as e:
1935 errorInfo += "Inventory collection exception: {eInfo}\n".format(eInfo=e)
Justin Thalerb4256672020-04-07 19:38:26 -05001936 exc_type, exc_obj, exc_tb = sys.exc_info()
1937 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
1938 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
1939 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06001940 if inventoryCollected:
1941 try:
1942 with open(fileDir +os.sep+'inventory.txt', 'w') as f:
1943 f.write(json.dumps(frulist, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n')
1944 print("Inventory collected and stored in " + fileDir + os.sep + "inventory.txt")
1945 output['fileLoc'] = fileDir+os.sep+'inventory.txt'
1946 except Exception as e:
1947 print("Failed to write inventory to file.")
1948 errorInfo += "Error writing inventory to the file. Exception: {eInfo}\n".format(eInfo=e)
Justin Thalerb4256672020-04-07 19:38:26 -05001949 exc_type, exc_obj, exc_tb = sys.exc_info()
1950 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
1951 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
1952 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06001953
1954 output['errors'] = errorInfo
1955
1956 return output
1957
1958def csdSensors(host, args,session, fileDir):
1959 """
1960 Collects the BMC sensor readings, retrying if necessary
1961
1962 @param host: string, the hostname or IP address of the bmc
1963 @param args: contains additional arguments used by the collectServiceData sub command
1964 @param session: the active session to use
1965 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1966 @param fileDir: string representation of the path to use for putting files created
1967 """
1968 errorInfo = "===========Sensors =============\n"
1969 sensorsCollected = False
1970 output={}
1971 try:
1972 d = vars(args)
1973 d['json'] = False
1974 except Exception as e:
1975 errorInfo += "Failed to set the json flag to False \n Exception: {eInfo}\n".format(eInfo=e)
Justin Thalerb4256672020-04-07 19:38:26 -05001976 exc_type, exc_obj, exc_tb = sys.exc_info()
1977 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
1978 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
1979 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06001980
1981 try:
1982 for i in range(3):
1983 sensorReadings = sensor(host, args, session)
1984 if 'OCC0' in sensorReadings:
1985 sensorsCollected = True
1986 break
1987 else:
1988 errorInfo += sensorReadings
1989 except Exception as e:
1990 errorInfo += "Sensor reading collection exception: {eInfo}\n".format(eInfo=e)
Justin Thalerb4256672020-04-07 19:38:26 -05001991 exc_type, exc_obj, exc_tb = sys.exc_info()
1992 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
1993 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
1994 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06001995 if sensorsCollected:
1996 try:
1997 with open(fileDir +os.sep+'sensorReadings.txt', 'w') as f:
1998 f.write(sensorReadings)
1999 print("Sensor readings collected and stored in " + fileDir + os.sep+ "sensorReadings.txt")
2000 output['fileLoc'] = fileDir+os.sep+'sensorReadings.txt'
2001 except Exception as e:
2002 print("Failed to write sensor readings to file system.")
2003 errorInfo += "Error writing sensor readings to the file. Exception: {eInfo}\n".format(eInfo=e)
Justin Thalerb4256672020-04-07 19:38:26 -05002004 exc_type, exc_obj, exc_tb = sys.exc_info()
2005 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
2006 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
2007 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06002008
2009 output['errors'] = errorInfo
2010 return output
2011
2012def csdLEDs(host,args, session, fileDir):
2013 """
2014 Collects the BMC LED status, retrying if necessary
2015
2016 @param host: string, the hostname or IP address of the bmc
2017 @param args: contains additional arguments used by the collectServiceData sub command
2018 @param session: the active session to use
2019 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
2020 @param fileDir: string representation of the path to use for putting files created
2021 """
2022 errorInfo = "===========LEDs =============\n"
2023 ledsCollected = False
2024 output={}
2025 try:
2026 d = vars(args)
2027 d['json'] = True
2028 except Exception as e:
2029 errorInfo += "Failed to set the json flag to False \n Exception: {eInfo}\n".format(eInfo=e)
Justin Thalerb4256672020-04-07 19:38:26 -05002030 exc_type, exc_obj, exc_tb = sys.exc_info()
2031 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
2032 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
2033 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06002034 try:
2035 url="https://"+host+"/xyz/openbmc_project/led/enumerate"
2036 httpHeader = {'Content-Type':'application/json'}
2037 for i in range(3):
2038 try:
2039 ledRes = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
2040 if ledRes.status_code == 200:
2041 ledsCollected = True
2042 leds = ledRes.json()['data']
2043 break
2044 else:
2045 errorInfo += ledRes.text
2046 except(requests.exceptions.Timeout):
2047 errorInfo+=json.dumps( connectionErrHandler(args.json, "Timeout", None), sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n'
2048 except(requests.exceptions.ConnectionError) as err:
2049 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 -05002050 exc_type, exc_obj, exc_tb = sys.exc_info()
2051 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
2052 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
2053 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06002054 except Exception as e:
2055 errorInfo += "LED status collection exception: {eInfo}\n".format(eInfo=e)
Justin Thalerb4256672020-04-07 19:38:26 -05002056 exc_type, exc_obj, exc_tb = sys.exc_info()
2057 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
2058 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
2059 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06002060
2061 if ledsCollected:
2062 try:
2063 with open(fileDir +os.sep+'ledStatus.txt', 'w') as f:
2064 f.write(json.dumps(leds, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n')
2065 print("LED status collected and stored in " + fileDir + os.sep+ "ledStatus.txt")
2066 output['fileLoc'] = fileDir+os.sep+'ledStatus.txt'
2067 except Exception as e:
2068 print("Failed to write LED status to file system.")
2069 errorInfo += "Error writing LED status to the file. Exception: {eInfo}\n".format(eInfo=e)
Justin Thalerb4256672020-04-07 19:38:26 -05002070 exc_type, exc_obj, exc_tb = sys.exc_info()
2071 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
2072 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
2073 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06002074
2075 output['errors'] = errorInfo
2076 return output
2077
2078def csdSelShortList(host, args, session, fileDir):
2079 """
2080 Collects the BMC log entries, retrying if necessary
2081
2082 @param host: string, the hostname or IP address of the bmc
2083 @param args: contains additional arguments used by the collectServiceData sub command
2084 @param session: the active session to use
2085 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
2086 @param fileDir: string representation of the path to use for putting files created
2087 """
2088 errorInfo = "===========SEL Short List =============\n"
2089 selsCollected = False
2090 output={}
2091 try:
2092 d = vars(args)
2093 d['json'] = False
2094 except Exception as e:
2095 errorInfo += "Failed to set the json flag to False \n Exception: {eInfo}\n".format(eInfo=e)
Justin Thalerb4256672020-04-07 19:38:26 -05002096 exc_type, exc_obj, exc_tb = sys.exc_info()
2097 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
2098 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
2099 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06002100
2101 try:
2102 for i in range(3):
2103 sels = selPrint(host,args,session)
2104 if '----Active Alerts----' in sels or 'No log entries found' in sels or '----Historical Alerts----' in sels:
2105 selsCollected = True
2106 break
2107 else:
2108 errorInfo += sels + '\n'
2109 except Exception as e:
2110 errorInfo += "SEL short list collection exception: {eInfo}\n".format(eInfo=e)
Justin Thalerb4256672020-04-07 19:38:26 -05002111 exc_type, exc_obj, exc_tb = sys.exc_info()
2112 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
2113 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
2114 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06002115
2116 if selsCollected:
2117 try:
2118 with open(fileDir +os.sep+'SELshortlist.txt', 'w') as f:
2119 f.write(sels)
2120 print("SEL short list collected and stored in " + fileDir + os.sep+ "SELshortlist.txt")
2121 output['fileLoc'] = fileDir+os.sep+'SELshortlist.txt'
2122 except Exception as e:
2123 print("Failed to write SEL short list to file system.")
2124 errorInfo += "Error writing SEL short list to the file. Exception: {eInfo}\n".format(eInfo=e)
Justin Thalerb4256672020-04-07 19:38:26 -05002125 exc_type, exc_obj, exc_tb = sys.exc_info()
2126 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
2127 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
2128 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06002129
2130 output['errors'] = errorInfo
2131 return output
2132
2133def csdParsedSels(host, args, session, fileDir):
2134 """
2135 Collects the BMC log entries, retrying if necessary
2136
2137 @param host: string, the hostname or IP address of the bmc
2138 @param args: contains additional arguments used by the collectServiceData sub command
2139 @param session: the active session to use
2140 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
2141 @param fileDir: string representation of the path to use for putting files created
2142 """
2143 errorInfo = "===========SEL Parsed List =============\n"
2144 selsCollected = False
2145 output={}
2146 try:
2147 d = vars(args)
2148 d['json'] = True
2149 d['fullEsel'] = True
2150 except Exception as e:
2151 errorInfo += "Failed to set the json flag to True \n Exception: {eInfo}\n".format(eInfo=e)
Justin Thalerb4256672020-04-07 19:38:26 -05002152 exc_type, exc_obj, exc_tb = sys.exc_info()
2153 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
2154 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
2155 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06002156
2157 try:
2158 for i in range(3):
2159 parsedfullsels = json.loads(selPrint(host,args,session))
2160 if 'numAlerts' in parsedfullsels:
2161 selsCollected = True
2162 break
2163 else:
2164 errorInfo += parsedfullsels + '\n'
2165 except Exception as e:
2166 errorInfo += "Parsed full SELs collection exception: {eInfo}\n".format(eInfo=e)
Justin Thalerb4256672020-04-07 19:38:26 -05002167 exc_type, exc_obj, exc_tb = sys.exc_info()
2168 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
2169 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
2170 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06002171
2172 if selsCollected:
2173 try:
2174 sortedSELs = sortSELs(parsedfullsels)
2175 with open(fileDir +os.sep+'parsedSELs.txt', 'w') as f:
2176 for log in sortedSELs[0]:
2177 esel = ""
2178 parsedfullsels[sortedSELs[1][str(log)]]['timestamp'] = datetime.datetime.fromtimestamp(int(parsedfullsels[sortedSELs[1][str(log)]]['timestamp']/1000)).strftime("%Y-%m-%d %H:%M:%S")
2179 if ('raweSEL' in parsedfullsels[sortedSELs[1][str(log)]] and args.devdebug):
2180 esel = parsedfullsels[sortedSELs[1][str(log)]]['raweSEL']
2181 del parsedfullsels[sortedSELs[1][str(log)]]['raweSEL']
2182 f.write(json.dumps(parsedfullsels[sortedSELs[1][str(log)]],sort_keys=True, indent=4, separators=(',', ': ')))
2183 if(args.devdebug and esel != ""):
2184 f.write(parseESEL(args, esel))
2185 print("Parsed SELs collected and stored in " + fileDir + os.sep+ "parsedSELs.txt")
2186 output['fileLoc'] = fileDir+os.sep+'parsedSELs.txt'
2187 except Exception as e:
2188 print("Failed to write fully parsed SELs to file system.")
2189 errorInfo += "Error writing fully parsed SELs to the file. Exception: {eInfo}\n".format(eInfo=e)
Justin Thalerb4256672020-04-07 19:38:26 -05002190 exc_type, exc_obj, exc_tb = sys.exc_info()
2191 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
2192 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
2193 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06002194
2195 output['errors'] = errorInfo
2196 return output
2197
2198def csdFullEnumeration(host, args, session, fileDir):
2199 """
2200 Collects a full enumeration of /xyz/openbmc_project/, retrying if necessary
2201
2202 @param host: string, the hostname or IP address of the bmc
2203 @param args: contains additional arguments used by the collectServiceData sub command
2204 @param session: the active session to use
2205 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
2206 @param fileDir: string representation of the path to use for putting files created
2207 """
2208 errorInfo = "===========BMC Full Enumeration =============\n"
2209 bmcFullCollected = False
2210 output={}
2211 try:
2212 d = vars(args)
2213 d['json'] = True
2214 except Exception as e:
2215 errorInfo += "Failed to set the json flag to False \n Exception: {eInfo}\n".format(eInfo=e)
Justin Thalerb4256672020-04-07 19:38:26 -05002216 exc_type, exc_obj, exc_tb = sys.exc_info()
2217 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
2218 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
2219 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06002220 try:
2221 print("Attempting to get a full BMC enumeration")
2222 url="https://"+host+"/xyz/openbmc_project/enumerate"
2223 httpHeader = {'Content-Type':'application/json'}
2224 for i in range(3):
2225 try:
2226 bmcRes = session.get(url, headers=jsonHeader, verify=False, timeout=180)
2227 if bmcRes.status_code == 200:
2228 bmcFullCollected = True
2229 fullEnumeration = bmcRes.json()
2230 break
2231 else:
2232 errorInfo += bmcRes.text
2233 except(requests.exceptions.Timeout):
2234 errorInfo+=json.dumps( connectionErrHandler(args.json, "Timeout", None), sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n'
2235 except(requests.exceptions.ConnectionError) as err:
2236 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 -05002237 exc_type, exc_obj, exc_tb = sys.exc_info()
2238 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
2239 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
2240 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06002241 except Exception as e:
2242 errorInfo += "RAW BMC data collection exception: {eInfo}\n".format(eInfo=e)
Justin Thalerb4256672020-04-07 19:38:26 -05002243 exc_type, exc_obj, exc_tb = sys.exc_info()
2244 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
2245 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
2246 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06002247
2248 if bmcFullCollected:
2249 try:
2250 with open(fileDir +os.sep+'bmcFullRaw.txt', 'w') as f:
2251 f.write(json.dumps(fullEnumeration, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n')
2252 print("RAW BMC data collected and saved into " + fileDir + os.sep+ "bmcFullRaw.txt")
2253 output['fileLoc'] = fileDir+os.sep+'bmcFullRaw.txt'
2254 except Exception as e:
2255 print("Failed to write RAW BMC data to file system.")
2256 errorInfo += "Error writing RAW BMC data collection to the file. Exception: {eInfo}\n".format(eInfo=e)
Justin Thalerb4256672020-04-07 19:38:26 -05002257 exc_type, exc_obj, exc_tb = sys.exc_info()
2258 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
2259 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
2260 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06002261
2262 output['errors'] = errorInfo
2263 return output
2264
2265def csdCollectAllDumps(host, args, session, fileDir):
2266 """
2267 Collects all of the bmc dump files and stores them in fileDir
2268
2269 @param host: string, the hostname or IP address of the bmc
2270 @param args: contains additional arguments used by the collectServiceData sub command
2271 @param session: the active session to use
2272 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
2273 @param fileDir: string representation of the path to use for putting files created
2274 """
2275
2276 errorInfo = "===========BMC Dump Collection =============\n"
2277 dumpListCollected = False
2278 output={}
2279 dumpList = {}
2280 try:
2281 d = vars(args)
2282 d['json'] = True
2283 d['dumpSaveLoc'] = fileDir
2284 except Exception as e:
2285 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 -05002286 exc_type, exc_obj, exc_tb = sys.exc_info()
2287 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
2288 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
2289 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06002290
2291 print('Collecting bmc dump files')
2292
2293 try:
2294 for i in range(3):
2295 dumpResp = bmcDumpList(host, args, session)
2296 if 'message' in dumpResp:
2297 if 'ok' in dumpResp['message'].lower():
2298 dumpList = dumpResp['data']
2299 dumpListCollected = True
2300 break
2301 else:
2302 errorInfo += "Status was not OK when retrieving the list of dumps available. \n Response: \n{resp}\n".format(resp=dumpResp)
2303 else:
2304 errorInfo += "Invalid response received from the BMC while retrieving the list of dumps available.\n {resp}\n".format(resp=dumpResp)
2305 except Exception as e:
2306 errorInfo += "BMC dump list exception: {eInfo}\n".format(eInfo=e)
Justin Thalerb4256672020-04-07 19:38:26 -05002307 exc_type, exc_obj, exc_tb = sys.exc_info()
2308 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
2309 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
2310 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06002311
2312 if dumpListCollected:
2313 output['fileList'] = []
2314 for dump in dumpList:
2315 try:
2316 if '/xyz/openbmc_project/dump/internal/manager' not in dump:
2317 d['dumpNum'] = int(dump.strip().split('/')[-1])
2318 print('retrieving dump file ' + str(d['dumpNum']))
2319 filename = bmcDumpRetrieve(host, args, session).split('Saved as ')[-1]
2320 output['fileList'].append(filename)
2321 except Exception as e:
2322 print("Unable to collect dump: {dumpInfo}".format(dumpInfo=dump))
2323 errorInfo += "Exception collecting a bmc dump {dumpInfo}\n {eInfo}\n".format(dumpInfo=dump, eInfo=e)
Justin Thalerb4256672020-04-07 19:38:26 -05002324 exc_type, exc_obj, exc_tb = sys.exc_info()
2325 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
2326 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
2327 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06002328 output['errors'] = errorInfo
2329 return output
Justin Thalere412dc22018-01-12 16:28:24 -06002330
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002331def collectServiceData(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06002332 """
2333 Collects all data needed for service from the BMC
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002334
Justin Thalere412dc22018-01-12 16:28:24 -06002335 @param host: string, the hostname or IP address of the bmc
2336 @param args: contains additional arguments used by the collectServiceData sub command
2337 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002338 @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 -06002339 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002340
Justin Thaler22b1bb52018-03-15 13:31:32 -05002341 global toolVersion
Justin Thaler666cf342019-01-23 14:44:27 -06002342 filelist = []
2343 errorInfo = ""
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002344
Justin Thaler666cf342019-01-23 14:44:27 -06002345 #get current number of bmc dumps and create a new bmc dump
2346 dumpInitdata = csdDumpInitiate(host, args, session)
Justin Thalerb4256672020-04-07 19:38:26 -05002347 if 'dumpFailure' in dumpInitdata:
2348 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 -06002349 dumpcount = dumpInitdata['dumpcount']
2350 errorInfo += dumpInitdata['errors']
2351 #create the directory to put files
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002352 try:
2353 args.silent = True
Justin Thalercf1deae2018-05-25 19:35:21 -05002354 myDir = tempfile.gettempdir()+os.sep + host + "--" + datetime.datetime.now().strftime("%Y-%m-%d_%H.%M.%S")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002355 os.makedirs(myDir)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002356
Justin Thaler666cf342019-01-23 14:44:27 -06002357 except Exception as e:
2358 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 -05002359 exc_type, exc_obj, exc_tb = sys.exc_info()
2360 fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
2361 errorInfo += "Exception: Error: {err}, Details: {etype}, {fname}, {lineno}\n".format(err=e, etype=exc_type, fname=fname, lineno=exc_tb.tb_lineno)
2362 errorInfo += traceback.format_exc()
Justin Thaler666cf342019-01-23 14:44:27 -06002363 return("Python exception: {eInfo}".format(eInfo = e))
2364
2365 #Collect Inventory
2366 inventoryData = csdInventory(host, args, session, myDir)
2367 if 'fileLoc' in inventoryData:
2368 filelist.append(inventoryData['fileLoc'])
2369 errorInfo += inventoryData['errors']
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002370 #Read all the sensor and OCC status
Justin Thaler666cf342019-01-23 14:44:27 -06002371 sensorData = csdSensors(host,args,session,myDir)
2372 if 'fileLoc' in sensorData:
2373 filelist.append(sensorData['fileLoc'])
2374 errorInfo += sensorData['errors']
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002375 #Collect all of the LEDs status
Justin Thaler666cf342019-01-23 14:44:27 -06002376 ledStatus = csdLEDs(host, args, session, myDir)
2377 if 'fileLoc' in ledStatus:
2378 filelist.append(ledStatus['fileLoc'])
2379 errorInfo += ledStatus['errors']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002380
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002381 #Collect the bmc logs
Justin Thaler666cf342019-01-23 14:44:27 -06002382 selShort = csdSelShortList(host, args, session, myDir)
2383 if 'fileLoc' in selShort:
2384 filelist.append(selShort['fileLoc'])
2385 errorInfo += selShort['errors']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002386
Justin Thaler666cf342019-01-23 14:44:27 -06002387 parsedSELs = csdParsedSels(host, args, session, myDir)
2388 if 'fileLoc' in parsedSELs:
2389 filelist.append(parsedSELs['fileLoc'])
2390 errorInfo += parsedSELs['errors']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002391
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002392 #collect RAW bmc enumeration
Justin Thaler666cf342019-01-23 14:44:27 -06002393 bmcRaw = csdFullEnumeration(host, args, session, myDir)
2394 if 'fileLoc' in bmcRaw:
2395 filelist.append(bmcRaw['fileLoc'])
2396 errorInfo += bmcRaw['errors']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002397
Justin Thaler666cf342019-01-23 14:44:27 -06002398 #wait for new dump to finish being created
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002399 waitingForNewDump = True
2400 count = 0;
Justin Thalerb4256672020-04-07 19:38:26 -05002401 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 -06002402 while(waitingForNewDump):
Justin Thaler666cf342019-01-23 14:44:27 -06002403 dumpList = bmcDumpList(host, args, session)['data']
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002404 if len(dumpList) > dumpcount:
2405 waitingForNewDump = False
2406 break;
Justin Thalerb4256672020-04-07 19:38:26 -05002407 elif(count>150):
2408 print("Timed out waiting for bmc to make a new dump file. Continuing without it.")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002409 break;
2410 else:
2411 time.sleep(2)
2412 count += 1
Justin Thaler666cf342019-01-23 14:44:27 -06002413
2414 #collect all of the dump files
2415 getBMCDumps = csdCollectAllDumps(host, args, session, myDir)
2416 if 'fileList' in getBMCDumps:
2417 filelist+= getBMCDumps['fileList']
2418 errorInfo += getBMCDumps['errors']
2419
2420 #write the runtime errors to a file
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002421 try:
Justin Thaler666cf342019-01-23 14:44:27 -06002422 with open(myDir +os.sep+'openbmctoolRuntimeErrors.txt', 'w') as f:
2423 f.write(errorInfo)
2424 print("OpenBMC tool runtime errors collected and stored in " + myDir + os.sep+ "openbmctoolRuntimeErrors.txt")
2425 filelist.append(myDir+os.sep+'openbmctoolRuntimeErrors.txt')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002426 except Exception as e:
Justin Thaler666cf342019-01-23 14:44:27 -06002427 print("Failed to write OpenBMC tool runtime errors to file system.")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002428
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002429 #create the zip file
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002430 try:
Justin Thalercf1deae2018-05-25 19:35:21 -05002431 filename = myDir.split(tempfile.gettempdir()+os.sep)[-1] + "_" + toolVersion + '_openbmc.zip'
Justin Thaler666cf342019-01-23 14:44:27 -06002432 zf = zipfile.ZipFile(myDir+os.sep + filename, 'w')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002433 for myfile in filelist:
2434 zf.write(myfile, os.path.basename(myfile))
2435 zf.close()
Justin Thaler666cf342019-01-23 14:44:27 -06002436 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 -06002437 except Exception as e:
2438 print("Failed to create zip file with collected information")
Justin Thaler666cf342019-01-23 14:44:27 -06002439 return "data collection finished"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002440
Justin Thalere412dc22018-01-12 16:28:24 -06002441
2442def healthCheck(host, args, session):
2443 """
2444 runs a health check on the platform
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002445
Justin Thalere412dc22018-01-12 16:28:24 -06002446 @param host: string, the hostname or IP address of the bmc
2447 @param args: contains additional arguments used by the bmc sub command
2448 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002449 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
2450 """
Justin Thalere412dc22018-01-12 16:28:24 -06002451 #check fru status and get as json to easily work through
2452 d = vars(args)
2453 useJson = d['json']
2454 d['json'] = True
2455 d['verbose']= False
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002456
Justin Thalere412dc22018-01-12 16:28:24 -06002457 frus = json.loads(fruStatus(host, args, session))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002458
Justin Thalere412dc22018-01-12 16:28:24 -06002459 hwStatus= "OK"
2460 performanceStatus = "OK"
2461 for key in frus:
2462 if frus[key]["Functional"] == "No" and frus[key]["Present"] == "Yes":
2463 hwStatus= "Degraded"
Justin Thalerfb9c81c2018-07-16 11:14:37 -05002464 if("power_supply" in key or "powersupply" in key):
2465 gpuCount =0
2466 for comp in frus:
Justin Thalere412dc22018-01-12 16:28:24 -06002467 if "gv100card" in comp:
2468 gpuCount +=1
2469 if gpuCount > 4:
2470 hwStatus = "Critical"
2471 performanceStatus="Degraded"
2472 break;
2473 elif("fan" in key):
2474 hwStatus = "Degraded"
2475 else:
2476 performanceStatus = "Degraded"
2477 if useJson:
2478 output = {"Hardware Status": hwStatus, "Performance": performanceStatus}
2479 output = json.dumps(output, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False)
2480 else:
2481 output = ("Hardware Status: " + hwStatus +
2482 "\nPerformance: " +performanceStatus )
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002483
2484
Justin Thalere412dc22018-01-12 16:28:24 -06002485 #SW407886: Clear the duplicate entries
2486 #collect the dups
2487 d['devdebug'] = False
2488 sels = json.loads(selPrint(host, args, session))
2489 logNums2Clr = []
2490 oldestLogNum={"logNum": "bogus" ,"key" : ""}
2491 count = 0
2492 if sels['numAlerts'] > 0:
2493 for key in sels:
2494 if "numAlerts" in key:
2495 continue
2496 try:
2497 if "slave@00:00/00:00:00:06/sbefifo1-dev0/occ1-dev0" in sels[key]['Message']:
2498 count += 1
2499 if count > 1:
2500 #preserve first occurrence
2501 if sels[key]['timestamp'] < sels[oldestLogNum['key']]['timestamp']:
2502 oldestLogNum['key']=key
2503 oldestLogNum['logNum'] = sels[key]['logNum']
2504 else:
2505 oldestLogNum['key']=key
2506 oldestLogNum['logNum'] = sels[key]['logNum']
2507 logNums2Clr.append(sels[key]['logNum'])
2508 except KeyError:
2509 continue
2510 if(count >0):
2511 logNums2Clr.remove(oldestLogNum['logNum'])
2512 #delete the dups
2513 if count >1:
Justin Thalere412dc22018-01-12 16:28:24 -06002514 data = "{\"data\": [] }"
2515 for logNum in logNums2Clr:
2516 url = "https://"+ host+ "/xyz/openbmc_project/logging/entry/"+logNum+"/action/Delete"
2517 try:
Justin Thaler27197622019-01-23 14:42:11 -06002518 session.post(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002519 except(requests.exceptions.Timeout):
2520 deleteFailed = True
2521 except(requests.exceptions.ConnectionError) as err:
2522 deleteFailed = True
2523 #End of defect resolve code
2524 d['json'] = useJson
2525 return output
2526
2527
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002528
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002529def bmc(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06002530 """
2531 handles various bmc level commands, currently bmc rebooting
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002532
Justin Thalere412dc22018-01-12 16:28:24 -06002533 @param host: string, the hostname or IP address of the bmc
2534 @param args: contains additional arguments used by the bmc sub command
2535 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002536 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
2537 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002538 if(args.type is not None):
2539 return bmcReset(host, args, session)
Justin Thalere412dc22018-01-12 16:28:24 -06002540 if(args.info):
2541 return "Not implemented at this time"
2542
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002543
Justin Thalere412dc22018-01-12 16:28:24 -06002544
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002545def bmcReset(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06002546 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002547 controls resetting the bmc. warm reset reboots the bmc, cold reset removes the configuration and reboots.
2548
Justin Thalere412dc22018-01-12 16:28:24 -06002549 @param host: string, the hostname or IP address of the bmc
2550 @param args: contains additional arguments used by the bmcReset sub command
2551 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002552 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
2553 """
Justin Thaler22b1bb52018-03-15 13:31:32 -05002554 if checkFWactivation(host, args, session):
2555 return ("BMC reset control disabled during firmware activation")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002556 if(args.type == "warm"):
2557 print("\nAttempting to reboot the BMC...:")
2558 url="https://"+host+"/xyz/openbmc_project/state/bmc0/attr/RequestedBMCTransition"
Justin Thalere412dc22018-01-12 16:28:24 -06002559 data = '{"data":"xyz.openbmc_project.State.BMC.Transition.Reboot"}'
Justin Thaler27197622019-01-23 14:42:11 -06002560 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002561 return res.text
2562 elif(args.type =="cold"):
Justin Thalere412dc22018-01-12 16:28:24 -06002563 print("\nAttempting to reboot the BMC...:")
2564 url="https://"+host+"/xyz/openbmc_project/state/bmc0/attr/RequestedBMCTransition"
Justin Thalere412dc22018-01-12 16:28:24 -06002565 data = '{"data":"xyz.openbmc_project.State.BMC.Transition.Reboot"}'
Justin Thaler27197622019-01-23 14:42:11 -06002566 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002567 return res.text
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002568 else:
2569 return "invalid command"
Justin Thalere412dc22018-01-12 16:28:24 -06002570
2571def gardClear(host, args, session):
2572 """
2573 clears the gard records from the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002574
Justin Thalere412dc22018-01-12 16:28:24 -06002575 @param host: string, the hostname or IP address of the bmc
2576 @param args: contains additional arguments used by the gardClear sub command
2577 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002578 """
Justin Thalere412dc22018-01-12 16:28:24 -06002579 url="https://"+host+"/org/open_power/control/gard/action/Reset"
Justin Thalere412dc22018-01-12 16:28:24 -06002580 data = '{"data":[]}'
2581 try:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002582
Justin Thaler27197622019-01-23 14:42:11 -06002583 res = session.post(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002584 if res.status_code == 404:
2585 return "Command not supported by this firmware version"
2586 else:
2587 return res.text
2588 except(requests.exceptions.Timeout):
2589 return connectionErrHandler(args.json, "Timeout", None)
2590 except(requests.exceptions.ConnectionError) as err:
2591 return connectionErrHandler(args.json, "ConnectionError", err)
2592
2593def activateFWImage(host, args, session):
2594 """
2595 activates a firmware image on the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002596
Justin Thalere412dc22018-01-12 16:28:24 -06002597 @param host: string, the hostname or IP address of the bmc
2598 @param args: contains additional arguments used by the fwflash sub command
2599 @param session: the active session to use
2600 @param fwID: the unique ID of the fw image to activate
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002601 """
Justin Thalere412dc22018-01-12 16:28:24 -06002602 fwID = args.imageID
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002603
Justin Thalere412dc22018-01-12 16:28:24 -06002604 #determine the existing versions
Justin Thalere412dc22018-01-12 16:28:24 -06002605 url="https://"+host+"/xyz/openbmc_project/software/enumerate"
2606 try:
Justin Thaler27197622019-01-23 14:42:11 -06002607 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002608 except(requests.exceptions.Timeout):
2609 return connectionErrHandler(args.json, "Timeout", None)
2610 except(requests.exceptions.ConnectionError) as err:
2611 return connectionErrHandler(args.json, "ConnectionError", err)
2612 existingSoftware = json.loads(resp.text)['data']
2613 altVersionID = ''
2614 versionType = ''
2615 imageKey = '/xyz/openbmc_project/software/'+fwID
2616 if imageKey in existingSoftware:
2617 versionType = existingSoftware[imageKey]['Purpose']
2618 for key in existingSoftware:
2619 if imageKey == key:
2620 continue
2621 if 'Purpose' in existingSoftware[key]:
2622 if versionType == existingSoftware[key]['Purpose']:
2623 altVersionID = key.split('/')[-1]
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002624
2625
2626
2627
Justin Thalere412dc22018-01-12 16:28:24 -06002628 url="https://"+host+"/xyz/openbmc_project/software/"+ fwID + "/attr/Priority"
2629 url1="https://"+host+"/xyz/openbmc_project/software/"+ altVersionID + "/attr/Priority"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002630 data = "{\"data\": 0}"
Justin Thalere412dc22018-01-12 16:28:24 -06002631 data1 = "{\"data\": 1 }"
2632 try:
Justin Thaler27197622019-01-23 14:42:11 -06002633 resp = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
2634 resp1 = session.put(url1, headers=jsonHeader, data=data1, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002635 except(requests.exceptions.Timeout):
2636 return connectionErrHandler(args.json, "Timeout", None)
2637 except(requests.exceptions.ConnectionError) as err:
2638 return connectionErrHandler(args.json, "ConnectionError", err)
2639 if(not args.json):
2640 if resp.status_code == 200 and resp1.status_code == 200:
Justin Thaler22b1bb52018-03-15 13:31:32 -05002641 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 -06002642 else:
2643 return "Firmware activation failed."
2644 else:
2645 return resp.text + resp1.text
Justin Thaler22b1bb52018-03-15 13:31:32 -05002646
2647def activateStatus(host, args, session):
2648 if checkFWactivation(host, args, session):
2649 return("Firmware is currently being activated. Do not reboot the BMC or start the Host OS")
2650 else:
2651 return("No firmware activations are pending")
2652
2653def extractFWimage(path, imageType):
2654 """
2655 extracts the bmc image and returns information about the package
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002656
Justin Thaler22b1bb52018-03-15 13:31:32 -05002657 @param path: the path and file name of the firmware image
2658 @param imageType: The type of image the user is trying to flash. Host or BMC
2659 @return: the image id associated with the package. returns an empty string on error.
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002660 """
Justin Thaler22b1bb52018-03-15 13:31:32 -05002661 f = tempfile.TemporaryFile()
2662 tmpDir = tempfile.gettempdir()
2663 newImageID = ""
2664 if os.path.exists(path):
2665 try:
2666 imageFile = tarfile.open(path,'r')
2667 contents = imageFile.getmembers()
2668 for tf in contents:
2669 if 'MANIFEST' in tf.name:
2670 imageFile.extract(tf.name, path=tmpDir)
2671 with open(tempfile.gettempdir() +os.sep+ tf.name, 'r') as imageInfo:
2672 for line in imageInfo:
2673 if 'purpose' in line:
2674 purpose = line.split('=')[1]
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002675 if imageType not in purpose.split('.')[-1]:
Justin Thaler22b1bb52018-03-15 13:31:32 -05002676 print('The specified image is not for ' + imageType)
2677 print('Please try again with the image for ' + imageType)
2678 return ""
2679 if 'version' == line.split('=')[0]:
2680 version = line.split('=')[1].strip().encode('utf-8')
2681 m = hashlib.sha512()
2682 m.update(version)
2683 newImageID = m.hexdigest()[:8]
2684 break
2685 try:
2686 os.remove(tempfile.gettempdir() +os.sep+ tf.name)
2687 except OSError:
2688 pass
2689 return newImageID
2690 except tarfile.ExtractError as e:
2691 print('Unable to extract information from the firmware file.')
2692 print('Ensure you have write access to the directory: ' + tmpDir)
2693 return newImageID
2694 except tarfile.TarError as e:
2695 print('This is not a valid firmware file.')
2696 return newImageID
2697 print("This is not a valid firmware file.")
2698 return newImageID
2699 else:
2700 print('The filename and path provided are not valid.')
2701 return newImageID
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002702
Justin Thaler22b1bb52018-03-15 13:31:32 -05002703def getAllFWImageIDs(fwInvDict):
2704 """
2705 gets a list of all the firmware image IDs
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002706
Justin Thaler22b1bb52018-03-15 13:31:32 -05002707 @param fwInvDict: the dictionary to search for FW image IDs
2708 @return: list containing string representation of the found image ids
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002709 """
Justin Thaler22b1bb52018-03-15 13:31:32 -05002710 idList = []
2711 for key in fwInvDict:
2712 if 'Version' in fwInvDict[key]:
2713 idList.append(key.split('/')[-1])
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002714 return idList
2715
Justin Thalere412dc22018-01-12 16:28:24 -06002716def fwFlash(host, args, session):
2717 """
2718 updates the bmc firmware and pnor firmware
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002719
Justin Thalere412dc22018-01-12 16:28:24 -06002720 @param host: string, the hostname or IP address of the bmc
2721 @param args: contains additional arguments used by the fwflash sub command
2722 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002723 """
Justin Thaler22b1bb52018-03-15 13:31:32 -05002724 d = vars(args)
Justin Thalere412dc22018-01-12 16:28:24 -06002725 if(args.type == 'bmc'):
2726 purp = 'BMC'
2727 else:
2728 purp = 'Host'
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002729
2730 #check power state of the machine. No concurrent FW updates allowed
Justin Thaler22b1bb52018-03-15 13:31:32 -05002731 d['powcmd'] = 'status'
2732 powerstate = chassisPower(host, args, session)
2733 if 'Chassis Power State: On' in powerstate:
2734 return("Aborting firmware update. Host is powered on. Please turn off the host and try again.")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002735
Justin Thaler22b1bb52018-03-15 13:31:32 -05002736 #determine the existing images on the bmc
Justin Thalere412dc22018-01-12 16:28:24 -06002737 url="https://"+host+"/xyz/openbmc_project/software/enumerate"
2738 try:
Justin Thaler27197622019-01-23 14:42:11 -06002739 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002740 except(requests.exceptions.Timeout):
2741 return connectionErrHandler(args.json, "Timeout", None)
2742 except(requests.exceptions.ConnectionError) as err:
2743 return connectionErrHandler(args.json, "ConnectionError", err)
2744 oldsoftware = json.loads(resp.text)['data']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002745
Justin Thaler22b1bb52018-03-15 13:31:32 -05002746 #Extract the tar and get information from the manifest file
2747 newversionID = extractFWimage(args.fileloc, purp)
2748 if newversionID == "":
2749 return "Unable to verify FW image."
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002750
2751
Justin Thaler22b1bb52018-03-15 13:31:32 -05002752 #check if the new image is already on the bmc
2753 if newversionID not in getAllFWImageIDs(oldsoftware):
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002754
Justin Thaler22b1bb52018-03-15 13:31:32 -05002755 #upload the file
2756 httpHeader = {'Content-Type':'application/octet-stream'}
Matt Spinler220c3c42019-01-04 15:09:29 -06002757 httpHeader.update(xAuthHeader)
Justin Thaler22b1bb52018-03-15 13:31:32 -05002758 url="https://"+host+"/upload/image"
2759 data=open(args.fileloc,'rb').read()
2760 print("Uploading file to BMC")
Justin Thalere412dc22018-01-12 16:28:24 -06002761 try:
Justin Thaler22b1bb52018-03-15 13:31:32 -05002762 resp = session.post(url, headers=httpHeader, data=data, verify=False)
Justin Thalere412dc22018-01-12 16:28:24 -06002763 except(requests.exceptions.Timeout):
2764 return connectionErrHandler(args.json, "Timeout", None)
2765 except(requests.exceptions.ConnectionError) as err:
2766 return connectionErrHandler(args.json, "ConnectionError", err)
Justin Thaler22b1bb52018-03-15 13:31:32 -05002767 if resp.status_code != 200:
2768 return "Failed to upload the file to the bmc"
Justin Thalere412dc22018-01-12 16:28:24 -06002769 else:
Justin Thaler22b1bb52018-03-15 13:31:32 -05002770 print("Upload complete.")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002771
Justin Thaler22b1bb52018-03-15 13:31:32 -05002772 #verify bmc processed the image
2773 software ={}
2774 for i in range(0, 5):
Justin Thaler22b1bb52018-03-15 13:31:32 -05002775 url="https://"+host+"/xyz/openbmc_project/software/enumerate"
2776 try:
Justin Thaler27197622019-01-23 14:42:11 -06002777 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thaler22b1bb52018-03-15 13:31:32 -05002778 except(requests.exceptions.Timeout):
2779 return connectionErrHandler(args.json, "Timeout", None)
2780 except(requests.exceptions.ConnectionError) as err:
2781 return connectionErrHandler(args.json, "ConnectionError", err)
2782 software = json.loads(resp.text)['data']
2783 #check if bmc is done processing the new image
2784 if (newversionID in getAllFWImageIDs(software)):
Justin Thalere412dc22018-01-12 16:28:24 -06002785 break
Justin Thaler22b1bb52018-03-15 13:31:32 -05002786 else:
2787 time.sleep(15)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002788
Justin Thaler22b1bb52018-03-15 13:31:32 -05002789 #activate the new image
2790 print("Activating new image: "+newversionID)
2791 url="https://"+host+"/xyz/openbmc_project/software/"+ newversionID + "/attr/RequestedActivation"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002792 data = '{"data":"xyz.openbmc_project.Software.Activation.RequestedActivations.Active"}'
Justin Thaler22b1bb52018-03-15 13:31:32 -05002793 try:
Justin Thaler27197622019-01-23 14:42:11 -06002794 resp = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thaler22b1bb52018-03-15 13:31:32 -05002795 except(requests.exceptions.Timeout):
2796 return connectionErrHandler(args.json, "Timeout", None)
2797 except(requests.exceptions.ConnectionError) as err:
2798 return connectionErrHandler(args.json, "ConnectionError", err)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002799
Justin Thaler22b1bb52018-03-15 13:31:32 -05002800 #wait for the activation to complete, timeout after ~1 hour
2801 i=0
2802 while i < 360:
2803 url="https://"+host+"/xyz/openbmc_project/software/"+ newversionID
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002804 data = '{"data":"xyz.openbmc_project.Software.Activation.RequestedActivations.Active"}'
Justin Thaler22b1bb52018-03-15 13:31:32 -05002805 try:
Justin Thaler27197622019-01-23 14:42:11 -06002806 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thaler22b1bb52018-03-15 13:31:32 -05002807 except(requests.exceptions.Timeout):
2808 return connectionErrHandler(args.json, "Timeout", None)
2809 except(requests.exceptions.ConnectionError) as err:
2810 return connectionErrHandler(args.json, "ConnectionError", err)
2811 fwInfo = json.loads(resp.text)['data']
2812 if 'Activating' not in fwInfo['Activation'] and 'Activating' not in fwInfo['RequestedActivation']:
2813 print('')
2814 break
2815 else:
2816 sys.stdout.write('.')
2817 sys.stdout.flush()
2818 time.sleep(10) #check every 10 seconds
2819 return "Firmware flash and activation completed. Please reboot the bmc and then boot the host OS for the changes to take effect. "
2820 else:
2821 print("This image has been found on the bmc. Activating image: " + newversionID)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002822
Justin Thaler22b1bb52018-03-15 13:31:32 -05002823 d['imageID'] = newversionID
2824 return activateFWImage(host, args, session)
Justin Thalere412dc22018-01-12 16:28:24 -06002825
Justin Thaler3d71d402018-07-24 14:35:39 -05002826def getFWInventoryAttributes(rawFWInvItem, ID):
2827 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002828 gets and lists all of the firmware in the system.
2829
Justin Thaler3d71d402018-07-24 14:35:39 -05002830 @return: returns a dictionary containing the image attributes
2831 """
2832 reqActivation = rawFWInvItem["RequestedActivation"].split('.')[-1]
2833 pendingActivation = ""
2834 if reqActivation == "None":
2835 pendingActivation = "No"
2836 else:
2837 pendingActivation = "Yes"
2838 firmwareAttr = {ID: {
2839 "Purpose": rawFWInvItem["Purpose"].split('.')[-1],
2840 "Version": rawFWInvItem["Version"],
2841 "RequestedActivation": pendingActivation,
2842 "ID": ID}}
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002843
Justin Thaler3d71d402018-07-24 14:35:39 -05002844 if "ExtendedVersion" in rawFWInvItem:
2845 firmwareAttr[ID]['ExtendedVersion'] = rawFWInvItem['ExtendedVersion'].split(',')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002846 else:
Justin Thaler3d71d402018-07-24 14:35:39 -05002847 firmwareAttr[ID]['ExtendedVersion'] = ""
2848 return firmwareAttr
2849
2850def parseFWdata(firmwareDict):
2851 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002852 creates a dictionary with parsed firmware data
2853
Justin Thaler3d71d402018-07-24 14:35:39 -05002854 @return: returns a dictionary containing the image attributes
2855 """
2856 firmwareInfoDict = {"Functional": {}, "Activated":{}, "NeedsActivated":{}}
2857 for key in firmwareDict['data']:
2858 #check for valid endpoint
2859 if "Purpose" in firmwareDict['data'][key]:
2860 id = key.split('/')[-1]
2861 if firmwareDict['data'][key]['Activation'].split('.')[-1] == "Active":
2862 fwActivated = True
2863 else:
2864 fwActivated = False
Justin Thalercb68e062019-03-26 19:04:52 -05002865 if 'Priority' in firmwareDict['data'][key]:
2866 if firmwareDict['data'][key]['Priority'] == 0:
2867 firmwareInfoDict['Functional'].update(getFWInventoryAttributes(firmwareDict['data'][key], id))
2868 elif firmwareDict['data'][key]['Priority'] >= 0 and fwActivated:
2869 firmwareInfoDict['Activated'].update(getFWInventoryAttributes(firmwareDict['data'][key], id))
2870 else:
2871 firmwareInfoDict['NeedsActivated'].update(getFWInventoryAttributes(firmwareDict['data'][key], id))
Justin Thaler3d71d402018-07-24 14:35:39 -05002872 else:
Justin Thalercb68e062019-03-26 19:04:52 -05002873 firmwareInfoDict['NeedsActivated'].update(getFWInventoryAttributes(firmwareDict['data'][key], id))
Justin Thaler3d71d402018-07-24 14:35:39 -05002874 emptySections = []
2875 for key in firmwareInfoDict:
2876 if len(firmwareInfoDict[key])<=0:
2877 emptySections.append(key)
2878 for key in emptySections:
2879 del firmwareInfoDict[key]
2880 return firmwareInfoDict
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002881
Justin Thaler3d71d402018-07-24 14:35:39 -05002882def displayFWInvenory(firmwareInfoDict, args):
2883 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002884 gets and lists all of the firmware in the system.
2885
Justin Thaler3d71d402018-07-24 14:35:39 -05002886 @return: returns a string containing all of the firmware information
2887 """
2888 output = ""
2889 if not args.json:
2890 for key in firmwareInfoDict:
2891 for subkey in firmwareInfoDict[key]:
2892 firmwareInfoDict[key][subkey]['ExtendedVersion'] = str(firmwareInfoDict[key][subkey]['ExtendedVersion'])
2893 if not args.verbose:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002894 output = "---Running Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002895 colNames = ["Purpose", "Version", "ID"]
2896 keylist = ["Purpose", "Version", "ID"]
2897 output += tableDisplay(keylist, colNames, firmwareInfoDict["Functional"])
2898 if "Activated" in firmwareInfoDict:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002899 output += "\n---Available Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002900 output += tableDisplay(keylist, colNames, firmwareInfoDict["Activated"])
2901 if "NeedsActivated" in firmwareInfoDict:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002902 output += "\n---Needs Activated Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002903 output += tableDisplay(keylist, colNames, firmwareInfoDict["NeedsActivated"])
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002904
Justin Thaler3d71d402018-07-24 14:35:39 -05002905 else:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002906 output = "---Running Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002907 colNames = ["Purpose", "Version", "ID", "Pending Activation", "Extended Version"]
2908 keylist = ["Purpose", "Version", "ID", "RequestedActivation", "ExtendedVersion"]
2909 output += tableDisplay(keylist, colNames, firmwareInfoDict["Functional"])
2910 if "Activated" in firmwareInfoDict:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002911 output += "\n---Available Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002912 output += tableDisplay(keylist, colNames, firmwareInfoDict["Activated"])
2913 if "NeedsActivated" in firmwareInfoDict:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002914 output += "\n---Needs Activated Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002915 output += tableDisplay(keylist, colNames, firmwareInfoDict["NeedsActivated"])
2916 return output
2917 else:
2918 return str(json.dumps(firmwareInfoDict, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False))
2919
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002920def firmwareList(host, args, session):
Justin Thaler3d71d402018-07-24 14:35:39 -05002921 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002922 gets and lists all of the firmware in the system.
2923
Justin Thaler3d71d402018-07-24 14:35:39 -05002924 @return: returns a string containing all of the firmware information
2925 """
Justin Thaler3d71d402018-07-24 14:35:39 -05002926 url="https://{hostname}/xyz/openbmc_project/software/enumerate".format(hostname=host)
2927 try:
Justin Thaler27197622019-01-23 14:42:11 -06002928 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thaler3d71d402018-07-24 14:35:39 -05002929 except(requests.exceptions.Timeout):
2930 return(connectionErrHandler(args.json, "Timeout", None))
2931 firmwareDict = json.loads(res.text)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002932
Justin Thaler3d71d402018-07-24 14:35:39 -05002933 #sort the received information
2934 firmwareInfoDict = parseFWdata(firmwareDict)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002935
Justin Thaler3d71d402018-07-24 14:35:39 -05002936 #display the information
2937 return displayFWInvenory(firmwareInfoDict, args)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002938
2939
Adriana Kobylak5af2fad2018-11-08 12:33:43 -06002940def deleteFWVersion(host, args, session):
2941 """
2942 deletes a firmware version on the BMC
2943
2944 @param host: string, the hostname or IP address of the BMC
2945 @param args: contains additional arguments used by the fwflash sub command
2946 @param session: the active session to use
2947 @param fwID: the unique ID of the fw version to delete
2948 """
2949 fwID = args.versionID
2950
2951 print("Deleting version: "+fwID)
2952 url="https://"+host+"/xyz/openbmc_project/software/"+ fwID + "/action/Delete"
Adriana Kobylak5af2fad2018-11-08 12:33:43 -06002953 data = "{\"data\": [] }"
2954
2955 try:
Justin Thaler27197622019-01-23 14:42:11 -06002956 res = session.post(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Adriana Kobylak5af2fad2018-11-08 12:33:43 -06002957 except(requests.exceptions.Timeout):
2958 return(connectionErrHandler(args.json, "Timeout", None))
2959 if res.status_code == 200:
2960 return ('The firmware version has been deleted')
2961 else:
2962 return ('Unable to delete the specified firmware version')
2963
2964
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05002965def restLogging(host, args, session):
2966 """
2967 Called by the logging function. Turns REST API logging on/off.
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002968
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05002969 @param host: string, the hostname or IP address of the bmc
2970 @param args: contains additional arguments used by the logging sub command
2971 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002972 @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 -05002973 """
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05002974 url="https://"+host+"/xyz/openbmc_project/logging/rest_api_logs/attr/Enabled"
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05002975
2976 if(args.rest_logging == 'on'):
2977 data = '{"data": 1}'
2978 elif(args.rest_logging == 'off'):
2979 data = '{"data": 0}'
2980 else:
2981 return "Invalid logging rest_api command"
2982
2983 try:
Justin Thaler27197622019-01-23 14:42:11 -06002984 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05002985 except(requests.exceptions.Timeout):
2986 return(connectionErrHandler(args.json, "Timeout", None))
2987 return res.text
2988
2989
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002990def remoteLogging(host, args, session):
2991 """
2992 Called by the logging function. View config information for/disable remote logging (rsyslog).
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002993
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002994 @param host: string, the hostname or IP address of the bmc
2995 @param args: contains additional arguments used by the logging sub command
2996 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002997 @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 -05002998 """
2999
3000 url="https://"+host+"/xyz/openbmc_project/logging/config/remote"
Deepak Kodihalli02d53282018-09-18 06:53:31 -05003001
3002 try:
3003 if(args.remote_logging == 'view'):
Justin Thaler27197622019-01-23 14:42:11 -06003004 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Deepak Kodihalli02d53282018-09-18 06:53:31 -05003005 elif(args.remote_logging == 'disable'):
Justin Thaler27197622019-01-23 14:42:11 -06003006 res = session.put(url + '/attr/Port', headers=jsonHeader, json = {"data": 0}, verify=False, timeout=baseTimeout)
3007 res = session.put(url + '/attr/Address', headers=jsonHeader, json = {"data": ""}, verify=False, timeout=baseTimeout)
Deepak Kodihalli02d53282018-09-18 06:53:31 -05003008 else:
3009 return "Invalid logging remote_logging command"
3010 except(requests.exceptions.Timeout):
3011 return(connectionErrHandler(args.json, "Timeout", None))
3012 return res.text
3013
3014
3015def remoteLoggingConfig(host, args, session):
3016 """
3017 Called by the logging function. Configures remote logging (rsyslog).
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003018
Deepak Kodihalli02d53282018-09-18 06:53:31 -05003019 @param host: string, the hostname or IP address of the bmc
3020 @param args: contains additional arguments used by the logging sub command
3021 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06003022 @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 -05003023 """
3024
3025 url="https://"+host+"/xyz/openbmc_project/logging/config/remote"
Deepak Kodihalli02d53282018-09-18 06:53:31 -05003026
3027 try:
Justin Thaler27197622019-01-23 14:42:11 -06003028 res = session.put(url + '/attr/Port', headers=jsonHeader, json = {"data": args.port}, verify=False, timeout=baseTimeout)
3029 res = session.put(url + '/attr/Address', headers=jsonHeader, json = {"data": args.address}, verify=False, timeout=baseTimeout)
Deepak Kodihalli02d53282018-09-18 06:53:31 -05003030 except(requests.exceptions.Timeout):
3031 return(connectionErrHandler(args.json, "Timeout", None))
3032 return res.text
3033
Marri Devender Rao82590dc2019-06-06 04:54:22 -05003034def redfishSupportPresent(host, session):
3035 url = "https://" + host + "/redfish/v1"
3036 try:
3037 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
3038 except(requests.exceptions.Timeout):
3039 return False
3040 except(requests.exceptions.ConnectionError) as err:
3041 return False
3042 if resp.status_code != 200:
3043 return False
3044 else:
3045 return True
Ratan Gupta9166cd22018-10-01 18:09:40 +05303046
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05003047def certificateUpdate(host, args, session):
3048 """
3049 Called by certificate management function. update server/client/authority certificates
3050 Example:
3051 certificate update server https -f cert.pem
3052 certificate update authority ldap -f Root-CA.pem
3053 certificate update client ldap -f cert.pem
3054 @param host: string, the hostname or IP address of the bmc
3055 @param args: contains additional arguments used by the certificate update sub command
3056 @param session: the active session to use
3057 """
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05003058 httpHeader = {'Content-Type': 'application/octet-stream'}
Matt Spinler220c3c42019-01-04 15:09:29 -06003059 httpHeader.update(xAuthHeader)
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05003060 data = open(args.fileloc, 'rb').read()
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05003061 try:
Marri Devender Rao82590dc2019-06-06 04:54:22 -05003062 if redfishSupportPresent(host, session):
Marri Devender Rao62db08a2019-08-22 03:16:02 -05003063 if(args.type.lower() == 'server' and args.service.lower() != "https"):
3064 return "Invalid service type"
3065 if(args.type.lower() == 'client' and args.service.lower() != "ldap"):
3066 return "Invalid service type"
3067 if(args.type.lower() == 'authority' and args.service.lower() != "ldap"):
3068 return "Invalid service type"
Marri Devender Rao82590dc2019-06-06 04:54:22 -05003069 url = "";
3070 if(args.type.lower() == 'server'):
3071 url = "https://" + host + \
3072 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"
3073 elif(args.type.lower() == 'client'):
3074 url = "https://" + host + \
3075 "/redfish/v1/AccountService/LDAP/Certificates"
3076 elif(args.type.lower() == 'authority'):
3077 url = "https://" + host + \
3078 "/redfish/v1/Managers/bmc/Truststore/Certificates"
3079 else:
3080 return "Unsupported certificate type"
3081 resp = session.post(url, headers=httpHeader, data=data,
3082 verify=False)
3083 else:
3084 url = "https://" + host + "/xyz/openbmc_project/certs/" + \
3085 args.type.lower() + "/" + args.service.lower()
3086 resp = session.put(url, headers=httpHeader, data=data, verify=False)
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05003087 except(requests.exceptions.Timeout):
3088 return(connectionErrHandler(args.json, "Timeout", None))
3089 except(requests.exceptions.ConnectionError) as err:
3090 return connectionErrHandler(args.json, "ConnectionError", err)
3091 if resp.status_code != 200:
3092 print(resp.text)
3093 return "Failed to update the certificate"
3094 else:
Marri Devender Rao82590dc2019-06-06 04:54:22 -05003095 print("Update complete.")
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05003096
3097def certificateDelete(host, args, session):
3098 """
3099 Called by certificate management function to delete certificate
3100 Example:
3101 certificate delete server https
3102 certificate delete authority ldap
3103 certificate delete client ldap
3104 @param host: string, the hostname or IP address of the bmc
3105 @param args: contains additional arguments used by the certificate delete sub command
3106 @param session: the active session to use
3107 """
Marri Devender Rao77e78682019-07-17 03:18:35 -05003108 if redfishSupportPresent(host, session):
3109 return "Not supported, please use certificate replace instead";
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05003110 httpHeader = {'Content-Type': 'multipart/form-data'}
Matt Spinler220c3c42019-01-04 15:09:29 -06003111 httpHeader.update(xAuthHeader)
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05003112 url = "https://" + host + "/xyz/openbmc_project/certs/" + args.type.lower() + "/" + args.service.lower()
3113 print("Deleting certificate url=" + url)
3114 try:
3115 resp = session.delete(url, headers=httpHeader)
3116 except(requests.exceptions.Timeout):
3117 return(connectionErrHandler(args.json, "Timeout", None))
3118 except(requests.exceptions.ConnectionError) as err:
3119 return connectionErrHandler(args.json, "ConnectionError", err)
3120 if resp.status_code != 200:
3121 print(resp.text)
3122 return "Failed to delete the certificate"
3123 else:
Marri Devender Rao77e78682019-07-17 03:18:35 -05003124 print("Delete complete.")
Deepak Kodihalli02d53282018-09-18 06:53:31 -05003125
Marri Devender Raodfe81ad2019-07-01 05:38:09 -05003126def certificateReplace(host, args, session):
3127 """
3128 Called by certificate management function. replace server/client/
3129 authority certificates
3130 Example:
3131 certificate replace server https -f cert.pem
3132 certificate replace authority ldap -f Root-CA.pem
3133 certificate replace client ldap -f cert.pem
3134 @param host: string, the hostname or IP address of the bmc
3135 @param args: contains additional arguments used by the certificate
3136 replace sub command
3137 @param session: the active session to use
3138 """
3139 cert = open(args.fileloc, 'rb').read()
3140 try:
3141 if redfishSupportPresent(host, session):
3142 httpHeader = {'Content-Type': 'application/json'}
3143 httpHeader.update(xAuthHeader)
3144 url = "";
Marri Devender Rao62db08a2019-08-22 03:16:02 -05003145 if(args.type.lower() == 'server' and args.service.lower() != "https"):
3146 return "Invalid service type"
3147 if(args.type.lower() == 'client' and args.service.lower() != "ldap"):
3148 return "Invalid service type"
3149 if(args.type.lower() == 'authority' and args.service.lower() != "ldap"):
3150 return "Invalid service type"
Marri Devender Raodfe81ad2019-07-01 05:38:09 -05003151 if(args.type.lower() == 'server'):
3152 url = "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/1"
3153 elif(args.type.lower() == 'client'):
3154 url = "/redfish/v1/AccountService/LDAP/Certificates/1"
3155 elif(args.type.lower() == 'authority'):
3156 url = "/redfish/v1/Managers/bmc/Truststore/Certificates/1"
3157 replaceUrl = "https://" + host + \
3158 "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate"
3159 data ={"CertificateUri":{"@odata.id":url}, "CertificateType":"PEM",
3160 "CertificateString":cert}
3161 resp = session.post(replaceUrl, headers=httpHeader, json=data, verify=False)
3162 else:
3163 httpHeader = {'Content-Type': 'application/octet-stream'}
3164 httpHeader.update(xAuthHeader)
3165 url = "https://" + host + "/xyz/openbmc_project/certs/" + \
3166 args.type.lower() + "/" + args.service.lower()
3167 resp = session.delete(url, headers=httpHeader)
3168 resp = session.put(url, headers=httpHeader, data=cert, verify=False)
3169 except(requests.exceptions.Timeout):
3170 return(connectionErrHandler(args.json, "Timeout", None))
3171 except(requests.exceptions.ConnectionError) as err:
3172 return connectionErrHandler(args.json, "ConnectionError", err)
3173 if resp.status_code != 200:
3174 print(resp.text)
3175 return "Failed to replace the certificate"
3176 else:
3177 print("Replace complete.")
3178 return resp.text
3179
Marri Devender Rao34646402019-07-01 05:46:03 -05003180def certificateDisplay(host, args, session):
3181 """
3182 Called by certificate management function. display server/client/
3183 authority certificates
3184 Example:
3185 certificate display server
3186 certificate display authority
3187 certificate display client
3188 @param host: string, the hostname or IP address of the bmc
3189 @param args: contains additional arguments used by the certificate
3190 display sub command
3191 @param session: the active session to use
3192 """
3193 if not redfishSupportPresent(host, session):
3194 return "Not supported";
3195
3196 httpHeader = {'Content-Type': 'application/octet-stream'}
3197 httpHeader.update(xAuthHeader)
3198 if(args.type.lower() == 'server'):
3199 url = "https://" + host + \
3200 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/1"
3201 elif(args.type.lower() == 'client'):
3202 url = "https://" + host + \
3203 "/redfish/v1/AccountService/LDAP/Certificates/1"
3204 elif(args.type.lower() == 'authority'):
3205 url = "https://" + host + \
3206 "/redfish/v1/Managers/bmc/Truststore/Certificates/1"
3207 try:
3208 resp = session.get(url, headers=httpHeader, verify=False)
3209 except(requests.exceptions.Timeout):
3210 return(connectionErrHandler(args.json, "Timeout", None))
3211 except(requests.exceptions.ConnectionError) as err:
3212 return connectionErrHandler(args.json, "ConnectionError", err)
3213 if resp.status_code != 200:
3214 print(resp.text)
3215 return "Failed to display the certificate"
3216 else:
3217 print("Display complete.")
3218 return resp.text
3219
Marri Devender Raoa208ff82019-07-01 05:51:27 -05003220def certificateList(host, args, session):
3221 """
3222 Called by certificate management function.
3223 Example:
3224 certificate list
3225 @param host: string, the hostname or IP address of the bmc
3226 @param args: contains additional arguments used by the certificate
3227 list sub command
3228 @param session: the active session to use
3229 """
3230 if not redfishSupportPresent(host, session):
3231 return "Not supported";
3232
3233 httpHeader = {'Content-Type': 'application/octet-stream'}
3234 httpHeader.update(xAuthHeader)
3235 url = "https://" + host + \
3236 "/redfish/v1/CertificateService/CertificateLocations/"
3237 try:
3238 resp = session.get(url, headers=httpHeader, verify=False)
3239 except(requests.exceptions.Timeout):
3240 return(connectionErrHandler(args.json, "Timeout", None))
3241 except(requests.exceptions.ConnectionError) as err:
3242 return connectionErrHandler(args.json, "ConnectionError", err)
3243 if resp.status_code != 200:
3244 print(resp.text)
3245 return "Failed to list certificates"
3246 else:
3247 print("List certificates complete.")
3248 return resp.text
3249
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05003250def certificateGenerateCSR(host, args, session):
3251 """
3252 Called by certificate management function. Generate CSR for server/
3253 client certificates
3254 Example:
Marri Devender Raodf0e1a42019-09-09 08:18:27 -05003255 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
3256 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 -05003257 @param host: string, the hostname or IP address of the bmc
3258 @param args: contains additional arguments used by the certificate replace sub command
3259 @param session: the active session to use
3260 """
3261 if not redfishSupportPresent(host, session):
3262 return "Not supported";
3263
3264 httpHeader = {'Content-Type': 'application/octet-stream'}
3265 httpHeader.update(xAuthHeader)
3266 url = "";
3267 if(args.type.lower() == 'server'):
3268 url = "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/"
Marri Devender Rao88064f02019-08-19 09:00:30 -05003269 usage_list = ["ServerAuthentication"]
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05003270 elif(args.type.lower() == 'client'):
3271 url = "/redfish/v1/AccountService/LDAP/Certificates/"
Marri Devender Rao88064f02019-08-19 09:00:30 -05003272 usage_list = ["ClientAuthentication"]
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05003273 elif(args.type.lower() == 'authority'):
3274 url = "/redfish/v1/Managers/bmc/Truststore/Certificates/"
3275 print("Generating CSR url=" + url)
3276 generateCSRUrl = "https://" + host + \
3277 "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR"
3278 try:
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05003279 alt_name_list = args.alternativeNames.split(",")
3280 data ={"CertificateCollection":{"@odata.id":url},
3281 "CommonName":args.commonName, "City":args.city,
3282 "Country":args.country, "Organization":args.organization,
3283 "OrganizationalUnit":args.organizationUnit, "State":args.state,
Marri Devender Raodf0e1a42019-09-09 08:18:27 -05003284 "KeyPairAlgorithm":args.keyPairAlgorithm, "KeyCurveId":args.keyCurveId,
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05003285 "AlternativeNames":alt_name_list, "ContactPerson":args.contactPerson,
3286 "Email":args.email, "GivenName":args.givenname, "Initials":args.initials,
3287 "KeyUsage":usage_list, "Surname":args.surname,
3288 "UnstructuredName":args.unstructuredname}
3289 resp = session.post(generateCSRUrl, headers=httpHeader,
3290 json=data, verify=False)
3291 except(requests.exceptions.Timeout):
3292 return(connectionErrHandler(args.json, "Timeout", None))
3293 except(requests.exceptions.ConnectionError) as err:
3294 return connectionErrHandler(args.json, "ConnectionError", err)
3295 if resp.status_code != 200:
3296 print(resp.text)
3297 return "Failed to generate CSR"
3298 else:
3299 print("GenerateCSR complete.")
3300 return resp.text
3301
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003302def enableLDAPConfig(host, args, session):
Ratan Gupta9166cd22018-10-01 18:09:40 +05303303 """
3304 Called by the ldap function. Configures LDAP.
3305
3306 @param host: string, the hostname or IP address of the bmc
3307 @param args: contains additional arguments used by the ldap subcommand
3308 @param session: the active session to use
3309 @param args.json: boolean, if this flag is set to true, the output will
3310 be provided in json format for programmatic consumption
3311 """
3312
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003313 if(isRedfishSupport):
3314 return enableLDAP(host, args, session)
3315 else:
3316 return enableLegacyLDAP(host, args, session)
3317
3318def enableLegacyLDAP(host, args, session):
3319 """
3320 Called by the ldap function. Configures LDAP on Lagecy systems.
3321
3322 @param host: string, the hostname or IP address of the bmc
3323 @param args: contains additional arguments used by the ldap subcommand
3324 @param session: the active session to use
3325 @param args.json: boolean, if this flag is set to true, the output will
3326 be provided in json format for programmatic consumption
3327 """
3328
Ratan Gupta9166cd22018-10-01 18:09:40 +05303329 url='https://'+host+'/xyz/openbmc_project/user/ldap/action/CreateConfig'
Ratan Gupta9166cd22018-10-01 18:09:40 +05303330 scope = {
3331 'sub' : 'xyz.openbmc_project.User.Ldap.Create.SearchScope.sub',
3332 'one' : 'xyz.openbmc_project.User.Ldap.Create.SearchScope.one',
3333 'base': 'xyz.openbmc_project.User.Ldap.Create.SearchScope.base'
3334 }
3335
3336 serverType = {
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003337 'ActiveDirectory' : 'xyz.openbmc_project.User.Ldap.Create.Type.ActiveDirectory',
3338 'OpenLDAP' : 'xyz.openbmc_project.User.Ldap.Create.Type.OpenLdap'
Ratan Gupta9166cd22018-10-01 18:09:40 +05303339 }
3340
3341 data = {"data": [args.uri, args.bindDN, args.baseDN, args.bindPassword, scope[args.scope], serverType[args.serverType]]}
3342
3343 try:
Justin Thaler27197622019-01-23 14:42:11 -06003344 res = session.post(url, headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
Ratan Gupta9166cd22018-10-01 18:09:40 +05303345 except(requests.exceptions.Timeout):
3346 return(connectionErrHandler(args.json, "Timeout", None))
3347 except(requests.exceptions.ConnectionError) as err:
3348 return connectionErrHandler(args.json, "ConnectionError", err)
3349
3350 return res.text
3351
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003352def enableLDAP(host, args, session):
3353 """
3354 Called by the ldap function. Configures LDAP for systems with latest user-manager design changes
3355
3356 @param host: string, the hostname or IP address of the bmc
3357 @param args: contains additional arguments used by the ldap subcommand
3358 @param session: the active session to use
3359 @param args.json: boolean, if this flag is set to true, the output will
3360 be provided in json format for programmatic consumption
3361 """
3362
3363 scope = {
3364 'sub' : 'xyz.openbmc_project.User.Ldap.Config.SearchScope.sub',
3365 'one' : 'xyz.openbmc_project.User.Ldap.Config.SearchScope.one',
3366 'base': 'xyz.openbmc_project.User.Ldap.Config.SearchScope.base'
3367 }
3368
3369 serverType = {
3370 'ActiveDirectory' : 'xyz.openbmc_project.User.Ldap.Config.Type.ActiveDirectory',
3371 'OpenLDAP' : 'xyz.openbmc_project.User.Ldap.Config.Type.OpenLdap'
3372 }
3373
3374 url = "https://"+host+"/xyz/openbmc_project/user/ldap/"
3375
3376 serverTypeEnabled = getLDAPTypeEnabled(host,session)
3377 serverTypeToBeEnabled = args.serverType
3378
3379 #If the given LDAP type is already enabled, then return
3380 if (serverTypeToBeEnabled == serverTypeEnabled):
3381 return("Server type " + serverTypeToBeEnabled + " is already enabled...")
3382
3383 try:
3384
3385 # Copy the role map from the currently enabled LDAP server type
3386 # to the newly enabled server type
3387 # Disable the currently enabled LDAP server type. Unless
3388 # it is disabled, we cannot enable a new LDAP server type
3389 if (serverTypeEnabled is not None):
3390
3391 if (serverTypeToBeEnabled != serverTypeEnabled):
3392 res = syncRoleMap(host,args,session,serverTypeEnabled,serverTypeToBeEnabled)
3393
3394 data = "{\"data\": 0 }"
3395 res = session.put(url + serverTypeMap[serverTypeEnabled] + '/attr/Enabled', headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
3396
3397 data = {"data": args.baseDN}
3398 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/LDAPBaseDN', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
3399 if (res.status_code != requests.codes.ok):
3400 print("Updates to the property LDAPBaseDN failed...")
3401 return(res.text)
3402
3403 data = {"data": args.bindDN}
3404 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/LDAPBindDN', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
3405 if (res.status_code != requests.codes.ok):
3406 print("Updates to the property LDAPBindDN failed...")
3407 return(res.text)
3408
3409 data = {"data": args.bindPassword}
3410 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/LDAPBindDNPassword', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
3411 if (res.status_code != requests.codes.ok):
3412 print("Updates to the property LDAPBindDNPassword failed...")
3413 return(res.text)
3414
3415 data = {"data": scope[args.scope]}
3416 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/LDAPSearchScope', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
3417 if (res.status_code != requests.codes.ok):
3418 print("Updates to the property LDAPSearchScope failed...")
3419 return(res.text)
3420
3421 data = {"data": args.uri}
3422 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/LDAPServerURI', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
3423 if (res.status_code != requests.codes.ok):
3424 print("Updates to the property LDAPServerURI failed...")
3425 return(res.text)
3426
3427 data = {"data": args.groupAttrName}
3428 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/GroupNameAttribute', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
3429 if (res.status_code != requests.codes.ok):
3430 print("Updates to the property GroupNameAttribute failed...")
3431 return(res.text)
3432
3433 data = {"data": args.userAttrName}
3434 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/UserNameAttribute', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
3435 if (res.status_code != requests.codes.ok):
3436 print("Updates to the property UserNameAttribute failed...")
3437 return(res.text)
3438
3439 #After updating the properties, enable the new server type
3440 data = "{\"data\": 1 }"
3441 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/Enabled', headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
3442
3443 except(requests.exceptions.Timeout):
3444 return(connectionErrHandler(args.json, "Timeout", None))
3445 except(requests.exceptions.ConnectionError) as err:
3446 return connectionErrHandler(args.json, "ConnectionError", err)
3447 return res.text
Ratan Gupta9166cd22018-10-01 18:09:40 +05303448
3449def disableLDAP(host, args, session):
3450 """
3451 Called by the ldap function. Deletes the LDAP Configuration.
3452
3453 @param host: string, the hostname or IP address of the bmc
3454 @param args: contains additional arguments used by the ldap subcommand
3455 @param session: the active session to use
3456 @param args.json: boolean, if this flag is set to true, the output
3457 will be provided in json format for programmatic consumption
3458 """
3459
Ratan Gupta9166cd22018-10-01 18:09:40 +05303460 try:
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003461 if (isRedfishSupport) :
3462
3463 url = "https://"+host+"/xyz/openbmc_project/user/ldap/"
3464
3465 serverTypeEnabled = getLDAPTypeEnabled(host,session)
3466
3467 if (serverTypeEnabled is not None):
3468 #To keep the role map in sync,
3469 #If the server type being disabled has role map, then
3470 # - copy the role map to the other server type(s)
3471 for serverType in serverTypeMap.keys():
3472 if (serverType != serverTypeEnabled):
3473 res = syncRoleMap(host,args,session,serverTypeEnabled,serverType)
3474
3475 #Disable the currently enabled LDAP server type
3476 data = "{\"data\": 0 }"
3477 res = session.put(url + serverTypeMap[serverTypeEnabled] + '/attr/Enabled', headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
3478
3479 else:
3480 return("LDAP server has not been enabled...")
3481
3482 else :
3483 url='https://'+host+'/xyz/openbmc_project/user/ldap/config/action/delete'
3484 data = {"data": []}
3485 res = session.post(url, headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
3486
Ratan Gupta9166cd22018-10-01 18:09:40 +05303487 except(requests.exceptions.Timeout):
3488 return(connectionErrHandler(args.json, "Timeout", None))
3489 except(requests.exceptions.ConnectionError) as err:
3490 return connectionErrHandler(args.json, "ConnectionError", err)
3491
3492 return res.text
3493
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003494def enableDHCP(host, args, session):
3495
3496 """
3497 Called by the network function. Enables DHCP.
3498
3499 @param host: string, the hostname or IP address of the bmc
3500 @param args: contains additional arguments used by the ldap subcommand
3501 args.json: boolean, if this flag is set to true, the output
3502 will be provided in json format for programmatic consumption
3503 @param session: the active session to use
3504 """
3505
3506 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3507 "/attr/DHCPEnabled"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003508 data = "{\"data\": 1 }"
3509 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003510 res = session.put(url, headers=jsonHeader, data=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003511 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003512
3513 except(requests.exceptions.Timeout):
3514 return(connectionErrHandler(args.json, "Timeout", None))
3515 except(requests.exceptions.ConnectionError) as err:
3516 return connectionErrHandler(args.json, "ConnectionError", err)
3517 if res.status_code == 403:
3518 return "The specified Interface"+"("+args.Interface+")"+\
3519 " doesn't exist"
3520
3521 return res.text
3522
3523
3524def disableDHCP(host, args, session):
3525 """
3526 Called by the network function. Disables DHCP.
3527
3528 @param host: string, the hostname or IP address of the bmc
3529 @param args: contains additional arguments used by the ldap subcommand
3530 args.json: boolean, if this flag is set to true, the output
3531 will be provided in json format for programmatic consumption
3532 @param session: the active session to use
3533 """
3534
3535 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3536 "/attr/DHCPEnabled"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003537 data = "{\"data\": 0 }"
3538 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003539 res = session.put(url, headers=jsonHeader, data=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003540 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003541 except(requests.exceptions.Timeout):
3542 return(connectionErrHandler(args.json, "Timeout", None))
3543 except(requests.exceptions.ConnectionError) as err:
3544 return connectionErrHandler(args.json, "ConnectionError", err)
3545 if res.status_code == 403:
3546 return "The specified Interface"+"("+args.Interface+")"+\
3547 " doesn't exist"
3548 return res.text
3549
3550
3551def getHostname(host, args, session):
3552
3553 """
3554 Called by the network function. Prints out the Hostname.
3555
3556 @param host: string, the hostname or IP address of the bmc
3557 @param args: contains additional arguments used by the ldap subcommand
3558 args.json: boolean, if this flag is set to true, the output
3559 will be provided in json format for programmatic consumption
3560 @param session: the active session to use
3561 """
3562
3563 url = "https://"+host+"/xyz/openbmc_project/network/config/attr/HostName"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003564
3565 try:
Justin Thaler27197622019-01-23 14:42:11 -06003566 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003567 except(requests.exceptions.Timeout):
3568 return(connectionErrHandler(args.json, "Timeout", None))
3569 except(requests.exceptions.ConnectionError) as err:
3570 return connectionErrHandler(args.json, "ConnectionError", err)
3571
3572 return res.text
3573
3574
3575def setHostname(host, args, session):
3576 """
3577 Called by the network function. Sets the Hostname.
3578
3579 @param host: string, the hostname or IP address of the bmc
3580 @param args: contains additional arguments used by the ldap subcommand
3581 args.json: boolean, if this flag is set to true, the output
3582 will be provided in json format for programmatic consumption
3583 @param session: the active session to use
3584 """
3585
3586 url = "https://"+host+"/xyz/openbmc_project/network/config/attr/HostName"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003587
3588 data = {"data": args.HostName}
3589
3590 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003591 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003592 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003593 except(requests.exceptions.Timeout):
3594 return(connectionErrHandler(args.json, "Timeout", None))
3595 except(requests.exceptions.ConnectionError) as err:
3596 return connectionErrHandler(args.json, "ConnectionError", err)
3597
3598 return res.text
3599
3600
3601def getDomainName(host, args, session):
3602
3603 """
3604 Called by the network function. Prints out the DomainName.
3605
3606 @param host: string, the hostname or IP address of the bmc
3607 @param args: contains additional arguments used by the ldap subcommand
3608 args.json: boolean, if this flag is set to true, the output
3609 will be provided in json format for programmatic consumption
3610 @param session: the active session to use
3611 """
3612
3613 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3614 "/attr/DomainName"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003615
3616 try:
Justin Thaler27197622019-01-23 14:42:11 -06003617 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003618 except(requests.exceptions.Timeout):
3619 return(connectionErrHandler(args.json, "Timeout", None))
3620 except(requests.exceptions.ConnectionError) as err:
3621 return connectionErrHandler(args.json, "ConnectionError", err)
3622 if res.status_code == 404:
Sunitha Harishf9bb2fa2019-09-19 01:48:00 -05003623 return "The DomainName is not configured on Interface"+"("+args.Interface+")"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003624
3625 return res.text
3626
3627
3628def setDomainName(host, args, session):
3629 """
3630 Called by the network function. Sets the DomainName.
3631
3632 @param host: string, the hostname or IP address of the bmc
3633 @param args: contains additional arguments used by the ldap subcommand
3634 args.json: boolean, if this flag is set to true, the output
3635 will be provided in json format for programmatic consumption
3636 @param session: the active session to use
3637 """
3638
3639 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3640 "/attr/DomainName"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003641
3642 data = {"data": args.DomainName.split(",")}
3643
3644 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003645 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003646 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003647 except(requests.exceptions.Timeout):
3648 return(connectionErrHandler(args.json, "Timeout", None))
3649 except(requests.exceptions.ConnectionError) as err:
3650 return connectionErrHandler(args.json, "ConnectionError", err)
3651 if res.status_code == 403:
3652 return "The specified Interface"+"("+args.Interface+")"+\
3653 " doesn't exist"
3654
3655 return res.text
3656
3657
3658def getMACAddress(host, args, session):
3659
3660 """
3661 Called by the network function. Prints out the MACAddress.
3662
3663 @param host: string, the hostname or IP address of the bmc
3664 @param args: contains additional arguments used by the ldap subcommand
3665 args.json: boolean, if this flag is set to true, the output
3666 will be provided in json format for programmatic consumption
3667 @param session: the active session to use
3668 """
3669
3670 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3671 "/attr/MACAddress"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003672
3673 try:
Justin Thaler27197622019-01-23 14:42:11 -06003674 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003675 except(requests.exceptions.Timeout):
3676 return(connectionErrHandler(args.json, "Timeout", None))
3677 except(requests.exceptions.ConnectionError) as err:
3678 return connectionErrHandler(args.json, "ConnectionError", err)
3679 if res.status_code == 404:
3680 return "The specified Interface"+"("+args.Interface+")"+\
3681 " doesn't exist"
3682
3683 return res.text
3684
3685
3686def setMACAddress(host, args, session):
3687 """
3688 Called by the network function. Sets the MACAddress.
3689
3690 @param host: string, the hostname or IP address of the bmc
3691 @param args: contains additional arguments used by the ldap subcommand
3692 args.json: boolean, if this flag is set to true, the output
3693 will be provided in json format for programmatic consumption
3694 @param session: the active session to use
3695 """
3696
3697 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3698 "/attr/MACAddress"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003699
3700 data = {"data": args.MACAddress}
3701
3702 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003703 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003704 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003705 except(requests.exceptions.Timeout):
3706 return(connectionErrHandler(args.json, "Timeout", None))
3707 except(requests.exceptions.ConnectionError) as err:
3708 return connectionErrHandler(args.json, "ConnectionError", err)
3709 if res.status_code == 403:
3710 return "The specified Interface"+"("+args.Interface+")"+\
3711 " doesn't exist"
3712
3713 return res.text
3714
3715
3716def getDefaultGateway(host, args, session):
3717
3718 """
3719 Called by the network function. Prints out the DefaultGateway.
3720
3721 @param host: string, the hostname or IP address of the bmc
3722 @param args: contains additional arguments used by the ldap subcommand
3723 args.json: boolean, if this flag is set to true, the output
3724 will be provided in json format for programmatic consumption
3725 @param session: the active session to use
3726 """
3727
3728 url = "https://"+host+"/xyz/openbmc_project/network/config/attr/DefaultGateway"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003729
3730 try:
Justin Thaler27197622019-01-23 14:42:11 -06003731 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003732 except(requests.exceptions.Timeout):
3733 return(connectionErrHandler(args.json, "Timeout", None))
3734 except(requests.exceptions.ConnectionError) as err:
3735 return connectionErrHandler(args.json, "ConnectionError", err)
3736 if res.status_code == 404:
3737 return "Failed to get Default Gateway info!!"
3738
3739 return res.text
3740
3741
3742def setDefaultGateway(host, args, session):
3743 """
3744 Called by the network function. Sets the DefaultGateway.
3745
3746 @param host: string, the hostname or IP address of the bmc
3747 @param args: contains additional arguments used by the ldap subcommand
3748 args.json: boolean, if this flag is set to true, the output
3749 will be provided in json format for programmatic consumption
3750 @param session: the active session to use
3751 """
3752
3753 url = "https://"+host+"/xyz/openbmc_project/network/config/attr/DefaultGateway"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003754
3755 data = {"data": args.DefaultGW}
3756
3757 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003758 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003759 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003760 except(requests.exceptions.Timeout):
3761 return(connectionErrHandler(args.json, "Timeout", None))
3762 except(requests.exceptions.ConnectionError) as err:
3763 return connectionErrHandler(args.json, "ConnectionError", err)
3764 if res.status_code == 403:
3765 return "Failed to set Default Gateway!!"
3766
3767 return res.text
3768
3769
3770def viewNWConfig(host, args, session):
3771 """
3772 Called by the ldap function. Prints out network configured properties
3773
3774 @param host: string, the hostname or IP address of the bmc
3775 @param args: contains additional arguments used by the ldap subcommand
3776 args.json: boolean, if this flag is set to true, the output
3777 will be provided in json format for programmatic consumption
3778 @param session: the active session to use
3779 @return returns LDAP's configured properties.
3780 """
3781 url = "https://"+host+"/xyz/openbmc_project/network/enumerate"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003782 try:
Justin Thaler27197622019-01-23 14:42:11 -06003783 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003784 except(requests.exceptions.Timeout):
3785 return(connectionErrHandler(args.json, "Timeout", None))
3786 except(requests.exceptions.ConnectionError) as err:
3787 return connectionErrHandler(args.json, "ConnectionError", err)
3788 except(requests.exceptions.RequestException) as err:
3789 return connectionErrHandler(args.json, "RequestException", err)
3790 if res.status_code == 404:
3791 return "LDAP server config has not been created"
3792 return res.text
3793
3794
3795def getDNS(host, args, session):
3796
3797 """
3798 Called by the network function. Prints out DNS servers on the interface
3799
3800 @param host: string, the hostname or IP address of the bmc
3801 @param args: contains additional arguments used by the ldap subcommand
3802 args.json: boolean, if this flag is set to true, the output
3803 will be provided in json format for programmatic consumption
3804 @param session: the active session to use
3805 """
3806
3807 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
3808 + "/attr/Nameservers"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003809
3810 try:
Justin Thaler27197622019-01-23 14:42:11 -06003811 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003812 except(requests.exceptions.Timeout):
3813 return(connectionErrHandler(args.json, "Timeout", None))
3814 except(requests.exceptions.ConnectionError) as err:
3815 return connectionErrHandler(args.json, "ConnectionError", err)
3816 if res.status_code == 404:
Sunitha Harishf9bb2fa2019-09-19 01:48:00 -05003817 return "The NameServer is not configured on Interface"+"("+args.Interface+")"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003818
3819 return res.text
3820
3821
3822def setDNS(host, args, session):
3823 """
3824 Called by the network function. Sets DNS servers on the interface.
3825
3826 @param host: string, the hostname or IP address of the bmc
3827 @param args: contains additional arguments used by the ldap subcommand
3828 args.json: boolean, if this flag is set to true, the output
3829 will be provided in json format for programmatic consumption
3830 @param session: the active session to use
3831 """
3832
3833 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
3834 + "/attr/Nameservers"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003835
3836 data = {"data": args.DNSServers.split(",")}
3837
3838 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003839 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003840 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003841 except(requests.exceptions.Timeout):
3842 return(connectionErrHandler(args.json, "Timeout", None))
3843 except(requests.exceptions.ConnectionError) as err:
3844 return connectionErrHandler(args.json, "ConnectionError", err)
3845 if res.status_code == 403:
3846 return "The specified Interface"+"("+args.Interface+")" +\
3847 " doesn't exist"
3848
3849 return res.text
3850
3851
3852def getNTP(host, args, session):
3853
3854 """
3855 Called by the network function. Prints out NTP servers on the interface
3856
3857 @param host: string, the hostname or IP address of the bmc
3858 @param args: contains additional arguments used by the ldap subcommand
3859 args.json: boolean, if this flag is set to true, the output
3860 will be provided in json format for programmatic consumption
3861 @param session: the active session to use
3862 """
3863
3864 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
3865 + "/attr/NTPServers"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003866 try:
Justin Thaler27197622019-01-23 14:42:11 -06003867 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003868 except(requests.exceptions.Timeout):
3869 return(connectionErrHandler(args.json, "Timeout", None))
3870 except(requests.exceptions.ConnectionError) as err:
3871 return connectionErrHandler(args.json, "ConnectionError", err)
3872 if res.status_code == 404:
Sunitha Harishf9bb2fa2019-09-19 01:48:00 -05003873 return "The NTPServer is not configured on Interface"+"("+args.Interface+")"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003874
3875 return res.text
3876
3877
3878def setNTP(host, args, session):
3879 """
3880 Called by the network function. Sets NTP servers on the interface.
3881
3882 @param host: string, the hostname or IP address of the bmc
3883 @param args: contains additional arguments used by the ldap subcommand
3884 args.json: boolean, if this flag is set to true, the output
3885 will be provided in json format for programmatic consumption
3886 @param session: the active session to use
3887 """
3888
3889 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
3890 + "/attr/NTPServers"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003891
3892 data = {"data": args.NTPServers.split(",")}
3893
3894 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003895 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003896 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003897 except(requests.exceptions.Timeout):
3898 return(connectionErrHandler(args.json, "Timeout", None))
3899 except(requests.exceptions.ConnectionError) as err:
3900 return connectionErrHandler(args.json, "ConnectionError", err)
3901 if res.status_code == 403:
3902 return "The specified Interface"+"("+args.Interface+")" +\
3903 " doesn't exist"
3904
3905 return res.text
3906
3907
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003908def addIP(host, args, session):
3909 """
3910 Called by the network function. Configures IP address on given interface
3911
3912 @param host: string, the hostname or IP address of the bmc
3913 @param args: contains additional arguments used by the ldap subcommand
3914 args.json: boolean, if this flag is set to true, the output
3915 will be provided in json format for programmatic consumption
3916 @param session: the active session to use
3917 """
3918
3919 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
3920 + "/action/IP"
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003921 protocol = {
3922 'ipv4': 'xyz.openbmc_project.Network.IP.Protocol.IPv4',
3923 'ipv6': 'xyz.openbmc_project.Network.IP.Protocol.IPv6'
3924 }
3925
3926 data = {"data": [protocol[args.type], args.address, int(args.prefixLength),
3927 args.gateway]}
3928
3929 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003930 res = session.post(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003931 timeout=baseTimeout)
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003932 except(requests.exceptions.Timeout):
3933 return(connectionErrHandler(args.json, "Timeout", None))
3934 except(requests.exceptions.ConnectionError) as err:
3935 return connectionErrHandler(args.json, "ConnectionError", err)
3936 if res.status_code == 404:
3937 return "The specified Interface" + "(" + args.Interface + ")" +\
3938 " doesn't exist"
3939
3940 return res.text
3941
3942
3943def getIP(host, args, session):
3944 """
3945 Called by the network function. Prints out IP address of given interface
3946
3947 @param host: string, the hostname or IP address of the bmc
3948 @param args: contains additional arguments used by the ldap subcommand
3949 args.json: boolean, if this flag is set to true, the output
3950 will be provided in json format for programmatic consumption
3951 @param session: the active session to use
3952 """
3953
3954 url = "https://" + host+"/xyz/openbmc_project/network/" + args.Interface +\
3955 "/enumerate"
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003956 try:
Justin Thaler27197622019-01-23 14:42:11 -06003957 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003958 except(requests.exceptions.Timeout):
3959 return(connectionErrHandler(args.json, "Timeout", None))
3960 except(requests.exceptions.ConnectionError) as err:
3961 return connectionErrHandler(args.json, "ConnectionError", err)
3962 if res.status_code == 404:
3963 return "The specified Interface" + "(" + args.Interface + ")" +\
3964 " doesn't exist"
3965
3966 return res.text
3967
3968
3969def deleteIP(host, args, session):
3970 """
3971 Called by the network function. Deletes the IP address from given Interface
3972
3973 @param host: string, the hostname or IP address of the bmc
3974 @param args: contains additional arguments used by the ldap subcommand
3975 @param session: the active session to use
3976 @param args.json: boolean, if this flag is set to true, the output
3977 will be provided in json format for programmatic consumption
3978 """
3979
3980 url = "https://"+host+"/xyz/openbmc_project/network/" + args.Interface+\
3981 "/enumerate"
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003982 data = {"data": []}
3983 try:
Justin Thaler27197622019-01-23 14:42:11 -06003984 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003985 except(requests.exceptions.Timeout):
3986 return(connectionErrHandler(args.json, "Timeout", None))
3987 except(requests.exceptions.ConnectionError) as err:
3988 return connectionErrHandler(args.json, "ConnectionError", err)
3989 if res.status_code == 404:
3990 return "The specified Interface" + "(" + args.Interface + ")" +\
3991 " doesn't exist"
3992 objDict = json.loads(res.text)
3993 if not objDict['data']:
3994 return "No object found for given address on given Interface"
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003995 for obj in objDict['data']:
Sunitha Harish0baf6372019-07-31 03:59:03 -05003996 try:
3997 if args.address in objDict['data'][obj]['Address']:
3998 url = "https://"+host+obj+"/action/Delete"
3999 try:
4000 res = session.post(url, headers=jsonHeader, json=data,
4001 verify=False, timeout=baseTimeout)
4002 except(requests.exceptions.Timeout):
4003 return(connectionErrHandler(args.json, "Timeout", None))
4004 except(requests.exceptions.ConnectionError) as err:
4005 return connectionErrHandler(args.json, "ConnectionError", err)
4006 return res.text
4007 else:
4008 continue
4009 except KeyError:
Sunitha Harishf9bb2fa2019-09-19 01:48:00 -05004010 continue
4011 return "No object found for address " + args.address + \
4012 " on Interface(" + args.Interface + ")"
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004013
4014
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004015def addVLAN(host, args, session):
4016 """
4017 Called by the network function. Creates VLAN on given interface.
4018
4019 @param host: string, the hostname or IP address of the bmc
4020 @param args: contains additional arguments used by the ldap subcommand
4021 args.json: boolean, if this flag is set to true, the output
4022 will be provided in json format for programmatic consumption
4023 @param session: the active session to use
4024 """
4025
4026 url = "https://" + host+"/xyz/openbmc_project/network/action/VLAN"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004027
Sunitha Harish0baf6372019-07-31 03:59:03 -05004028 data = {"data": [args.Interface,int(args.Identifier)]}
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004029 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06004030 res = session.post(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06004031 timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004032 except(requests.exceptions.Timeout):
4033 return(connectionErrHandler(args.json, "Timeout", None))
4034 except(requests.exceptions.ConnectionError) as err:
4035 return connectionErrHandler(args.json, "ConnectionError", err)
4036 if res.status_code == 400:
Sunitha Harish0baf6372019-07-31 03:59:03 -05004037 return "Adding VLAN to interface" + "(" + args.Interface + ")" +\
4038 " failed"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004039
4040 return res.text
4041
4042
4043def deleteVLAN(host, args, session):
4044 """
4045 Called by the network function. Creates VLAN on given interface.
4046
4047 @param host: string, the hostname or IP address of the bmc
4048 @param args: contains additional arguments used by the ldap subcommand
4049 args.json: boolean, if this flag is set to true, the output
4050 will be provided in json format for programmatic consumption
4051 @param session: the active session to use
4052 """
4053
Sunitha Harish577a5032019-08-08 06:27:40 -05004054 url = "https://" + host+"/xyz/openbmc_project/network/"+args.Interface+"/action/Delete"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004055 data = {"data": []}
4056
4057 try:
Justin Thaler27197622019-01-23 14:42:11 -06004058 res = session.post(url, headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004059 except(requests.exceptions.Timeout):
4060 return(connectionErrHandler(args.json, "Timeout", None))
4061 except(requests.exceptions.ConnectionError) as err:
4062 return connectionErrHandler(args.json, "ConnectionError", err)
4063 if res.status_code == 404:
Sunitha Harish577a5032019-08-08 06:27:40 -05004064 return "The specified VLAN"+"("+args.Interface+")" +" doesn't exist"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004065
4066 return res.text
4067
4068
4069def viewDHCPConfig(host, args, session):
4070 """
4071 Called by the network function. Shows DHCP configured Properties.
4072
4073 @param host: string, the hostname or IP address of the bmc
4074 @param args: contains additional arguments used by the ldap subcommand
4075 args.json: boolean, if this flag is set to true, the output
4076 will be provided in json format for programmatic consumption
4077 @param session: the active session to use
4078 """
4079
4080 url="https://"+host+"/xyz/openbmc_project/network/config/dhcp"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004081
4082 try:
Justin Thaler27197622019-01-23 14:42:11 -06004083 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004084 except(requests.exceptions.Timeout):
4085 return(connectionErrHandler(args.json, "Timeout", None))
4086 except(requests.exceptions.ConnectionError) as err:
4087 return connectionErrHandler(args.json, "ConnectionError", err)
4088
4089 return res.text
4090
4091
4092def configureDHCP(host, args, session):
4093 """
4094 Called by the network function. Configures/updates DHCP Properties.
4095
4096 @param host: string, the hostname or IP address of the bmc
4097 @param args: contains additional arguments used by the ldap subcommand
4098 args.json: boolean, if this flag is set to true, the output
4099 will be provided in json format for programmatic consumption
4100 @param session: the active session to use
4101 """
4102
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004103
4104 try:
4105 url="https://"+host+"/xyz/openbmc_project/network/config/dhcp"
4106 if(args.DNSEnabled == True):
4107 data = '{"data": 1}'
4108 else:
4109 data = '{"data": 0}'
Matt Spinler220c3c42019-01-04 15:09:29 -06004110 res = session.put(url + '/attr/DNSEnabled', headers=jsonHeader,
Justin Thaler27197622019-01-23 14:42:11 -06004111 data=data, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004112 if(args.HostNameEnabled == True):
4113 data = '{"data": 1}'
4114 else:
4115 data = '{"data": 0}'
Matt Spinler220c3c42019-01-04 15:09:29 -06004116 res = session.put(url + '/attr/HostNameEnabled', headers=jsonHeader,
Justin Thaler27197622019-01-23 14:42:11 -06004117 data=data, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004118 if(args.NTPEnabled == True):
4119 data = '{"data": 1}'
4120 else:
4121 data = '{"data": 0}'
Matt Spinler220c3c42019-01-04 15:09:29 -06004122 res = session.put(url + '/attr/NTPEnabled', headers=jsonHeader,
Justin Thaler27197622019-01-23 14:42:11 -06004123 data=data, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004124 if(args.SendHostNameEnabled == True):
4125 data = '{"data": 1}'
4126 else:
4127 data = '{"data": 0}'
Matt Spinler220c3c42019-01-04 15:09:29 -06004128 res = session.put(url + '/attr/SendHostNameEnabled', headers=jsonHeader,
Justin Thaler27197622019-01-23 14:42:11 -06004129 data=data, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004130 except(requests.exceptions.Timeout):
4131 return(connectionErrHandler(args.json, "Timeout", None))
4132 except(requests.exceptions.ConnectionError) as err:
4133 return connectionErrHandler(args.json, "ConnectionError", err)
4134
4135 return res.text
4136
4137
4138def nwReset(host, args, session):
4139
4140 """
4141 Called by the network function. Resets networks setting to factory defaults.
4142
4143 @param host: string, the hostname or IP address of the bmc
4144 @param args: contains additional arguments used by the ldap subcommand
4145 args.json: boolean, if this flag is set to true, the output
4146 will be provided in json format for programmatic consumption
4147 @param session: the active session to use
4148 """
4149
4150 url = "https://"+host+"/xyz/openbmc_project/network/action/Reset"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004151 data = '{"data":[] }'
4152 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06004153 res = session.post(url, headers=jsonHeader, data=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06004154 timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004155
4156 except(requests.exceptions.Timeout):
4157 return(connectionErrHandler(args.json, "Timeout", None))
4158 except(requests.exceptions.ConnectionError) as err:
4159 return connectionErrHandler(args.json, "ConnectionError", err)
4160
4161 return res.text
4162
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004163def getLDAPTypeEnabled(host,session):
4164
4165 """
4166 Called by LDAP related functions to find the LDAP server type that has been enabled.
4167 Returns None if LDAP has not been configured.
4168
4169 @param host: string, the hostname or IP address of the bmc
4170 @param session: the active session to use
4171 """
4172
4173 enabled = False
4174 url = 'https://'+host+'/xyz/openbmc_project/user/ldap/'
4175 for key,value in serverTypeMap.items():
4176 data = {"data": []}
4177 try:
4178 res = session.get(url + value + '/attr/Enabled', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
4179 except(requests.exceptions.Timeout):
4180 print(connectionErrHandler(args.json, "Timeout", None))
4181 return
4182 except(requests.exceptions.ConnectionError) as err:
4183 print(connectionErrHandler(args.json, "ConnectionError", err))
4184 return
4185
4186 enabled = res.json()['data']
4187 if (enabled):
4188 return key
4189
4190def syncRoleMap(host,args,session,fromServerType,toServerType):
4191
4192 """
4193 Called by LDAP related functions to sync the role maps
4194 Returns False if LDAP has not been configured.
4195
4196 @param host: string, the hostname or IP address of the bmc
4197 @param session: the active session to use
4198 @param fromServerType : Server type whose role map has to be copied
4199 @param toServerType : Server type to which role map has to be copied
4200 """
4201
4202 url = "https://"+host+"/xyz/openbmc_project/user/ldap/"
4203
4204 try:
4205 #Note: If the fromServerType has no role map, then
4206 #the toServerType will not have any role map.
4207
4208 #delete the privilege mapping from the toServerType and
4209 #then copy the privilege mapping from fromServerType to
4210 #toServerType.
4211 args.serverType = toServerType
4212 res = deleteAllPrivilegeMapping(host, args, session)
4213
4214 data = {"data": []}
4215 res = session.get(url + serverTypeMap[fromServerType] + '/role_map/enumerate', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
4216 #Previously enabled server type has no role map
4217 if (res.status_code != requests.codes.ok):
4218
4219 #fromServerType has no role map; So, no need to copy
4220 #role map to toServerType.
4221 return
4222
4223 objDict = json.loads(res.text)
4224 dataDict = objDict['data']
4225 for key,value in dataDict.items():
4226 data = {"data": [value["GroupName"], value["Privilege"]]}
4227 res = session.post(url + serverTypeMap[toServerType] + '/action/Create', headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
4228
4229 except(requests.exceptions.Timeout):
4230 return(connectionErrHandler(args.json, "Timeout", None))
4231 except(requests.exceptions.ConnectionError) as err:
4232 return connectionErrHandler(args.json, "ConnectionError", err)
4233 return res.text
4234
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004235
Ratan Guptafeee6372018-10-17 23:25:51 +05304236def createPrivilegeMapping(host, args, session):
4237 """
4238 Called by the ldap function. Creates the group and the privilege mapping.
4239
4240 @param host: string, the hostname or IP address of the bmc
4241 @param args: contains additional arguments used by the ldap subcommand
4242 @param session: the active session to use
4243 @param args.json: boolean, if this flag is set to true, the output
4244 will be provided in json format for programmatic consumption
4245 """
4246
Ratan Guptafeee6372018-10-17 23:25:51 +05304247 try:
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004248 if (isRedfishSupport):
4249 url = 'https://'+host+'/xyz/openbmc_project/user/ldap/'
4250
4251 #To maintain the interface compatibility between op930 and op940, the server type has been made
4252 #optional. If the server type is not specified, then create the role-mapper for the currently
4253 #enabled server type.
4254 serverType = args.serverType
4255 if (serverType is None):
4256 serverType = getLDAPTypeEnabled(host,session)
4257 if (serverType is None):
4258 return("LDAP server has not been enabled. Please specify LDAP serverType to proceed further...")
4259
4260 data = {"data": [args.groupName,args.privilege]}
4261 res = session.post(url + serverTypeMap[serverType] + '/action/Create', headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
4262
4263 else:
4264 url = 'https://'+host+'/xyz/openbmc_project/user/ldap/action/Create'
4265 data = {"data": [args.groupName,args.privilege]}
4266 res = session.post(url, headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
4267
Ratan Guptafeee6372018-10-17 23:25:51 +05304268 except(requests.exceptions.Timeout):
4269 return(connectionErrHandler(args.json, "Timeout", None))
4270 except(requests.exceptions.ConnectionError) as err:
4271 return connectionErrHandler(args.json, "ConnectionError", err)
4272 return res.text
4273
4274def listPrivilegeMapping(host, args, session):
4275 """
4276 Called by the ldap function. Lists the group and the privilege mapping.
4277
4278 @param host: string, the hostname or IP address of the bmc
4279 @param args: contains additional arguments used by the ldap subcommand
4280 @param session: the active session to use
4281 @param args.json: boolean, if this flag is set to true, the output
4282 will be provided in json format for programmatic consumption
4283 """
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004284
4285 if (isRedfishSupport):
4286 serverType = args.serverType
4287 if (serverType is None):
4288 serverType = getLDAPTypeEnabled(host,session)
4289 if (serverType is None):
4290 return("LDAP has not been enabled. Please specify LDAP serverType to proceed further...")
4291
4292 url = 'https://'+host+'/xyz/openbmc_project/user/ldap/'+serverTypeMap[serverType]+'/role_map/enumerate'
4293
4294 else:
4295 url = 'https://'+host+'/xyz/openbmc_project/user/ldap/enumerate'
4296
Ratan Guptafeee6372018-10-17 23:25:51 +05304297 data = {"data": []}
4298
4299 try:
Justin Thaler27197622019-01-23 14:42:11 -06004300 res = session.get(url, headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
Ratan Guptafeee6372018-10-17 23:25:51 +05304301 except(requests.exceptions.Timeout):
4302 return(connectionErrHandler(args.json, "Timeout", None))
4303 except(requests.exceptions.ConnectionError) as err:
4304 return connectionErrHandler(args.json, "ConnectionError", err)
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004305
Ratan Guptafeee6372018-10-17 23:25:51 +05304306 return res.text
4307
4308def deletePrivilegeMapping(host, args, session):
4309 """
4310 Called by the ldap function. Deletes the mapping associated with the group.
4311
4312 @param host: string, the hostname or IP address of the bmc
4313 @param args: contains additional arguments used by the ldap subcommand
4314 @param session: the active session to use
4315 @param args.json: boolean, if this flag is set to true, the output
4316 will be provided in json format for programmatic consumption
4317 """
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004318
4319 ldapNameSpaceObjects = listPrivilegeMapping(host, args, session)
Ratan Guptafeee6372018-10-17 23:25:51 +05304320 ldapNameSpaceObjects = json.loads(ldapNameSpaceObjects)["data"]
4321 path = ''
Ratan Guptafeee6372018-10-17 23:25:51 +05304322 data = {"data": []}
4323
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004324 if (isRedfishSupport):
4325 if (args.serverType is None):
4326 serverType = getLDAPTypeEnabled(host,session)
4327 if (serverType is None):
4328 return("LDAP has not been enabled. Please specify LDAP serverType to proceed further...")
4329 # search for the object having the mapping for the given group
4330 for key,value in ldapNameSpaceObjects.items():
4331 if value['GroupName'] == args.groupName:
4332 path = key
4333 break
4334
4335 if path == '':
4336 return "No privilege mapping found for this group."
4337
4338 # delete the object
4339 url = 'https://'+host+path+'/action/Delete'
4340
4341 else:
4342 # not interested in the config objet
4343 ldapNameSpaceObjects.pop('/xyz/openbmc_project/user/ldap/config', None)
4344
4345 # search for the object having the mapping for the given group
4346 for key,value in ldapNameSpaceObjects.items():
4347 if value['GroupName'] == args.groupName:
4348 path = key
4349 break
4350
4351 if path == '':
4352 return "No privilege mapping found for this group."
4353
4354 # delete the object
4355 url = 'https://'+host+path+'/action/delete'
4356
Ratan Guptafeee6372018-10-17 23:25:51 +05304357 try:
Justin Thaler27197622019-01-23 14:42:11 -06004358 res = session.post(url, headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
Ratan Guptafeee6372018-10-17 23:25:51 +05304359 except(requests.exceptions.Timeout):
4360 return(connectionErrHandler(args.json, "Timeout", None))
4361 except(requests.exceptions.ConnectionError) as err:
4362 return connectionErrHandler(args.json, "ConnectionError", err)
4363 return res.text
Ratan Gupta9166cd22018-10-01 18:09:40 +05304364
Sivas SRR78835272018-11-27 05:27:19 -06004365def deleteAllPrivilegeMapping(host, args, session):
4366 """
4367 Called by the ldap function. Deletes all the privilege mapping and group defined.
4368 @param host: string, the hostname or IP address of the bmc
4369 @param args: contains additional arguments used by the ldap subcommand
4370 @param session: the active session to use
4371 @param args.json: boolean, if this flag is set to true, the output
4372 will be provided in json format for programmatic consumption
4373 """
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004374
Sivas SRR78835272018-11-27 05:27:19 -06004375 ldapNameSpaceObjects = listPrivilegeMapping(host, args, session)
4376 ldapNameSpaceObjects = json.loads(ldapNameSpaceObjects)["data"]
4377 path = ''
Sivas SRR78835272018-11-27 05:27:19 -06004378 data = {"data": []}
4379
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004380 if (isRedfishSupport):
4381 if (args.serverType is None):
4382 serverType = getLDAPTypeEnabled(host,session)
4383 if (serverType is None):
4384 return("LDAP has not been enabled. Please specify LDAP serverType to proceed further...")
4385
4386 else:
4387 # Remove the config object.
4388 ldapNameSpaceObjects.pop('/xyz/openbmc_project/user/ldap/config', None)
4389
Sivas SRR78835272018-11-27 05:27:19 -06004390 try:
4391 # search for GroupName property and delete if it is available.
4392 for path in ldapNameSpaceObjects.keys():
4393 # delete the object
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004394 url = 'https://'+host+path+'/action/Delete'
Justin Thaler27197622019-01-23 14:42:11 -06004395 res = session.post(url, headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004396
Sivas SRR78835272018-11-27 05:27:19 -06004397 except(requests.exceptions.Timeout):
4398 return(connectionErrHandler(args.json, "Timeout", None))
4399 except(requests.exceptions.ConnectionError) as err:
4400 return connectionErrHandler(args.json, "ConnectionError", err)
4401 return res.text
4402
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06004403def viewLDAPConfig(host, args, session):
4404 """
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004405 Called by the ldap function. Prints out active LDAP configuration properties
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06004406
4407 @param host: string, the hostname or IP address of the bmc
4408 @param args: contains additional arguments used by the ldap subcommand
4409 args.json: boolean, if this flag is set to true, the output
4410 will be provided in json format for programmatic consumption
4411 @param session: the active session to use
4412 @return returns LDAP's configured properties.
4413 """
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004414
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06004415 try:
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004416 if (isRedfishSupport):
4417
4418 url = "https://"+host+"/xyz/openbmc_project/user/ldap/"
4419
4420 serverTypeEnabled = getLDAPTypeEnabled(host,session)
4421
4422 if (serverTypeEnabled is not None):
4423 data = {"data": []}
4424 res = session.get(url + serverTypeMap[serverTypeEnabled], headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
4425 else:
4426 return("LDAP server has not been enabled...")
4427
4428 else :
4429 url = "https://"+host+"/xyz/openbmc_project/user/ldap/config"
4430 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
4431
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06004432 except(requests.exceptions.Timeout):
4433 return(connectionErrHandler(args.json, "Timeout", None))
4434 except(requests.exceptions.ConnectionError) as err:
4435 return connectionErrHandler(args.json, "ConnectionError", err)
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06004436 if res.status_code == 404:
4437 return "LDAP server config has not been created"
4438 return res.text
4439
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004440def str2bool(v):
4441 if v.lower() in ('yes', 'true', 't', 'y', '1'):
4442 return True
4443 elif v.lower() in ('no', 'false', 'f', 'n', '0'):
4444 return False
4445 else:
4446 raise argparse.ArgumentTypeError('Boolean value expected.')
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06004447
Matt Spinler7d426c22018-09-24 14:42:07 -05004448def localUsers(host, args, session):
4449 """
4450 Enables and disables local BMC users.
4451
4452 @param host: string, the hostname or IP address of the bmc
4453 @param args: contains additional arguments used by the logging sub command
4454 @param session: the active session to use
4455 """
4456
Matt Spinler7d426c22018-09-24 14:42:07 -05004457 url="https://{hostname}/xyz/openbmc_project/user/enumerate".format(hostname=host)
4458 try:
Justin Thaler27197622019-01-23 14:42:11 -06004459 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Matt Spinler7d426c22018-09-24 14:42:07 -05004460 except(requests.exceptions.Timeout):
4461 return(connectionErrHandler(args.json, "Timeout", None))
4462 usersDict = json.loads(res.text)
4463
4464 if not usersDict['data']:
4465 return "No users found"
4466
4467 output = ""
4468 for user in usersDict['data']:
Matt Spinler015adc22018-10-23 14:30:19 -05004469
4470 # Skip LDAP and another non-local users
4471 if 'UserEnabled' not in usersDict['data'][user]:
4472 continue
4473
Matt Spinler7d426c22018-09-24 14:42:07 -05004474 name = user.split('/')[-1]
4475 url = "https://{hostname}{user}/attr/UserEnabled".format(hostname=host, user=user)
4476
4477 if args.local_users == "queryenabled":
4478 try:
Justin Thaler27197622019-01-23 14:42:11 -06004479 res = session.get(url, headers=jsonHeader,verify=False, timeout=baseTimeout)
Matt Spinler7d426c22018-09-24 14:42:07 -05004480 except(requests.exceptions.Timeout):
4481 return(connectionErrHandler(args.json, "Timeout", None))
4482
4483 result = json.loads(res.text)
4484 output += ("User: {name} Enabled: {result}\n").format(name=name, result=result['data'])
4485
4486 elif args.local_users in ["enableall", "disableall"]:
4487 action = ""
4488 if args.local_users == "enableall":
4489 data = '{"data": true}'
4490 action = "Enabling"
4491 else:
4492 data = '{"data": false}'
4493 action = "Disabling"
4494
4495 output += "{action} {name}\n".format(action=action, name=name)
4496
4497 try:
Justin Thaler27197622019-01-23 14:42:11 -06004498 resp = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Matt Spinler7d426c22018-09-24 14:42:07 -05004499 except(requests.exceptions.Timeout):
4500 return connectionErrHandler(args.json, "Timeout", None)
4501 except(requests.exceptions.ConnectionError) as err:
4502 return connectionErrHandler(args.json, "ConnectionError", err)
4503 else:
4504 return "Invalid local users argument"
4505
4506 return output
4507
Marri Devender Rao2c2a5162018-11-05 08:57:11 -06004508def setPassword(host, args, session):
4509 """
4510 Set local user password
4511 @param host: string, the hostname or IP address of the bmc
4512 @param args: contains additional arguments used by the logging sub
4513 command
4514 @param session: the active session to use
4515 @param args.json: boolean, if this flag is set to true, the output
4516 will be provided in json format for programmatic consumption
4517 @return: Session object
4518 """
Marri Devender Rao2c2a5162018-11-05 08:57:11 -06004519 try:
Sunitha Harishc99faba2019-07-19 06:55:22 -05004520 if(isRedfishSupport):
4521 url = "https://" + host + "/redfish/v1/AccountService/Accounts/"+ \
4522 args.user
4523 data = {"Password":args.password}
4524 res = session.patch(url, headers=jsonHeader, json=data,
4525 verify=False, timeout=baseTimeout)
4526 else:
4527 url = "https://" + host + "/xyz/openbmc_project/user/" + args.user + \
4528 "/action/SetPassword"
4529 res = session.post(url, headers=jsonHeader,
Marri Devender Rao2c2a5162018-11-05 08:57:11 -06004530 json={"data": [args.password]}, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06004531 timeout=baseTimeout)
Marri Devender Rao2c2a5162018-11-05 08:57:11 -06004532 except(requests.exceptions.Timeout):
4533 return(connectionErrHandler(args.json, "Timeout", None))
4534 except(requests.exceptions.ConnectionError) as err:
4535 return connectionErrHandler(args.json, "ConnectionError", err)
4536 except(requests.exceptions.RequestException) as err:
4537 return connectionErrHandler(args.json, "RequestException", err)
Sunitha Harishc99faba2019-07-19 06:55:22 -05004538 return res.status_code
Matthew Barth368e83c2019-02-01 13:48:25 -06004539
4540def getThermalZones(host, args, session):
4541 """
4542 Get the available thermal control zones
4543 @param host: string, the hostname or IP address of the bmc
4544 @param args: contains additional arguments used to get the thermal
4545 control zones
4546 @param session: the active session to use
4547 @return: Session object
4548 """
4549 url = "https://" + host + "/xyz/openbmc_project/control/thermal/enumerate"
4550
4551 try:
4552 res = session.get(url, headers=jsonHeader, verify=False, timeout=30)
4553 except(requests.exceptions.Timeout):
4554 return(connectionErrHandler(args.json, "Timeout", None))
4555 except(requests.exceptions.ConnectionError) as err:
4556 return connectionErrHandler(args.json, "ConnectionError", err)
4557 except(requests.exceptions.RequestException) as err:
4558 return connectionErrHandler(args.json, "RequestException", err)
4559
4560 if (res.status_code == 404):
Matthew Barth0939e822019-09-27 15:47:50 -05004561 return "No thermal control zones found"
Matthew Barth368e83c2019-02-01 13:48:25 -06004562
4563 zonesDict = json.loads(res.text)
4564 if not zonesDict['data']:
4565 return "No thermal control zones found"
4566 for zone in zonesDict['data']:
4567 z = ",".join(str(zone.split('/')[-1]) for zone in zonesDict['data'])
4568
4569 return "Zones: [ " + z + " ]"
4570
4571
4572def getThermalMode(host, args, session):
4573 """
4574 Get thermal control mode
4575 @param host: string, the hostname or IP address of the bmc
4576 @param args: contains additional arguments used to get the thermal
4577 control mode
4578 @param session: the active session to use
4579 @param args.zone: the zone to get the mode on
4580 @return: Session object
4581 """
4582 url = "https://" + host + "/xyz/openbmc_project/control/thermal/" + \
4583 args.zone
4584
4585 try:
4586 res = session.get(url, headers=jsonHeader, verify=False, timeout=30)
4587 except(requests.exceptions.Timeout):
4588 return(connectionErrHandler(args.json, "Timeout", None))
4589 except(requests.exceptions.ConnectionError) as err:
4590 return connectionErrHandler(args.json, "ConnectionError", err)
4591 except(requests.exceptions.RequestException) as err:
4592 return connectionErrHandler(args.json, "RequestException", err)
4593
4594 if (res.status_code == 404):
Matthew Barth0939e822019-09-27 15:47:50 -05004595 return "Thermal control zone(" + args.zone + ") not found"
Matthew Barth368e83c2019-02-01 13:48:25 -06004596
4597 propsDict = json.loads(res.text)
4598 if not propsDict['data']:
4599 return "No thermal control properties found on zone(" + args.zone + ")"
4600 curMode = "Current"
4601 supModes = "Supported"
4602 result = "\n"
4603 for prop in propsDict['data']:
4604 if (prop.casefold() == curMode.casefold()):
4605 result += curMode + " Mode: " + propsDict['data'][curMode] + "\n"
4606 if (prop.casefold() == supModes.casefold()):
4607 s = ", ".join(str(sup) for sup in propsDict['data'][supModes])
4608 result += supModes + " Modes: [ " + s + " ]\n"
4609
4610 return result
4611
4612def setThermalMode(host, args, session):
4613 """
4614 Set thermal control mode
4615 @param host: string, the hostname or IP address of the bmc
4616 @param args: contains additional arguments used for setting the thermal
4617 control mode
4618 @param session: the active session to use
4619 @param args.zone: the zone to set the mode on
4620 @param args.mode: the mode to enable
4621 @return: Session object
4622 """
4623 url = "https://" + host + "/xyz/openbmc_project/control/thermal/" + \
4624 args.zone + "/attr/Current"
4625
4626 # Check args.mode against supported modes using `getThermalMode` output
4627 modes = getThermalMode(host, args, session)
4628 modes = os.linesep.join([m for m in modes.splitlines() if m])
4629 modes = modes.replace("\n", ";").strip()
4630 modesDict = dict(m.split(': ') for m in modes.split(';'))
4631 sModes = ''.join(s for s in modesDict['Supported Modes'] if s not in '[ ]')
4632 if args.mode.casefold() not in \
4633 (m.casefold() for m in sModes.split(',')) or not args.mode:
4634 result = ("Unsupported mode('" + args.mode + "') given, " +
4635 "select a supported mode: \n" +
4636 getThermalMode(host, args, session))
4637 return result
4638
4639 data = '{"data":"' + args.mode + '"}'
4640 try:
4641 res = session.get(url, headers=jsonHeader, verify=False, timeout=30)
4642 except(requests.exceptions.Timeout):
4643 return(connectionErrHandler(args.json, "Timeout", None))
4644 except(requests.exceptions.ConnectionError) as err:
4645 return connectionErrHandler(args.json, "ConnectionError", err)
4646 except(requests.exceptions.RequestException) as err:
4647 return connectionErrHandler(args.json, "RequestException", err)
4648
4649 if (data and res.status_code != 404):
4650 try:
4651 res = session.put(url, headers=jsonHeader,
4652 data=data, verify=False,
4653 timeout=30)
4654 except(requests.exceptions.Timeout):
4655 return(connectionErrHandler(args.json, "Timeout", None))
4656 except(requests.exceptions.ConnectionError) as err:
4657 return connectionErrHandler(args.json, "ConnectionError", err)
4658 except(requests.exceptions.RequestException) as err:
4659 return connectionErrHandler(args.json, "RequestException", err)
4660
4661 if res.status_code == 403:
4662 return "The specified thermal control zone(" + args.zone + ")" + \
4663 " does not exist"
4664
4665 return res.text
4666 else:
4667 return "Setting thermal control mode(" + args.mode + ")" + \
Matthew Barth0939e822019-09-27 15:47:50 -05004668 " not supported or operation not available"
Matthew Barth368e83c2019-02-01 13:48:25 -06004669
4670
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004671def createCommandParser():
Justin Thalere412dc22018-01-12 16:28:24 -06004672 """
4673 creates the parser for the command line along with help for each command and subcommand
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004674
Justin Thalere412dc22018-01-12 16:28:24 -06004675 @return: returns the parser for the command line
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004676 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004677 parser = argparse.ArgumentParser(description='Process arguments')
Justin Thalere412dc22018-01-12 16:28:24 -06004678 parser.add_argument("-H", "--host", help='A hostname or IP for the BMC')
4679 parser.add_argument("-U", "--user", help='The username to login with')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004680 group = parser.add_mutually_exclusive_group()
4681 group.add_argument("-A", "--askpw", action='store_true', help='prompt for password')
4682 group.add_argument("-P", "--PW", help='Provide the password in-line')
Joseph Reynoldsa2d54c52019-06-11 22:02:57 -05004683 group.add_argument("-E", "--PWenvvar", action='store_true', help='Get password from envvar OPENBMCTOOL_PASSWORD')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004684 parser.add_argument('-j', '--json', action='store_true', help='output json data only')
4685 parser.add_argument('-t', '--policyTableLoc', help='The location of the policy table to parse alerts')
4686 parser.add_argument('-c', '--CerFormat', action='store_true', help=argparse.SUPPRESS)
4687 parser.add_argument('-T', '--procTime', action='store_true', help= argparse.SUPPRESS)
Justin Thalere412dc22018-01-12 16:28:24 -06004688 parser.add_argument('-V', '--version', action='store_true', help='Display the version number of the openbmctool')
4689 subparsers = parser.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004690
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004691 #fru command
4692 parser_inv = subparsers.add_parser("fru", help='Work with platform inventory')
Justin Thalere412dc22018-01-12 16:28:24 -06004693 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 -05004694 inv_subparser.required = True
4695 #fru print
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004696 inv_print = inv_subparser.add_parser("print", help="prints out a list of all FRUs")
4697 inv_print.set_defaults(func=fruPrint)
4698 #fru list [0....n]
4699 inv_list = inv_subparser.add_parser("list", help="print out details on selected FRUs. Specifying no items will list the entire inventory")
4700 inv_list.add_argument('items', nargs='?', help="print out details on selected FRUs. Specifying no items will list the entire inventory")
4701 inv_list.set_defaults(func=fruList)
4702 #fru status
4703 inv_status = inv_subparser.add_parser("status", help="prints out the status of all FRUs")
Justin Thalere412dc22018-01-12 16:28:24 -06004704 inv_status.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004705 inv_status.set_defaults(func=fruStatus)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004706
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004707 #sensors command
4708 parser_sens = subparsers.add_parser("sensors", help="Work with platform sensors")
Justin Thalere412dc22018-01-12 16:28:24 -06004709 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 -05004710 sens_subparser.required = True
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004711 #sensor print
4712 sens_print= sens_subparser.add_parser('print', help="prints out a list of all Sensors.")
4713 sens_print.set_defaults(func=sensor)
4714 #sensor list[0...n]
4715 sens_list=sens_subparser.add_parser("list", help="Lists all Sensors in the platform. Specify a sensor for full details. ")
4716 sens_list.add_argument("sensNum", nargs='?', help="The Sensor number to get full details on" )
4717 sens_list.set_defaults(func=sensor)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004718
Matthew Barth368e83c2019-02-01 13:48:25 -06004719 #thermal control commands
4720 parser_therm = subparsers.add_parser("thermal", help="Work with thermal control parameters")
4721 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')
4722 #thermal control zones
4723 parser_thermZones = therm_subparser.add_parser("zones", help="Get a list of available thermal control zones")
4724 parser_thermZones.set_defaults(func=getThermalZones)
4725 #thermal control modes
4726 parser_thermMode = therm_subparser.add_parser("modes", help="Work with thermal control modes")
4727 thermMode_sub = parser_thermMode.add_subparsers(title='subactions', description='Work with thermal control modes', help="Work with thermal control modes")
4728 #get thermal control mode
4729 parser_getThermMode = thermMode_sub.add_parser("get", help="Get current and supported thermal control modes")
4730 parser_getThermMode.add_argument('-z', '--zone', required=True, help='Thermal zone to work with')
4731 parser_getThermMode.set_defaults(func=getThermalMode)
4732 #set thermal control mode
4733 parser_setThermMode = thermMode_sub.add_parser("set", help="Set the thermal control mode")
4734 parser_setThermMode.add_argument('-z', '--zone', required=True, help='Thermal zone to work with')
4735 parser_setThermMode.add_argument('-m', '--mode', required=True, help='The supported thermal control mode')
4736 parser_setThermMode.set_defaults(func=setThermalMode)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004737
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004738 #sel command
4739 parser_sel = subparsers.add_parser("sel", help="Work with platform alerts")
Justin Thalere412dc22018-01-12 16:28:24 -06004740 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 -05004741 sel_subparser.required = True
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004742 #sel print
4743 sel_print = sel_subparser.add_parser("print", help="prints out a list of all sels in a condensed list")
4744 sel_print.add_argument('-d', '--devdebug', action='store_true', help=argparse.SUPPRESS)
4745 sel_print.add_argument('-v', '--verbose', action='store_true', help="Changes the output to being very verbose")
4746 sel_print.add_argument('-f', '--fileloc', help='Parse a file instead of the BMC output')
4747 sel_print.set_defaults(func=selPrint)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004748
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004749 #sel list
4750 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")
4751 sel_list.add_argument("selNum", nargs='?', type=int, help="The SEL entry to get details on")
4752 sel_list.set_defaults(func=selList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004753
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004754 sel_get = sel_subparser.add_parser("get", help="Gets the verbose details of a specified SEL entry")
4755 sel_get.add_argument('selNum', type=int, help="the number of the SEL entry to get")
4756 sel_get.set_defaults(func=selList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004757
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004758 sel_clear = sel_subparser.add_parser("clear", help="Clears all entries from the SEL")
4759 sel_clear.set_defaults(func=selClear)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004760
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004761 sel_setResolved = sel_subparser.add_parser("resolve", help="Sets the sel entry to resolved")
Justin Thalere412dc22018-01-12 16:28:24 -06004762 sel_setResolved.add_argument('-n', '--selNum', type=int, help="the number of the SEL entry to resolve")
4763 sel_ResolveAll_sub = sel_setResolved.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
4764 sel_ResolveAll = sel_ResolveAll_sub.add_parser('all', help='Resolve all SEL entries')
4765 sel_ResolveAll.set_defaults(func=selResolveAll)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004766 sel_setResolved.set_defaults(func=selSetResolved)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004767
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004768 parser_chassis = subparsers.add_parser("chassis", help="Work with chassis power and status")
Justin Thalere412dc22018-01-12 16:28:24 -06004769 chas_sub = parser_chassis.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004770
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004771 parser_chassis.add_argument('status', action='store_true', help='Returns the current status of the platform')
4772 parser_chassis.set_defaults(func=chassis)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004773
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004774 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 -06004775 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 -06004776 parser_chasPower.set_defaults(func=chassisPower)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004777
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004778 #control the chassis identify led
4779 parser_chasIdent = chas_sub.add_parser("identify", help="Control the chassis identify led")
4780 parser_chasIdent.add_argument('identcmd', choices=['on', 'off', 'status'], help='The control option for the led: on, off, blink, status')
4781 parser_chasIdent.set_defaults(func=chassisIdent)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004782
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004783 #collect service data
4784 parser_servData = subparsers.add_parser("collect_service_data", help="Collect all bmc data needed for service")
4785 parser_servData.add_argument('-d', '--devdebug', action='store_true', help=argparse.SUPPRESS)
4786 parser_servData.set_defaults(func=collectServiceData)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004787
Justin Thalere412dc22018-01-12 16:28:24 -06004788 #system quick health check
4789 parser_healthChk = subparsers.add_parser("health_check", help="Work with platform sensors")
4790 parser_healthChk.set_defaults(func=healthCheck)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004791
Ravi Tejad8be0b42020-03-18 14:31:46 -05004792 #work with dumps
4793 parser_bmcdump = subparsers.add_parser("dump", help="Work with dumps")
4794 parser_bmcdump.add_argument("-t", "--dumpType", default='bmc', choices=['bmc','SystemDump'],help="Type of dump")
Justin Thalere412dc22018-01-12 16:28:24 -06004795 bmcDump_sub = parser_bmcdump.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Justin Thaler53bf2f12018-07-16 14:05:32 -05004796 bmcDump_sub.required = True
Ravi Tejad8be0b42020-03-18 14:31:46 -05004797 dump_Create = bmcDump_sub.add_parser('create', help="Create a dump of given type")
4798 dump_Create.set_defaults(func=dumpCreate)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004799
Ravi Tejad8be0b42020-03-18 14:31:46 -05004800 dump_list = bmcDump_sub.add_parser('list', help="list all dumps")
4801 dump_list.set_defaults(func=dumpList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004802
Ravi Tejad8be0b42020-03-18 14:31:46 -05004803 parserdumpdelete = bmcDump_sub.add_parser('delete', help="Delete dump")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004804 parserdumpdelete.add_argument("-n", "--dumpNum", nargs='*', type=int, help="The Dump entry to delete")
Ravi Tejad8be0b42020-03-18 14:31:46 -05004805 parserdumpdelete.set_defaults(func=dumpDelete)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004806
Justin Thalere412dc22018-01-12 16:28:24 -06004807 bmcDumpDelsub = parserdumpdelete.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Ravi Tejad8be0b42020-03-18 14:31:46 -05004808 deleteAllDumps = bmcDumpDelsub.add_parser('all', help='Delete all dumps')
4809 deleteAllDumps.set_defaults(func=dumpDeleteAll)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004810
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004811 parser_dumpretrieve = bmcDump_sub.add_parser('retrieve', help='Retrieve a dump file')
Ravi Tejad8be0b42020-03-18 14:31:46 -05004812 parser_dumpretrieve.add_argument("-n,", "--dumpNum", help="The Dump entry to retrieve")
4813 parser_dumpretrieve.add_argument("-s", "--dumpSaveLoc", help="The location to save the bmc dump file or file path for system dump")
4814 parser_dumpretrieve.set_defaults(func=dumpRetrieve)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004815
Justin Thaler22b1bb52018-03-15 13:31:32 -05004816 #bmc command for reseting the bmc
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004817 parser_bmc = subparsers.add_parser('bmc', help="Work with the bmc")
Justin Thalere412dc22018-01-12 16:28:24 -06004818 bmc_sub = parser_bmc.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004819 parser_BMCReset = bmc_sub.add_parser('reset', help='Reset the bmc' )
4820 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 -06004821 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.")
4822 parser_bmc.set_defaults(func=bmc)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004823
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004824 #add alias to the bmc command
4825 parser_mc = subparsers.add_parser('mc', help="Work with the management controller")
Justin Thalere412dc22018-01-12 16:28:24 -06004826 mc_sub = parser_mc.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004827 parser_MCReset = mc_sub.add_parser('reset', help='Reset the bmc' )
4828 parser_MCReset.add_argument('type', choices=['warm','cold'], help="Reboot the BMC")
4829 #parser_MCReset.add_argument('cold', action='store_true', help="Reboot the BMC and CLEAR the configuration")
4830 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 -06004831 parser_MCReset.set_defaults(func=bmcReset)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004832 parser_mc.set_defaults(func=bmc)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004833
Justin Thalere412dc22018-01-12 16:28:24 -06004834 #gard clear
4835 parser_gc = subparsers.add_parser("gardclear", help="Used to clear gard records")
4836 parser_gc.set_defaults(func=gardClear)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004837
Justin Thalere412dc22018-01-12 16:28:24 -06004838 #firmware_flash
4839 parser_fw = subparsers.add_parser("firmware", help="Work with the system firmware")
4840 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 -05004841 fwflash_subproc.required = True
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004842
Justin Thalere412dc22018-01-12 16:28:24 -06004843 fwflash = fwflash_subproc.add_parser('flash', help="Flash the system firmware")
4844 fwflash.add_argument('type', choices=['bmc', 'pnor'], help="image type to flash")
4845 fwflash.add_argument('-f', '--fileloc', required=True, help="The absolute path to the firmware image")
4846 fwflash.set_defaults(func=fwFlash)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004847
Justin Thaler22b1bb52018-03-15 13:31:32 -05004848 fwActivate = fwflash_subproc.add_parser('activate', help="Activate existing image on the bmc")
Justin Thalere412dc22018-01-12 16:28:24 -06004849 fwActivate.add_argument('imageID', help="The image ID to activate from the firmware list. Ex: 63c95399")
4850 fwActivate.set_defaults(func=activateFWImage)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004851
Justin Thaler22b1bb52018-03-15 13:31:32 -05004852 fwActivateStatus = fwflash_subproc.add_parser('activation_status', help="Check Status of activations")
4853 fwActivateStatus.set_defaults(func=activateStatus)
4854
Justin Thaler3d71d402018-07-24 14:35:39 -05004855 fwList = fwflash_subproc.add_parser('list', help="List all of the installed firmware")
4856 fwList.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
4857 fwList.set_defaults(func=firmwareList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004858
Justin Thaler3d71d402018-07-24 14:35:39 -05004859 fwprint = fwflash_subproc.add_parser('print', help="List all of the installed firmware")
4860 fwprint.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
4861 fwprint.set_defaults(func=firmwareList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004862
Adriana Kobylak5af2fad2018-11-08 12:33:43 -06004863 fwDelete = fwflash_subproc.add_parser('delete', help="Delete an existing firmware version")
4864 fwDelete.add_argument('versionID', help="The version ID to delete from the firmware list. Ex: 63c95399")
4865 fwDelete.set_defaults(func=deleteFWVersion)
4866
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05004867 #logging
4868 parser_logging = subparsers.add_parser("logging", help="logging controls")
4869 logging_sub = parser_logging.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004870
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05004871 #turn rest api logging on/off
4872 parser_rest_logging = logging_sub.add_parser("rest_api", help="turn rest api logging on/off")
4873 parser_rest_logging.add_argument('rest_logging', choices=['on', 'off'], help='The control option for rest logging: on, off')
4874 parser_rest_logging.set_defaults(func=restLogging)
Deepak Kodihalli02d53282018-09-18 06:53:31 -05004875
4876 #remote logging
4877 parser_remote_logging = logging_sub.add_parser("remote_logging", help="Remote logging (rsyslog) commands")
4878 parser_remote_logging.add_argument('remote_logging', choices=['view', 'disable'], help='Remote logging (rsyslog) commands')
4879 parser_remote_logging.set_defaults(func=remoteLogging)
4880
4881 #configure remote logging
4882 parser_remote_logging_config = logging_sub.add_parser("remote_logging_config", help="Configure remote logging (rsyslog)")
4883 parser_remote_logging_config.add_argument("-a", "--address", required=True, help="Set IP address of rsyslog server")
4884 parser_remote_logging_config.add_argument("-p", "--port", required=True, type=int, help="Set Port of rsyslog server")
4885 parser_remote_logging_config.set_defaults(func=remoteLoggingConfig)
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05004886
4887 #certificate management
4888 parser_cert = subparsers.add_parser("certificate", help="Certificate management")
4889 certMgmt_subproc = parser_cert.add_subparsers(title='subcommands', description='valid certificate commands', help='sub-command help', dest='command')
4890
4891 certUpdate = certMgmt_subproc.add_parser('update', help="Update the certificate")
4892 certUpdate.add_argument('type', choices=['server', 'client', 'authority'], help="certificate type to update")
4893 certUpdate.add_argument('service', choices=['https', 'ldap'], help="Service to update")
4894 certUpdate.add_argument('-f', '--fileloc', required=True, help="The absolute path to the certificate file")
4895 certUpdate.set_defaults(func=certificateUpdate)
4896
4897 certDelete = certMgmt_subproc.add_parser('delete', help="Delete the certificate")
4898 certDelete.add_argument('type', choices=['server', 'client', 'authority'], help="certificate type to delete")
4899 certDelete.add_argument('service', choices=['https', 'ldap'], help="Service to delete the certificate")
4900 certDelete.set_defaults(func=certificateDelete)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004901
Marri Devender Raodfe81ad2019-07-01 05:38:09 -05004902 certReplace = certMgmt_subproc.add_parser('replace',
4903 help="Replace the certificate")
4904 certReplace.add_argument('type', choices=['server', 'client', 'authority'],
4905 help="certificate type to replace")
4906 certReplace.add_argument('service', choices=['https', 'ldap'],
4907 help="Service to replace the certificate")
4908 certReplace.add_argument('-f', '--fileloc', required=True,
4909 help="The absolute path to the certificate file")
4910 certReplace.set_defaults(func=certificateReplace)
4911
Marri Devender Rao34646402019-07-01 05:46:03 -05004912 certDisplay = certMgmt_subproc.add_parser('display',
4913 help="Print the certificate")
4914 certDisplay.add_argument('type', choices=['server', 'client', 'authority'],
4915 help="certificate type to display")
4916 certDisplay.set_defaults(func=certificateDisplay)
4917
Marri Devender Raoa208ff82019-07-01 05:51:27 -05004918 certList = certMgmt_subproc.add_parser('list',
4919 help="Certificate list")
4920 certList.set_defaults(func=certificateList)
4921
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05004922 certGenerateCSR = certMgmt_subproc.add_parser('generatecsr', help="Generate CSR")
4923 certGenerateCSR.add_argument('type', choices=['server', 'client', 'authority'],
4924 help="Generate CSR")
4925 certGenerateCSR.add_argument('city',
4926 help="The city or locality of the organization making the request")
4927 certGenerateCSR.add_argument('commonName',
4928 help="The fully qualified domain name of the component that is being secured.")
4929 certGenerateCSR.add_argument('country',
4930 help="The country of the organization making the request")
4931 certGenerateCSR.add_argument('organization',
4932 help="The name of the organization making the request.")
4933 certGenerateCSR.add_argument('organizationUnit',
4934 help="The name of the unit or division of the organization making the request.")
4935 certGenerateCSR.add_argument('state',
4936 help="The state, province, or region of the organization making the request.")
4937 certGenerateCSR.add_argument('keyPairAlgorithm', choices=['RSA', 'EC'],
4938 help="The type of key pair for use with signing algorithms.")
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05004939 certGenerateCSR.add_argument('keyCurveId',
4940 help="The curve ID to be used with the key, if needed based on the value of the 'KeyPairAlgorithm' parameter.")
4941 certGenerateCSR.add_argument('contactPerson',
4942 help="The name of the user making the request")
4943 certGenerateCSR.add_argument('email',
4944 help="The email address of the contact within the organization")
4945 certGenerateCSR.add_argument('alternativeNames',
4946 help="Additional hostnames of the component that is being secured")
4947 certGenerateCSR.add_argument('givenname',
4948 help="The given name of the user making the request")
4949 certGenerateCSR.add_argument('surname',
4950 help="The surname of the user making the request")
4951 certGenerateCSR.add_argument('unstructuredname',
4952 help="he unstructured name of the subject")
4953 certGenerateCSR.add_argument('initials',
4954 help="The initials of the user making the request")
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05004955 certGenerateCSR.set_defaults(func=certificateGenerateCSR)
4956
Matt Spinler7d426c22018-09-24 14:42:07 -05004957 # local users
4958 parser_users = subparsers.add_parser("local_users", help="Work with local users")
4959 parser_users.add_argument('local_users', choices=['disableall','enableall', 'queryenabled'], help="Disable, enable or query local user accounts")
4960 parser_users.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
4961 parser_users.set_defaults(func=localUsers)
4962
Ratan Gupta9166cd22018-10-01 18:09:40 +05304963 #LDAP
4964 parser_ldap = subparsers.add_parser("ldap", help="LDAP controls")
4965 ldap_sub = parser_ldap.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
4966
4967 #configure and enable LDAP
4968 parser_ldap_config = ldap_sub.add_parser("enable", help="Configure and enables the LDAP")
4969 parser_ldap_config.add_argument("-a", "--uri", required=True, help="Set LDAP server URI")
4970 parser_ldap_config.add_argument("-B", "--bindDN", required=True, help="Set the bind DN of the LDAP server")
4971 parser_ldap_config.add_argument("-b", "--baseDN", required=True, help="Set the base DN of the LDAP server")
4972 parser_ldap_config.add_argument("-p", "--bindPassword", required=True, help="Set the bind password of the LDAP server")
4973 parser_ldap_config.add_argument("-S", "--scope", choices=['sub','one', 'base'],
4974 help='Specifies the search scope:subtree, one level or base object.')
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004975 parser_ldap_config.add_argument("-t", "--serverType", required=True, choices=['ActiveDirectory','OpenLDAP'],
Ratan Gupta9166cd22018-10-01 18:09:40 +05304976 help='Specifies the configured server is ActiveDirectory(AD) or OpenLdap')
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004977 parser_ldap_config.add_argument("-g","--groupAttrName", required=False, default='', help="Group Attribute Name")
4978 parser_ldap_config.add_argument("-u","--userAttrName", required=False, default='', help="User Attribute Name")
4979 parser_ldap_config.set_defaults(func=enableLDAPConfig)
Ratan Gupta9166cd22018-10-01 18:09:40 +05304980
4981 # disable LDAP
4982 parser_disable_ldap = ldap_sub.add_parser("disable", help="disables the LDAP")
4983 parser_disable_ldap.set_defaults(func=disableLDAP)
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06004984 # view-config
4985 parser_ldap_config = \
4986 ldap_sub.add_parser("view-config", help="prints out a list of all \
4987 LDAPS's configured properties")
4988 parser_ldap_config.set_defaults(func=viewLDAPConfig)
Ratan Gupta9166cd22018-10-01 18:09:40 +05304989
Ratan Guptafeee6372018-10-17 23:25:51 +05304990 #create group privilege mapping
4991 parser_ldap_mapper = ldap_sub.add_parser("privilege-mapper", help="LDAP group privilege controls")
4992 parser_ldap_mapper_sub = parser_ldap_mapper.add_subparsers(title='subcommands', description='valid subcommands',
4993 help="sub-command help", dest='command')
4994
4995 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 -05004996 parser_ldap_mapper_create.add_argument("-t", "--serverType", choices=['ActiveDirectory','OpenLDAP'],
4997 help='Specifies the configured server is ActiveDirectory(AD) or OpenLdap')
Ratan Guptafeee6372018-10-17 23:25:51 +05304998 parser_ldap_mapper_create.add_argument("-g","--groupName",required=True,help="Group Name")
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004999 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 +05305000 parser_ldap_mapper_create.set_defaults(func=createPrivilegeMapping)
5001
5002 #list group privilege mapping
5003 parser_ldap_mapper_list = parser_ldap_mapper_sub.add_parser("list",help="List privilege mapping")
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05005004 parser_ldap_mapper_list.add_argument("-t", "--serverType", choices=['ActiveDirectory','OpenLDAP'],
5005 help='Specifies the configured server is ActiveDirectory(AD) or OpenLdap')
Ratan Guptafeee6372018-10-17 23:25:51 +05305006 parser_ldap_mapper_list.set_defaults(func=listPrivilegeMapping)
5007
5008 #delete group privilege mapping
5009 parser_ldap_mapper_delete = parser_ldap_mapper_sub.add_parser("delete",help="Delete privilege mapping")
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05005010 parser_ldap_mapper_delete.add_argument("-t", "--serverType", choices=['ActiveDirectory','OpenLDAP'],
5011 help='Specifies the configured server is ActiveDirectory(AD) or OpenLdap')
Ratan Guptafeee6372018-10-17 23:25:51 +05305012 parser_ldap_mapper_delete.add_argument("-g","--groupName",required=True,help="Group Name")
5013 parser_ldap_mapper_delete.set_defaults(func=deletePrivilegeMapping)
5014
Sivas SRR78835272018-11-27 05:27:19 -06005015 #deleteAll group privilege mapping
5016 parser_ldap_mapper_delete = parser_ldap_mapper_sub.add_parser("purge",help="Delete All privilege mapping")
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05005017 parser_ldap_mapper_delete.add_argument("-t", "--serverType", choices=['ActiveDirectory','OpenLDAP'],
5018 help='Specifies the configured server is ActiveDirectory(AD) or OpenLdap')
Sivas SRR78835272018-11-27 05:27:19 -06005019 parser_ldap_mapper_delete.set_defaults(func=deleteAllPrivilegeMapping)
5020
Marri Devender Rao2c2a5162018-11-05 08:57:11 -06005021 # set local user password
5022 parser_set_password = subparsers.add_parser("set_password",
5023 help="Set password of local user")
5024 parser_set_password.add_argument( "-p", "--password", required=True,
5025 help="Password of local user")
5026 parser_set_password.set_defaults(func=setPassword)
5027
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06005028 # network
5029 parser_nw = subparsers.add_parser("network", help="network controls")
5030 nw_sub = parser_nw.add_subparsers(title='subcommands',
5031 description='valid subcommands',
5032 help="sub-command help",
5033 dest='command')
5034
5035 # enable DHCP
5036 parser_enable_dhcp = nw_sub.add_parser("enableDHCP",
5037 help="enables the DHCP on given "
5038 "Interface")
5039 parser_enable_dhcp.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06005040 help="Name of the ethernet interface(it can"
5041 "be obtained by the "
5042 "command:network view-config)"
5043 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06005044 parser_enable_dhcp.set_defaults(func=enableDHCP)
5045
5046 # disable DHCP
5047 parser_disable_dhcp = nw_sub.add_parser("disableDHCP",
5048 help="disables the DHCP on given "
5049 "Interface")
5050 parser_disable_dhcp.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06005051 help="Name of the ethernet interface(it can"
5052 "be obtained by the "
5053 "command:network view-config)"
5054 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06005055 parser_disable_dhcp.set_defaults(func=disableDHCP)
5056
5057 # get HostName
5058 parser_gethostname = nw_sub.add_parser("getHostName",
5059 help="prints out HostName")
5060 parser_gethostname.set_defaults(func=getHostname)
5061
5062 # set HostName
5063 parser_sethostname = nw_sub.add_parser("setHostName", help="sets HostName")
5064 parser_sethostname.add_argument("-H", "--HostName", required=True,
5065 help="A HostName for the BMC")
5066 parser_sethostname.set_defaults(func=setHostname)
5067
5068 # get domainname
5069 parser_getdomainname = nw_sub.add_parser("getDomainName",
5070 help="prints out DomainName of "
5071 "given Interface")
5072 parser_getdomainname.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06005073 help="Name of the ethernet interface(it "
5074 "can be obtained by the "
5075 "command:network view-config)"
5076 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06005077 parser_getdomainname.set_defaults(func=getDomainName)
5078
5079 # set domainname
5080 parser_setdomainname = nw_sub.add_parser("setDomainName",
5081 help="sets DomainName of given "
5082 "Interface")
5083 parser_setdomainname.add_argument("-D", "--DomainName", required=True,
5084 help="Ex: DomainName=Domain1,Domain2,...")
5085 parser_setdomainname.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06005086 help="Name of the ethernet interface(it "
5087 "can be obtained by the "
5088 "command:network view-config)"
5089 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06005090 parser_setdomainname.set_defaults(func=setDomainName)
5091
5092 # get MACAddress
5093 parser_getmacaddress = nw_sub.add_parser("getMACAddress",
5094 help="prints out MACAddress the "
5095 "given Interface")
5096 parser_getmacaddress.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06005097 help="Name of the ethernet interface(it "
5098 "can be obtained by the "
5099 "command:network view-config)"
5100 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06005101 parser_getmacaddress.set_defaults(func=getMACAddress)
5102
5103 # set MACAddress
5104 parser_setmacaddress = nw_sub.add_parser("setMACAddress",
5105 help="sets MACAddress")
5106 parser_setmacaddress.add_argument("-MA", "--MACAddress", required=True,
5107 help="A MACAddress for the given "
5108 "Interface")
5109 parser_setmacaddress.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06005110 help="Name of the ethernet interface(it can"
5111 "be obtained by the "
5112 "command:network view-config)"
5113 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06005114 parser_setmacaddress.set_defaults(func=setMACAddress)
5115
5116 # get DefaultGW
5117 parser_getdefaultgw = nw_sub.add_parser("getDefaultGW",
5118 help="prints out DefaultGateway "
5119 "the BMC")
5120 parser_getdefaultgw.set_defaults(func=getDefaultGateway)
5121
5122 # set DefaultGW
5123 parser_setdefaultgw = nw_sub.add_parser("setDefaultGW",
5124 help="sets DefaultGW")
5125 parser_setdefaultgw.add_argument("-GW", "--DefaultGW", required=True,
5126 help="A DefaultGateway for the BMC")
5127 parser_setdefaultgw.set_defaults(func=setDefaultGateway)
5128
5129 # view network Config
5130 parser_ldap_config = nw_sub.add_parser("view-config", help="prints out a "
5131 "list of all network's configured "
5132 "properties")
5133 parser_ldap_config.set_defaults(func=viewNWConfig)
5134
5135 # get DNS
5136 parser_getDNS = nw_sub.add_parser("getDNS",
5137 help="prints out DNS servers on the "
5138 "given interface")
5139 parser_getDNS.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06005140 help="Name of the ethernet interface(it can"
5141 "be obtained by the "
5142 "command:network view-config)"
5143 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06005144 parser_getDNS.set_defaults(func=getDNS)
5145
5146 # set DNS
5147 parser_setDNS = nw_sub.add_parser("setDNS",
5148 help="sets DNS servers on the given "
5149 "interface")
5150 parser_setDNS.add_argument("-d", "--DNSServers", required=True,
5151 help="Ex: DNSSERVERS=DNS1,DNS2,...")
5152 parser_setDNS.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06005153 help="Name of the ethernet interface(it can"
5154 "be obtained by the "
5155 "command:network view-config)"
5156 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06005157 parser_setDNS.set_defaults(func=setDNS)
5158
5159 # get NTP
5160 parser_getNTP = nw_sub.add_parser("getNTP",
5161 help="prints out NTP servers on the "
5162 "given interface")
5163 parser_getNTP.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06005164 help="Name of the ethernet interface(it can"
5165 "be obtained by the "
5166 "command:network view-config)"
5167 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06005168 parser_getNTP.set_defaults(func=getNTP)
5169
5170 # set NTP
5171 parser_setNTP = nw_sub.add_parser("setNTP",
5172 help="sets NTP servers on the given "
5173 "interface")
5174 parser_setNTP.add_argument("-N", "--NTPServers", required=True,
5175 help="Ex: NTPSERVERS=NTP1,NTP2,...")
5176 parser_setNTP.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06005177 help="Name of the ethernet interface(it can"
5178 "be obtained by the "
5179 "command:network view-config)"
5180 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06005181 parser_setNTP.set_defaults(func=setNTP)
5182
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06005183 # configure IP
5184 parser_ip_config = nw_sub.add_parser("addIP", help="Sets IP address to"
5185 "given interface")
5186 parser_ip_config.add_argument("-a", "--address", required=True,
5187 help="IP address of given interface")
5188 parser_ip_config.add_argument("-gw", "--gateway", required=False, default='',
5189 help="The gateway for given interface")
5190 parser_ip_config.add_argument("-l", "--prefixLength", required=True,
5191 help="The prefixLength of IP address")
Sunitha Harish0baf6372019-07-31 03:59:03 -05005192 parser_ip_config.add_argument("-p", "--type", required=True,
5193 choices=['ipv4', 'ipv6'],
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06005194 help="The protocol type of the given"
5195 "IP address")
5196 parser_ip_config.add_argument("-I", "--Interface", required=True,
5197 help="Name of the ethernet interface(it can"
5198 "be obtained by the "
5199 "command:network view-config)"
5200 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
5201 parser_ip_config.set_defaults(func=addIP)
5202
5203 # getIP
5204 parser_getIP = nw_sub.add_parser("getIP", help="prints out IP address"
5205 "of given interface")
5206 parser_getIP.add_argument("-I", "--Interface", required=True,
5207 help="Name of the ethernet interface(it can"
5208 "be obtained by the command:network view-config)"
5209 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
5210 parser_getIP.set_defaults(func=getIP)
5211
5212 # rmIP
5213 parser_rmIP = nw_sub.add_parser("rmIP", help="deletes IP address"
5214 "of given interface")
5215 parser_rmIP.add_argument("-a", "--address", required=True,
5216 help="IP address to remove form given Interface")
5217 parser_rmIP.add_argument("-I", "--Interface", required=True,
5218 help="Name of the ethernet interface(it can"
5219 "be obtained by the command:network view-config)"
5220 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
5221 parser_rmIP.set_defaults(func=deleteIP)
5222
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06005223 # add VLAN
5224 parser_create_vlan = nw_sub.add_parser("addVLAN", help="enables VLAN "
5225 "on given interface with given "
5226 "VLAN Identifier")
5227 parser_create_vlan.add_argument("-I", "--Interface", required=True,
5228 choices=['eth0', 'eth1'],
5229 help="Name of the ethernet interface")
5230 parser_create_vlan.add_argument("-n", "--Identifier", required=True,
5231 help="VLAN Identifier")
5232 parser_create_vlan.set_defaults(func=addVLAN)
5233
5234 # delete VLAN
5235 parser_delete_vlan = nw_sub.add_parser("deleteVLAN", help="disables VLAN "
5236 "on given interface with given "
5237 "VLAN Identifier")
5238 parser_delete_vlan.add_argument("-I", "--Interface", required=True,
5239 help="Name of the ethernet interface(it can"
5240 "be obtained by the "
5241 "command:network view-config)"
5242 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
5243 parser_delete_vlan.set_defaults(func=deleteVLAN)
5244
5245 # viewDHCPConfig
5246 parser_viewDHCPConfig = nw_sub.add_parser("viewDHCPConfig",
5247 help="Shows DHCP configured "
5248 "Properties")
5249 parser_viewDHCPConfig.set_defaults(func=viewDHCPConfig)
5250
5251 # configureDHCP
5252 parser_configDHCP = nw_sub.add_parser("configureDHCP",
5253 help="Configures/updates DHCP "
5254 "Properties")
5255 parser_configDHCP.add_argument("-d", "--DNSEnabled", type=str2bool,
5256 required=True, help="Sets DNSEnabled property")
5257 parser_configDHCP.add_argument("-n", "--HostNameEnabled", type=str2bool,
5258 required=True,
5259 help="Sets HostNameEnabled property")
5260 parser_configDHCP.add_argument("-t", "--NTPEnabled", type=str2bool,
5261 required=True,
5262 help="Sets NTPEnabled property")
5263 parser_configDHCP.add_argument("-s", "--SendHostNameEnabled", type=str2bool,
5264 required=True,
5265 help="Sets SendHostNameEnabled property")
5266 parser_configDHCP.set_defaults(func=configureDHCP)
5267
5268 # network factory reset
5269 parser_nw_reset = nw_sub.add_parser("nwReset",
5270 help="Resets networks setting to "
5271 "factory defaults. "
5272 "note:Reset settings will be applied "
5273 "after BMC reboot")
5274 parser_nw_reset.set_defaults(func=nwReset)
5275
Justin Thalerf9aee3e2017-12-05 12:11:09 -06005276 return parser
5277
Justin Thalerf9aee3e2017-12-05 12:11:09 -06005278def main(argv=None):
Justin Thalere412dc22018-01-12 16:28:24 -06005279 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06005280 main function for running the command line utility as a sub application
5281 """
5282 global toolVersion
Joy Onyerikwu182c3a32019-10-15 08:33:59 -05005283 toolVersion = "1.18"
Sunitha Harishc99faba2019-07-19 06:55:22 -05005284 global isRedfishSupport
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05005285
Justin Thalerf9aee3e2017-12-05 12:11:09 -06005286 parser = createCommandParser()
Justin Thalerf9aee3e2017-12-05 12:11:09 -06005287 args = parser.parse_args(argv)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06005288
Justin Thalerf9aee3e2017-12-05 12:11:09 -06005289 totTimeStart = int(round(time.time()*1000))
5290
5291 if(sys.version_info < (3,0)):
5292 urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
5293 if sys.version_info >= (3,0):
5294 requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)
Justin Thalere412dc22018-01-12 16:28:24 -06005295 if (args.version):
Justin Thaler22b1bb52018-03-15 13:31:32 -05005296 print("Version: "+ toolVersion)
Justin Thalere412dc22018-01-12 16:28:24 -06005297 sys.exit(0)
5298 if (hasattr(args, 'fileloc') and args.fileloc is not None and 'print' in args.command):
Justin Thalerf9aee3e2017-12-05 12:11:09 -06005299 mysess = None
Justin Thalere412dc22018-01-12 16:28:24 -06005300 print(selPrint('N/A', args, mysess))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06005301 else:
Justin Thalere412dc22018-01-12 16:28:24 -06005302 if(hasattr(args, 'host') and hasattr(args,'user')):
5303 if (args.askpw):
5304 pw = getpass.getpass()
5305 elif(args.PW is not None):
5306 pw = args.PW
Joseph Reynoldsa2d54c52019-06-11 22:02:57 -05005307 elif(args.PWenvvar):
5308 pw = os.environ['OPENBMCTOOL_PASSWORD']
Justin Thalere412dc22018-01-12 16:28:24 -06005309 else:
5310 print("You must specify a password")
5311 sys.exit()
5312 logintimeStart = int(round(time.time()*1000))
Joy Onyerikwu182c3a32019-10-15 08:33:59 -05005313 mysess = login(args.host, args.user, pw, args.json,
5314 args.command == 'set_password')
Sunitha Harish336cda22019-07-23 02:02:52 -05005315 if(mysess == None):
5316 print("Login Failed!")
5317 sys.exit()
Justin Thalera9415b42018-05-25 19:40:13 -05005318 if(sys.version_info < (3,0)):
5319 if isinstance(mysess, basestring):
5320 print(mysess)
5321 sys.exit(1)
5322 elif sys.version_info >= (3,0):
5323 if isinstance(mysess, str):
5324 print(mysess)
5325 sys.exit(1)
Justin Thalere412dc22018-01-12 16:28:24 -06005326 logintimeStop = int(round(time.time()*1000))
Sunitha Harishc99faba2019-07-19 06:55:22 -05005327 isRedfishSupport = redfishSupportPresent(args.host,mysess)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06005328 commandTimeStart = int(round(time.time()*1000))
Justin Thalere412dc22018-01-12 16:28:24 -06005329 output = args.func(args.host, args, mysess)
5330 commandTimeStop = int(round(time.time()*1000))
Justin Thaler761484a2019-03-26 19:20:23 -05005331 if isinstance(output, dict):
5332 print(json.dumps(output, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False))
5333 else:
5334 print(output)
Justin Thalere412dc22018-01-12 16:28:24 -06005335 if (mysess is not None):
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06005336 logout(args.host, args.user, pw, mysess, args.json)
5337 if(args.procTime):
Justin Thalere412dc22018-01-12 16:28:24 -06005338 print("Total time: " + str(int(round(time.time()*1000))- totTimeStart))
5339 print("loginTime: " + str(logintimeStop - logintimeStart))
5340 print("command Time: " + str(commandTimeStop - commandTimeStart))
5341 else:
Joseph Reynoldsa2d54c52019-06-11 22:02:57 -05005342 print("usage:\n"
5343 " OPENBMCTOOL_PASSWORD=secret # if using -E\n"
5344 " openbmctool.py [-h] -H HOST -U USER {-A | -P PW | -E} [-j]\n" +
Justin Thalere412dc22018-01-12 16:28:24 -06005345 "\t[-t POLICYTABLELOC] [-V]\n" +
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05005346 "\t{fru,sensors,sel,chassis,collect_service_data, \
5347 health_check,dump,bmc,mc,gardclear,firmware,logging}\n" +
Justin Thalere412dc22018-01-12 16:28:24 -06005348 "\t...\n" +
5349 "openbmctool.py: error: the following arguments are required: -H/--host, -U/--user")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06005350 sys.exit()
Justin Thalerf9aee3e2017-12-05 12:11:09 -06005351
Justin Thalerf9aee3e2017-12-05 12:11:09 -06005352if __name__ == '__main__':
Justin Thalere412dc22018-01-12 16:28:24 -06005353 """
5354 main function when called from the command line
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06005355
5356 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06005357 import sys
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06005358
Justin Thalerf9aee3e2017-12-05 12:11:09 -06005359 isTTY = sys.stdout.isatty()
5360 assert sys.version_info >= (2,7)
5361 main()