blob: 63c4a3f631229552f452e1691e8f4639972c5cb2 [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 Thalerf9aee3e2017-12-05 12:11:09 -060039
Ravi Tejad8be0b42020-03-18 14:31:46 -050040
41MAX_NBD_PACKET_SIZE = 131088
Matt Spinler220c3c42019-01-04 15:09:29 -060042jsonHeader = {'Content-Type' : 'application/json'}
43xAuthHeader = {}
Justin Thaler27197622019-01-23 14:42:11 -060044baseTimeout = 60
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -050045serverTypeMap = {
46 'ActiveDirectory' : 'active_directory',
47 'OpenLDAP' : 'openldap'
48 }
Matt Spinler220c3c42019-01-04 15:09:29 -060049
Ravi Tejad8be0b42020-03-18 14:31:46 -050050class NBDPipe:
51
52 def openHTTPSocket(self,args):
53
54 try:
55 _create_unverified_https_context = ssl._create_unverified_context
56 except AttributeError:
57 # Legacy Python that doesn't verify HTTPS certificates by default
58 pass
59 else:
60 # Handle target environment that doesn't support HTTPS verification
61 ssl._create_default_https_context = _create_unverified_https_context
62
63
64 token = gettoken(args)
65 self.conn = http.client.HTTPSConnection(args.host,port=443)
66 URI = "/redfish/v1/Systems/system/LogServices/SystemDump/Entries/"+str(args.dumpNum)+"/Actions/Oem/OpenBmc/LogEntry.DownloadLog"
67 self.conn.request("POST",URI, headers={"X-Auth-Token":token})
68
69 def openTCPSocket(self):
70 # Create a TCP/IP socket
71 self.tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
72 # Connect the socket to the port where the server is listening
73 server_address = ('localhost', 1043)
74 self.tcp.connect(server_address)
75
76 def waitformessage(self):
77 inputs = [self.conn.sock,self.tcp]
78 outputs = []
79 message_queues = {}
80 while True:
81 readable, writable, exceptional = select.select(
82 inputs, outputs, inputs)
83
84 for s in readable:
85 if s is self.conn.sock:
86
87 data = self.conn.sock.recv(MAX_NBD_PACKET_SIZE)
88 print("<<HTTP")
89 #print(len(data))
90 if data:
91 self.tcp.send(data)
92 else:
93 print ("BMC Closed the connection")
94 self.conn.close()
95 self.tcp.close()
96 sys.exit(1)
97 elif s is self.tcp:
98 data = self.tcp.recv(MAX_NBD_PACKET_SIZE)
99 print(">>TCP")
100 #print(len(data));
101 if data:
102 self.conn.sock.send(data)
103 else:
104 print("NBD server closed the connection")
105 self.conn.sock.close()
106 self.tcp.close()
107 sys.exit(1)
108 for s in exceptional:
109 inputs.remove(s)
110 print("Exceptional closing the socket")
111 s.close()
112
113def getsize(host,args,session):
114 url = "https://"+host+"/redfish/v1/Systems/system/LogServices/SystemDump/Entries/"+str(args.dumpNum)
115 print(url)
116 try:
117 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
118 if resp.status_code==200:
119 size = resp.json()["Oem"]["OpenBmc"]['SizeInB']
120 print(size)
121 return size
122 else:
123 return "Failed get Size"
124 except(requests.exceptions.Timeout):
125 return connectionErrHandler(args.json, "Timeout", None)
126
127 except(requests.exceptions.ConnectionError) as err:
128 return connectionErrHandler(args.json, "ConnectionError", err)
129
130def gettoken(args):
131 mysess = requests.session()
132 resp = mysess.post('https://'+args.host+'/login', headers=jsonHeader,json={"data":[args.user,args.PW]},verify=False)
133 if resp.status_code == 200:
134 cookie = resp.headers['Set-Cookie']
135 match = re.search('SESSION=(\w+);', cookie)
136 return match.group(1)
137
138
139
140def get_pid(name):
141 try:
142 pid = map(int, check_output(["pidof", "-s",name]))
143 except Exception:
144 pid = 0
145
146 return pid
147
148def findThisProcess( process_name ):
149 ps = subprocess.Popen("ps -eaf | grep "+process_name, shell=True, stdout=subprocess.PIPE)
150 output = ps.stdout.read()
151 ps.stdout.close()
152 ps.wait()
153 pid = get_pid(process_name)
154 print(pid)
155 return output
156
157def isThisProcessRunning( process_name ):
158 pid = get_pid(process_name)
159 if (pid == 0 ):
160 return False
161 else:
162 return True
163
164def NBDSetup(host,args,session):
165 user=os.getenv("SUDO_USER")
166 if user is None:
167 path = os.getcwd()
168 nbdServerPath = path + "/nbd-server"
169 print(nbdServerPath,os.path.exists(nbdServerPath))
170 if not os.path.exists(nbdServerPath):
171 print("Error: this program did not run as sudo!\nplease copy nbd-server to current directory and run script again")
172 exit()
173
174 if isThisProcessRunning('nbd-server') == True:
175 print("nbd-server already Running! killing the nbd-server")
176 os.system('killall nbd-server')
177
178 if (args.dumpSaveLoc is not None):
179 if(os.path.exists(args.dumpSaveLoc)):
180 print("Error: File already exists.")
181 exit()
182
183 fp= open(args.dumpSaveLoc,"w")
184 sizeInBytes = getsize(host,args,session)
185 #Round off size to mutiples of 1024
186 size = int(sizeInBytes)
187 print(size)
188 mod = size % 1024
189 if mod :
190 roundoff = 1024 - mod
191 size = size + roundoff
192
193 cmd = 'chmod 777 ' + args.dumpSaveLoc
194 os.system(cmd)
195
196 #Run truncate to create file with given size
197 cmd = 'truncate -s ' + str(size) + ' '+ args.dumpSaveLoc
198 os.system(cmd)
199
200 if user is None:
201 cmd = './nbd-server 1043 '+ args.dumpSaveLoc
202 else:
203 cmd = 'nbd-server 1043 '+ args.dumpSaveLoc
204 os.system(cmd)
205
206
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600207def hilight(textToColor, color, bold):
Justin Thalere412dc22018-01-12 16:28:24 -0600208 """
209 Used to add highlights to various text for displaying in a terminal
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600210
Justin Thalere412dc22018-01-12 16:28:24 -0600211 @param textToColor: string, the text to be colored
212 @param color: string, used to color the text red or green
213 @param bold: boolean, used to bold the textToColor
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600214 @return: Buffered reader containing the modified string.
215 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600216 if(sys.platform.__contains__("win")):
217 if(color == "red"):
218 os.system('color 04')
219 elif(color == "green"):
220 os.system('color 02')
221 else:
222 os.system('color') #reset to default
223 return textToColor
224 else:
225 attr = []
226 if(color == "red"):
227 attr.append('31')
228 elif(color == "green"):
229 attr.append('32')
230 else:
231 attr.append('0')
232 if bold:
233 attr.append('1')
234 else:
235 attr.append('0')
236 return '\x1b[%sm%s\x1b[0m' % (';'.join(attr),textToColor)
237
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600238def connectionErrHandler(jsonFormat, errorStr, err):
Justin Thalere412dc22018-01-12 16:28:24 -0600239 """
240 Error handler various connection errors to bmcs
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600241
242 @param jsonFormat: boolean, used to output in json format with an error code.
Justin Thalere412dc22018-01-12 16:28:24 -0600243 @param errorStr: string, used to color the text red or green
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600244 @param err: string, the text from the exception
245 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600246 if errorStr == "Timeout":
247 if not jsonFormat:
248 return("FQPSPIN0000M: Connection timed out. Ensure you have network connectivity to the bmc")
249 else:
Justin Thaler115bca72018-05-25 19:29:08 -0500250 conerror = {}
251 conerror['CommonEventID'] = 'FQPSPIN0000M'
252 conerror['sensor']="N/A"
253 conerror['state']="N/A"
254 conerror['additionalDetails'] = "N/A"
255 conerror['Message']="Connection timed out. Ensure you have network connectivity to the BMC"
256 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."
257 conerror['Serviceable']="Yes"
258 conerror['CallHomeCandidate']= "No"
259 conerror['Severity'] = "Critical"
260 conerror['EventType'] = "Communication Failure/Timeout"
261 conerror['VMMigrationFlag'] = "Yes"
262 conerror["AffectedSubsystem"] = "Interconnect (Networking)"
263 conerror["timestamp"] = str(int(time.time()))
264 conerror["UserAction"] = "Verify network connectivity between the two systems and the bmc is functional."
265 eventdict = {}
266 eventdict['event0'] = conerror
267 eventdict['numAlerts'] = '1'
Justin Thaler115bca72018-05-25 19:29:08 -0500268 errorMessageStr = errorMessageStr = json.dumps(eventdict, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600269 return(errorMessageStr)
270 elif errorStr == "ConnectionError":
271 if not jsonFormat:
272 return("FQPSPIN0001M: " + str(err))
273 else:
Justin Thaler115bca72018-05-25 19:29:08 -0500274 conerror = {}
275 conerror['CommonEventID'] = 'FQPSPIN0001M'
276 conerror['sensor']="N/A"
277 conerror['state']="N/A"
278 conerror['additionalDetails'] = str(err)
279 conerror['Message']="Connection Error. View additional details for more information"
280 conerror['LengthyDescription'] = "A connection error to the specified BMC occurred and additional details are provided. Review these details to resolve the issue."
281 conerror['Serviceable']="Yes"
282 conerror['CallHomeCandidate']= "No"
283 conerror['Severity'] = "Critical"
284 conerror['EventType'] = "Communication Failure/Timeout"
285 conerror['VMMigrationFlag'] = "Yes"
286 conerror["AffectedSubsystem"] = "Interconnect (Networking)"
287 conerror["timestamp"] = str(int(time.time()))
288 conerror["UserAction"] = "Correct the issue highlighted in additional details and try again"
289 eventdict = {}
290 eventdict['event0'] = conerror
291 eventdict['numAlerts'] = '1'
Justin Thaler115bca72018-05-25 19:29:08 -0500292 errorMessageStr = json.dumps(eventdict, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600293 return(errorMessageStr)
Justin Thaler115bca72018-05-25 19:29:08 -0500294
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600295 else:
296 return("Unknown Error: "+ str(err))
297
Justin Thalere412dc22018-01-12 16:28:24 -0600298
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600299def setColWidth(keylist, numCols, dictForOutput, colNames):
Justin Thalere412dc22018-01-12 16:28:24 -0600300 """
301 Sets the output width of the columns to display
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600302
303 @param keylist: list, list of strings representing the keys for the dictForOutput
Justin Thalere412dc22018-01-12 16:28:24 -0600304 @param numcols: the total number of columns in the final output
305 @param dictForOutput: dictionary, contains the information to print to the screen
306 @param colNames: list, The strings to use for the column headings, in order of the keylist
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600307 @return: A list of the column widths for each respective column.
Justin Thalere412dc22018-01-12 16:28:24 -0600308 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600309 colWidths = []
310 for x in range(0, numCols):
311 colWidths.append(0)
312 for key in dictForOutput:
313 for x in range(0, numCols):
314 colWidths[x] = max(colWidths[x], len(str(dictForOutput[key][keylist[x]])))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600315
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600316 for x in range(0, numCols):
317 colWidths[x] = max(colWidths[x], len(colNames[x])) +2
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600318
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600319 return colWidths
320
321def loadPolicyTable(pathToPolicyTable):
Justin Thalere412dc22018-01-12 16:28:24 -0600322 """
323 loads a json based policy table into a dictionary
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600324
Justin Thalere412dc22018-01-12 16:28:24 -0600325 @param value: boolean, the value to convert
326 @return: A string of "Yes" or "No"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600327 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600328 policyTable = {}
329 if(os.path.exists(pathToPolicyTable)):
330 with open(pathToPolicyTable, 'r') as stream:
331 try:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600332 contents =json.load(stream)
333 policyTable = contents['events']
Justin Thalere412dc22018-01-12 16:28:24 -0600334 except Exception as err:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600335 print(err)
336 return policyTable
337
Justin Thalere412dc22018-01-12 16:28:24 -0600338
339def boolToString(value):
340 """
341 converts a boolean value to a human readable string value
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600342
Justin Thalere412dc22018-01-12 16:28:24 -0600343 @param value: boolean, the value to convert
344 @return: A string of "Yes" or "No"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600345 """
Justin Thalere412dc22018-01-12 16:28:24 -0600346 if(value):
347 return "Yes"
348 else:
349 return "No"
350
Justin Thalera6b5df72018-07-16 11:10:07 -0500351def stringToInt(text):
352 """
353 returns an integer if the string can be converted, otherwise returns the string
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600354
Justin Thalera6b5df72018-07-16 11:10:07 -0500355 @param text: the string to try to convert to an integer
356 """
357 if text.isdigit():
358 return int(text)
359 else:
360 return text
Justin Thalere412dc22018-01-12 16:28:24 -0600361
Justin Thalera6b5df72018-07-16 11:10:07 -0500362def naturalSort(text):
363 """
364 provides a way to naturally sort a list
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600365
Justin Thalera6b5df72018-07-16 11:10:07 -0500366 @param text: the key to convert for sorting
367 @return list containing the broken up string parts by integers and strings
368 """
369 stringPartList = []
370 for c in re.split('(\d+)', text):
371 stringPartList.append(stringToInt(c))
372 return stringPartList
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600373
Justin Thalere412dc22018-01-12 16:28:24 -0600374def tableDisplay(keylist, colNames, output):
375 """
376 Logs into the BMC and creates a session
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600377
Justin Thalere412dc22018-01-12 16:28:24 -0600378 @param keylist: list, keys for the output dictionary, ordered by colNames
379 @param colNames: Names for the Table of the columns
380 @param output: The dictionary of data to display
381 @return: Session object
382 """
383 colWidth = setColWidth(keylist, len(colNames), output, colNames)
384 row = ""
385 outputText = ""
386 for i in range(len(colNames)):
387 if (i != 0): row = row + "| "
388 row = row + colNames[i].ljust(colWidth[i])
389 outputText += row + "\n"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600390
Justin Thalera6b5df72018-07-16 11:10:07 -0500391 output_keys = list(output.keys())
392 output_keys.sort(key=naturalSort)
393 for key in output_keys:
Justin Thalere412dc22018-01-12 16:28:24 -0600394 row = ""
Justin Thaler8fe0c732018-07-24 14:32:35 -0500395 for i in range(len(keylist)):
Justin Thalere412dc22018-01-12 16:28:24 -0600396 if (i != 0): row = row + "| "
397 row = row + output[key][keylist[i]].ljust(colWidth[i])
398 outputText += row + "\n"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600399
Justin Thalere412dc22018-01-12 16:28:24 -0600400 return outputText
401
Justin Thaler22b1bb52018-03-15 13:31:32 -0500402def checkFWactivation(host, args, session):
403 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600404 Checks the software inventory for an image that is being activated.
405
Justin Thaler22b1bb52018-03-15 13:31:32 -0500406 @return: True if an image is being activated, false is no activations are happening
407 """
408 url="https://"+host+"/xyz/openbmc_project/software/enumerate"
Justin Thaler22b1bb52018-03-15 13:31:32 -0500409 try:
Justin Thaler27197622019-01-23 14:42:11 -0600410 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thaler22b1bb52018-03-15 13:31:32 -0500411 except(requests.exceptions.Timeout):
412 print(connectionErrHandler(args.json, "Timeout", None))
413 return(True)
414 except(requests.exceptions.ConnectionError) as err:
415 print( connectionErrHandler(args.json, "ConnectionError", err))
416 return True
Justin Thaler3a5771b2019-01-23 14:31:52 -0600417 fwInfo = resp.json()['data']
Justin Thaler22b1bb52018-03-15 13:31:32 -0500418 for key in fwInfo:
419 if 'Activation' in fwInfo[key]:
420 if 'Activating' in fwInfo[key]['Activation'] or 'Activating' in fwInfo[key]['RequestedActivation']:
421 return True
422 return False
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600423
Joy Onyerikwu182c3a32019-10-15 08:33:59 -0500424def login(host, username, pw,jsonFormat, allowExpiredPassword):
Justin Thalere412dc22018-01-12 16:28:24 -0600425 """
426 Logs into the BMC and creates a session
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600427
Justin Thalere412dc22018-01-12 16:28:24 -0600428 @param host: string, the hostname or IP address of the bmc to log into
429 @param username: The user name for the bmc to log into
430 @param pw: The password for the BMC to log into
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600431 @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 -0500432 @param allowExpiredPassword: true, if the requested operation should
433 be allowed when the password is expired
Justin Thalere412dc22018-01-12 16:28:24 -0600434 @return: Session object
435 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600436 if(jsonFormat==False):
437 print("Attempting login...")
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600438 mysess = requests.session()
439 try:
Justin Thaler27197622019-01-23 14:42:11 -0600440 r = mysess.post('https://'+host+'/login', headers=jsonHeader, json = {"data": [username, pw]}, verify=False, timeout=baseTimeout)
Sunitha Harish336cda22019-07-23 02:02:52 -0500441 if r.status_code == 200:
442 cookie = r.headers['Set-Cookie']
443 match = re.search('SESSION=(\w+);', cookie)
444 if match:
445 xAuthHeader['X-Auth-Token'] = match.group(1)
446 jsonHeader.update(xAuthHeader)
447 loginMessage = json.loads(r.text)
448 if (loginMessage['status'] != "ok"):
449 print(loginMessage["data"]["description"].encode('utf-8'))
450 sys.exit(1)
Joy Onyerikwu182c3a32019-10-15 08:33:59 -0500451 if (('extendedMessage' in r.json()) and
452 ('The password for this account must be changed' in r.json()['extendedMessage'])):
453 if not allowExpiredPassword:
454 print("The password for this system has expired and must be changed"+
455 "\nsee openbmctool.py set_password --help")
456 logout(host, username, pw, mysess, jsonFormat)
457 sys.exit(1)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600458# if(sys.version_info < (3,0)):
459# urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
460# if sys.version_info >= (3,0):
461# requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)
Sunitha Harish336cda22019-07-23 02:02:52 -0500462 return mysess
463 else:
464 return None
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600465 except(requests.exceptions.Timeout):
Justin Thaler115bca72018-05-25 19:29:08 -0500466 return (connectionErrHandler(jsonFormat, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600467 except(requests.exceptions.ConnectionError) as err:
Justin Thaler115bca72018-05-25 19:29:08 -0500468 return (connectionErrHandler(jsonFormat, "ConnectionError", err))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600469
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600470
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600471def logout(host, username, pw, session, jsonFormat):
Justin Thalere412dc22018-01-12 16:28:24 -0600472 """
473 Logs out of the bmc and terminates the session
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600474
Justin Thalere412dc22018-01-12 16:28:24 -0600475 @param host: string, the hostname or IP address of the bmc to log out of
476 @param username: The user name for the bmc to log out of
477 @param pw: The password for the BMC to log out of
478 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600479 @param jsonFormat: boolean, flag that will only allow relevant data from user command to be display. This function becomes silent when set to true.
480 """
Justin Thalere412dc22018-01-12 16:28:24 -0600481 try:
Justin Thaler27197622019-01-23 14:42:11 -0600482 r = session.post('https://'+host+'/logout', headers=jsonHeader,json = {"data": [username, pw]}, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600483 except(requests.exceptions.Timeout):
484 print(connectionErrHandler(jsonFormat, "Timeout", None))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600485
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600486 if(jsonFormat==False):
Matt Spinlereae05b02019-01-24 12:59:34 -0600487 if r.status_code == 200:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600488 print('User ' +username + ' has been logged out')
489
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600490
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600491def fru(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -0600492 """
493 prints out the system inventory. deprecated see fruPrint and fruList
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600494
Justin Thalere412dc22018-01-12 16:28:24 -0600495 @param host: string, the hostname or IP address of the bmc
496 @param args: contains additional arguments used by the fru sub command
497 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600498 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
499 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600500 #url="https://"+host+"/org/openbmc/inventory/system/chassis/enumerate"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600501
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600502 #print(url)
503 #res = session.get(url, headers=httpHeader, verify=False)
504 #print(res.text)
505 #sample = res.text
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600506
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600507 #inv_list = json.loads(sample)["data"]
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600508
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600509 url="https://"+host+"/xyz/openbmc_project/inventory/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600510 try:
Justin Thaler27197622019-01-23 14:42:11 -0600511 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600512 except(requests.exceptions.Timeout):
513 return(connectionErrHandler(args.json, "Timeout", None))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600514
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600515 sample = res.text
516# inv_list.update(json.loads(sample)["data"])
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600517#
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600518# #determine column width's
519# colNames = ["FRU Name", "FRU Type", "Has Fault", "Is FRU", "Present", "Version"]
520# colWidths = setColWidth(["FRU Name", "fru_type", "fault", "is_fru", "present", "version"], 6, inv_list, colNames)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600521#
522# 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 -0600523# "Present".ljust(colWidths[4]) + "Version".ljust(colWidths[5]))
524# format the output
525# for key in sorted(inv_list.keys()):
526# keyParts = key.split("/")
527# isFRU = "True" if (inv_list[key]["is_fru"]==1) else "False"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600528#
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600529# fruEntry = (keyParts[len(keyParts) - 1].ljust(colWidths[0]) + inv_list[key]["fru_type"].ljust(colWidths[1])+
530# inv_list[key]["fault"].ljust(colWidths[2])+isFRU.ljust(colWidths[3])+
531# inv_list[key]["present"].ljust(colWidths[4])+ inv_list[key]["version"].ljust(colWidths[5]))
532# if(isTTY):
533# if(inv_list[key]["is_fru"] == 1):
534# color = "green"
535# bold = True
536# else:
537# color='black'
538# bold = False
539# fruEntry = hilight(fruEntry, color, bold)
540# print (fruEntry)
541 return sample
Justin Thalere412dc22018-01-12 16:28:24 -0600542
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600543def fruPrint(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -0600544 """
545 prints out all inventory
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600546
Justin Thalere412dc22018-01-12 16:28:24 -0600547 @param host: string, the hostname or IP address of the bmc
548 @param args: contains additional arguments used by the fru sub command
549 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600550 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
551 @return returns the total fru list.
552 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600553 url="https://"+host+"/xyz/openbmc_project/inventory/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600554 try:
Justin Thaler27197622019-01-23 14:42:11 -0600555 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600556 except(requests.exceptions.Timeout):
557 return(connectionErrHandler(args.json, "Timeout", None))
558
Justin Thaler3a5771b2019-01-23 14:31:52 -0600559 frulist={}
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600560# print(res.text)
Justin Thaler3a5771b2019-01-23 14:31:52 -0600561 if res.status_code==200:
562 frulist['Hardware'] = res.json()['data']
563 else:
564 if not args.json:
565 return "Error retrieving the system inventory. BMC message: {msg}".format(msg=res.json()['message'])
566 else:
567 return res.json()
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600568 url="https://"+host+"/xyz/openbmc_project/software/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600569 try:
Justin Thaler27197622019-01-23 14:42:11 -0600570 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600571 except(requests.exceptions.Timeout):
572 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600573# print(res.text)
Justin Thaler3a5771b2019-01-23 14:31:52 -0600574 if res.status_code==200:
575 frulist['Software'] = res.json()['data']
576 else:
577 if not args.json():
578 return "Error retrieving the system inventory. BMC message: {msg}".format(msg=res.json()['message'])
579 else:
580 return res.json()
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600581 return frulist
582
Justin Thalere412dc22018-01-12 16:28:24 -0600583
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600584def fruList(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -0600585 """
586 prints out all inventory or only a specific specified item
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600587
Justin Thalere412dc22018-01-12 16:28:24 -0600588 @param host: string, the hostname or IP address of the bmc
589 @param args: contains additional arguments used by the fru sub command
590 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600591 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
592 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600593 if(args.items==True):
594 return fruPrint(host, args, session)
595 else:
Justin Thalere412dc22018-01-12 16:28:24 -0600596 return fruPrint(host, args, session)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600597
598
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600599
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600600def fruStatus(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -0600601 """
602 prints out the status of all FRUs
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600603
Justin Thalere412dc22018-01-12 16:28:24 -0600604 @param host: string, the hostname or IP address of the bmc
605 @param args: contains additional arguments used by the fru sub command
606 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600607 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
608 """
Justin Thalere412dc22018-01-12 16:28:24 -0600609 url="https://"+host+"/xyz/openbmc_project/inventory/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600610 try:
Matt Spinler220c3c42019-01-04 15:09:29 -0600611 res = session.get(url, headers=jsonHeader, verify=False)
Justin Thalere412dc22018-01-12 16:28:24 -0600612 except(requests.exceptions.Timeout):
613 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600614# print(res.text)
Justin Thaler3a5771b2019-01-23 14:31:52 -0600615 frulist = res.json()['data']
Justin Thalere412dc22018-01-12 16:28:24 -0600616 frus = {}
617 for key in frulist:
618 component = frulist[key]
619 isFru = False
620 present = False
621 func = False
622 hasSels = False
623 keyPieces = key.split('/')
624 fruName = keyPieces[-1]
625 if 'core' in fruName: #associate cores to cpus
626 fruName = keyPieces[-2] + '-' + keyPieces[-1]
627 if 'Functional' in component:
628 if('Present' in component):
Justin Thalere412dc22018-01-12 16:28:24 -0600629 if 'FieldReplaceable' in component:
630 if component['FieldReplaceable'] == 1:
631 isFru = True
632 if "fan" in fruName:
633 isFru = True;
634 if component['Present'] == 1:
635 present = True
636 if component['Functional'] == 1:
637 func = True
638 if ((key + "/fault") in frulist):
639 hasSels = True;
640 if args.verbose:
641 if hasSels:
642 loglist = []
643 faults = frulist[key+"/fault"]['endpoints']
644 for item in faults:
645 loglist.append(item.split('/')[-1])
646 frus[fruName] = {"compName": fruName, "Functional": boolToString(func), "Present":boolToString(present), "IsFru": boolToString(isFru), "selList": ', '.join(loglist).strip() }
647 else:
648 frus[fruName] = {"compName": fruName, "Functional": boolToString(func), "Present":boolToString(present), "IsFru": boolToString(isFru), "selList": "None" }
649 else:
650 frus[fruName] = {"compName": fruName, "Functional": boolToString(func), "Present":boolToString(present), "IsFru": boolToString(isFru), "hasSEL": boolToString(hasSels) }
Justin Thalerfb9c81c2018-07-16 11:14:37 -0500651 elif "power_supply" in fruName or "powersupply" in fruName:
Justin Thalere412dc22018-01-12 16:28:24 -0600652 if component['Present'] ==1:
653 present = True
654 isFru = True
655 if ((key + "/fault") in frulist):
656 hasSels = True;
657 if args.verbose:
658 if hasSels:
659 loglist = []
660 faults = frulist[key+"/fault"]['endpoints']
Obihörnchenff8035f2018-12-05 21:07:37 +0100661 for item in faults:
662 loglist.append(item.split('/')[-1])
Justin Thalere412dc22018-01-12 16:28:24 -0600663 frus[fruName] = {"compName": fruName, "Functional": "No", "Present":boolToString(present), "IsFru": boolToString(isFru), "selList": ', '.join(loglist).strip() }
664 else:
665 frus[fruName] = {"compName": fruName, "Functional": "Yes", "Present":boolToString(present), "IsFru": boolToString(isFru), "selList": "None" }
666 else:
667 frus[fruName] = {"compName": fruName, "Functional": boolToString(not hasSels), "Present":boolToString(present), "IsFru": boolToString(isFru), "hasSEL": boolToString(hasSels) }
668 if not args.json:
669 if not args.verbose:
670 colNames = ["Component", "Is a FRU", "Present", "Functional", "Has Logs"]
671 keylist = ["compName", "IsFru", "Present", "Functional", "hasSEL"]
672 else:
673 colNames = ["Component", "Is a FRU", "Present", "Functional", "Assoc. Log Number(s)"]
674 keylist = ["compName", "IsFru", "Present", "Functional", "selList"]
675 return tableDisplay(keylist, colNames, frus)
676 else:
677 return str(json.dumps(frus, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600678
Justin Thalere412dc22018-01-12 16:28:24 -0600679def sensor(host, args, session):
680 """
681 prints out all sensors
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600682
Justin Thalere412dc22018-01-12 16:28:24 -0600683 @param host: string, the hostname or IP address of the bmc
684 @param args: contains additional arguments used by the sensor sub command
685 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600686 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
687 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600688 url="https://"+host+"/xyz/openbmc_project/sensors/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600689 try:
Justin Thaler27197622019-01-23 14:42:11 -0600690 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600691 except(requests.exceptions.Timeout):
692 return(connectionErrHandler(args.json, "Timeout", None))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600693
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600694 #Get OCC status
695 url="https://"+host+"/org/open_power/control/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600696 try:
Justin Thaler27197622019-01-23 14:42:11 -0600697 occres = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600698 except(requests.exceptions.Timeout):
699 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600700 if not args.json:
701 colNames = ['sensor', 'type', 'units', 'value', 'target']
Justin Thaler3a5771b2019-01-23 14:31:52 -0600702 sensors = res.json()["data"]
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600703 output = {}
704 for key in sensors:
705 senDict = {}
706 keyparts = key.split("/")
Matt Spinler596ef742019-09-20 08:54:36 -0500707
708 # Associations like the following also show up here:
709 # /xyz/openbmc_project/sensors/<type>/<name>/<assoc-name>
710 # Skip them.
711 # Note: keyparts[0] = '' which is why there are 7 segments.
712 if len(keyparts) > 6:
713 continue
714
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600715 senDict['sensorName'] = keyparts[-1]
716 senDict['type'] = keyparts[-2]
Justin Thalere412dc22018-01-12 16:28:24 -0600717 try:
718 senDict['units'] = sensors[key]['Unit'].split('.')[-1]
719 except KeyError:
Justin Thaler22b1bb52018-03-15 13:31:32 -0500720 senDict['units'] = "N/A"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600721 if('Scale' in sensors[key]):
722 scale = 10 ** sensors[key]['Scale']
723 else:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600724 scale = 1
Justin Thaler22b1bb52018-03-15 13:31:32 -0500725 try:
726 senDict['value'] = str(sensors[key]['Value'] * scale)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600727 except KeyError:
Justin Thaler22b1bb52018-03-15 13:31:32 -0500728 if 'value' in sensors[key]:
729 senDict['value'] = sensors[key]['value']
730 else:
731 senDict['value'] = "N/A"
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600732 if 'Target' in sensors[key]:
733 senDict['target'] = str(sensors[key]['Target'])
734 else:
735 senDict['target'] = 'N/A'
736 output[senDict['sensorName']] = senDict
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600737
Justin Thaler3a5771b2019-01-23 14:31:52 -0600738 occstatus = occres.json()["data"]
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600739 if '/org/open_power/control/occ0' in occstatus:
740 occ0 = occstatus["/org/open_power/control/occ0"]['OccActive']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600741 if occ0 == 1:
742 occ0 = 'Active'
743 else:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600744 occ0 = 'Inactive'
745 output['OCC0'] = {'sensorName':'OCC0', 'type': 'Discrete', 'units': 'N/A', 'value': occ0, 'target': 'Active'}
746 occ1 = occstatus["/org/open_power/control/occ1"]['OccActive']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600747 if occ1 == 1:
748 occ1 = 'Active'
749 else:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600750 occ1 = 'Inactive'
751 output['OCC1'] = {'sensorName':'OCC1', 'type': 'Discrete', 'units': 'N/A', 'value': occ0, 'target': 'Active'}
752 else:
753 output['OCC0'] = {'sensorName':'OCC0', 'type': 'Discrete', 'units': 'N/A', 'value': 'Inactive', 'target': 'Inactive'}
754 output['OCC1'] = {'sensorName':'OCC1', 'type': 'Discrete', 'units': 'N/A', 'value': 'Inactive', 'target': 'Inactive'}
755 keylist = ['sensorName', 'type', 'units', 'value', 'target']
Justin Thalere412dc22018-01-12 16:28:24 -0600756
757 return tableDisplay(keylist, colNames, output)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600758 else:
759 return res.text + occres.text
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600760
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600761def sel(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -0600762 """
763 prints out the bmc alerts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600764
Justin Thalere412dc22018-01-12 16:28:24 -0600765 @param host: string, the hostname or IP address of the bmc
766 @param args: contains additional arguments used by the sel sub command
767 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600768 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
769 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600770
771 url="https://"+host+"/xyz/openbmc_project/logging/entry/enumerate"
Justin Thalere412dc22018-01-12 16:28:24 -0600772 try:
Justin Thaler27197622019-01-23 14:42:11 -0600773 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -0600774 except(requests.exceptions.Timeout):
775 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600776 return res.text
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600777
778
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600779def parseESEL(args, eselRAW):
Justin Thalere412dc22018-01-12 16:28:24 -0600780 """
781 parses the esel data and gets predetermined search terms
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600782
Justin Thalere412dc22018-01-12 16:28:24 -0600783 @param eselRAW: string, the raw esel string from the bmc
784 @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 -0600785 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600786 eselParts = {}
787 esel_bin = binascii.unhexlify(''.join(eselRAW.split()[16:]))
788 #search terms contains the search term as the key and the return dictionary key as it's value
789 searchTerms = { 'Signature Description':'signatureDescription', 'devdesc':'devdesc',
Justin Thaler22b1bb52018-03-15 13:31:32 -0500790 'Callout type': 'calloutType', 'Procedure':'procedure', 'Sensor Type': 'sensorType'}
Justin Thaler24d4efa2018-11-08 22:48:10 -0600791 uniqueID = str(uuid.uuid4())
792 eselBinPath = tempfile.gettempdir() + os.sep + uniqueID + 'esel.bin'
Justin Thalercf1deae2018-05-25 19:35:21 -0500793 with open(eselBinPath, 'wb') as f:
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600794 f.write(esel_bin)
795 errlPath = ""
796 #use the right errl file for the machine architecture
797 arch = platform.machine()
798 if(arch =='x86_64' or arch =='AMD64'):
799 if os.path.exists('/opt/ibm/ras/bin/x86_64/errl'):
800 errlPath = '/opt/ibm/ras/bin/x86_64/errl'
801 elif os.path.exists('errl/x86_64/errl'):
802 errlPath = 'errl/x86_64/errl'
803 else:
804 errlPath = 'x86_64/errl'
805 elif (platform.machine()=='ppc64le'):
806 if os.path.exists('/opt/ibm/ras/bin/ppc64le/errl'):
807 errlPath = '/opt/ibm/ras/bin/ppc64le/errl'
808 elif os.path.exists('errl/ppc64le/errl'):
809 errlPath = 'errl/ppc64le/errl'
810 else:
811 errlPath = 'ppc64le/errl'
812 else:
813 print("machine architecture not supported for parsing eSELs")
814 return eselParts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600815
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600816 if(os.path.exists(errlPath)):
Justin Thalercf1deae2018-05-25 19:35:21 -0500817 output= subprocess.check_output([errlPath, '-d', '--file='+eselBinPath]).decode('utf-8')
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600818# output = proc.communicate()[0]
819 lines = output.split('\n')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600820
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600821 if(hasattr(args, 'fullEsel')):
822 return output
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600823
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600824 for i in range(0, len(lines)):
825 lineParts = lines[i].split(':')
826 if(len(lineParts)>1): #ignore multi lines, output formatting lines, and other information
827 for term in searchTerms:
828 if(term in lineParts[0]):
829 temp = lines[i][lines[i].find(':')+1:].strip()[:-1].strip()
830 if lines[i+1].find(':') != -1:
831 if (len(lines[i+1].split(':')[0][1:].strip())==0):
832 while(len(lines[i][:lines[i].find(':')].strip())>2):
Justin Thaler43030422018-11-08 22:50:21 -0600833 #has multiple lines, process and update line counter
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600834 if((i+1) <= len(lines)):
835 i+=1
836 else:
837 i=i-1
838 break
Justin Thaler43030422018-11-08 22:50:21 -0600839 #Append the content from the next line removing the pretty display characters
840 #Finds the first colon then starts 2 characters after, then removes all whitespace
841 temp = temp + lines[i][lines[i].find(':')+2:].strip()[:-1].strip()[:-1].strip()
Justin Thaler22b1bb52018-03-15 13:31:32 -0500842 if(searchTerms[term] in eselParts):
843 eselParts[searchTerms[term]] = eselParts[searchTerms[term]] + ", " + temp
844 else:
845 eselParts[searchTerms[term]] = temp
Justin Thalercf1deae2018-05-25 19:35:21 -0500846 os.remove(eselBinPath)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600847 else:
848 print("errl file cannot be found")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600849
850 return eselParts
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600851
Justin Thalere412dc22018-01-12 16:28:24 -0600852
Matt Spinler02d0dff2018-08-29 13:19:25 -0500853def getESELSeverity(esel):
854 """
855 Finds the severity type in an eSEL from the User Header section.
856 @param esel - the eSEL data
857 @return severity - e.g. 'Critical'
858 """
859
860 # everything but 1 and 2 are Critical
861 # '1': 'recovered',
862 # '2': 'predictive',
863 # '4': 'unrecoverable',
864 # '5': 'critical',
865 # '6': 'diagnostic',
866 # '7': 'symptom'
867 severities = {
868 '1': 'Informational',
869 '2': 'Warning'
870 }
871
872 try:
873 headerPosition = esel.index('55 48') # 'UH'
874 # The severity is the last byte in the 8 byte section (a byte is ' bb')
875 severity = esel[headerPosition:headerPosition+32].split(' ')[-1]
876 type = severity[0]
877 except ValueError:
878 print("Could not find severity value in UH section in eSEL")
879 type = 'x';
880
881 return severities.get(type, 'Critical')
882
883
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600884def sortSELs(events):
Justin Thalere412dc22018-01-12 16:28:24 -0600885 """
886 sorts the sels by timestamp, then log entry number
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600887
Justin Thalere412dc22018-01-12 16:28:24 -0600888 @param events: Dictionary containing events
889 @return: list containing a list of the ordered log entries, and dictionary of keys
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600890 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600891 logNumList = []
892 timestampList = []
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600893 eventKeyDict = {}
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600894 eventsWithTimestamp = {}
895 logNum2events = {}
896 for key in events:
897 if key == 'numAlerts': continue
898 if 'callout' in key: continue
899 timestamp = (events[key]['timestamp'])
900 if timestamp not in timestampList:
901 eventsWithTimestamp[timestamp] = [events[key]['logNum']]
902 else:
903 eventsWithTimestamp[timestamp].append(events[key]['logNum'])
904 #map logNumbers to the event dictionary keys
905 eventKeyDict[str(events[key]['logNum'])] = key
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600906
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600907 timestampList = list(eventsWithTimestamp.keys())
908 timestampList.sort()
909 for ts in timestampList:
910 if len(eventsWithTimestamp[ts]) > 1:
911 tmplist = eventsWithTimestamp[ts]
912 tmplist.sort()
913 logNumList = logNumList + tmplist
914 else:
915 logNumList = logNumList + eventsWithTimestamp[ts]
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600916
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600917 return [logNumList, eventKeyDict]
918
Justin Thalere412dc22018-01-12 16:28:24 -0600919
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600920def parseAlerts(policyTable, selEntries, args):
Justin Thalere412dc22018-01-12 16:28:24 -0600921 """
922 parses alerts in the IBM CER format, using an IBM policy Table
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600923
Justin Thalere412dc22018-01-12 16:28:24 -0600924 @param policyTable: dictionary, the policy table entries
925 @param selEntries: dictionary, the alerts retrieved from the bmc
926 @return: A dictionary of the parsed entries, in chronological order
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600927 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600928 eventDict = {}
929 eventNum =""
930 count = 0
931 esel = ""
932 eselParts = {}
933 i2cdevice= ""
Matt Spinler02d0dff2018-08-29 13:19:25 -0500934 eselSeverity = None
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600935
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600936 'prepare and sort the event entries'
Justin Thaler667f87c2020-04-06 16:13:12 -0500937 sels = {}
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600938 for key in selEntries:
Justin Thaler667f87c2020-04-06 16:13:12 -0500939 if '/xyz/openbmc_project/logging/entry/' not in key: continue
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600940 if 'callout' not in key:
Justin Thaler667f87c2020-04-06 16:13:12 -0500941 sels[key] = selEntries[key]
942 sels[key]['logNum'] = key.split('/')[-1]
943 sels[key]['timestamp'] = selEntries[key]['Timestamp']
944 sortedEntries = sortSELs(sels)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600945 logNumList = sortedEntries[0]
946 eventKeyDict = sortedEntries[1]
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600947
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600948 for logNum in logNumList:
949 key = eventKeyDict[logNum]
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600950 hasEsel=False
951 i2creadFail = False
952 if 'callout' in key:
953 continue
954 else:
955 messageID = str(selEntries[key]['Message'])
956 addDataPiece = selEntries[key]['AdditionalData']
957 calloutIndex = 0
958 calloutFound = False
959 for i in range(len(addDataPiece)):
960 if("CALLOUT_INVENTORY_PATH" in addDataPiece[i]):
961 calloutIndex = i
962 calloutFound = True
963 fruCallout = str(addDataPiece[calloutIndex]).split('=')[1]
964 if("CALLOUT_DEVICE_PATH" in addDataPiece[i]):
965 i2creadFail = True
Matt Spinlerd178a472018-08-31 09:48:52 -0500966
967 fruCallout = str(addDataPiece[calloutIndex]).split('=')[1]
968
969 # Fall back to "I2C"/"FSI" if dev path isn't in policy table
970 if (messageID + '||' + fruCallout) not in policyTable:
971 i2cdevice = str(addDataPiece[i]).strip().split('=')[1]
972 i2cdevice = '/'.join(i2cdevice.split('/')[-4:])
973 if 'fsi' in str(addDataPiece[calloutIndex]).split('=')[1]:
974 fruCallout = 'FSI'
975 else:
976 fruCallout = 'I2C'
Justin Thalere34c43a2018-05-25 19:37:55 -0500977 calloutFound = True
978 if("CALLOUT_GPIO_NUM" in addDataPiece[i]):
979 if not calloutFound:
980 fruCallout = 'GPIO'
981 calloutFound = True
982 if("CALLOUT_IIC_BUS" in addDataPiece[i]):
983 if not calloutFound:
984 fruCallout = "I2C"
985 calloutFound = True
986 if("CALLOUT_IPMI_SENSOR_NUM" in addDataPiece[i]):
987 if not calloutFound:
988 fruCallout = "IPMI"
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600989 calloutFound = True
990 if("ESEL" in addDataPiece[i]):
991 esel = str(addDataPiece[i]).strip().split('=')[1]
Matt Spinler02d0dff2018-08-29 13:19:25 -0500992 eselSeverity = getESELSeverity(esel)
Justin Thalerf9aee3e2017-12-05 12:11:09 -0600993 if args.devdebug:
994 eselParts = parseESEL(args, esel)
995 hasEsel=True
996 if("GPU" in addDataPiece[i]):
997 fruCallout = '/xyz/openbmc_project/inventory/system/chassis/motherboard/gpu' + str(addDataPiece[i]).strip()[-1]
998 calloutFound = True
999 if("PROCEDURE" in addDataPiece[i]):
1000 fruCallout = str(hex(int(str(addDataPiece[i]).split('=')[1])))[2:]
1001 calloutFound = True
Justin Thalere412dc22018-01-12 16:28:24 -06001002 if("RAIL_NAME" in addDataPiece[i]):
1003 calloutFound=True
1004 fruCallout = str(addDataPiece[i]).split('=')[1].strip()
1005 if("INPUT_NAME" in addDataPiece[i]):
1006 calloutFound=True
1007 fruCallout = str(addDataPiece[i]).split('=')[1].strip()
1008 if("SENSOR_TYPE" in addDataPiece[i]):
1009 calloutFound=True
1010 fruCallout = str(addDataPiece[i]).split('=')[1].strip()
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001011
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001012 if(calloutFound):
Justin Thaler667f87c2020-04-06 16:13:12 -05001013 if fruCallout.strip() != "":
Justin Thaler22b1bb52018-03-15 13:31:32 -05001014 policyKey = messageID +"||" + fruCallout
Matt Spinler02d0dff2018-08-29 13:19:25 -05001015
1016 # Also use the severity for hostboot errors
1017 if eselSeverity and messageID == 'org.open_power.Host.Error.Event':
1018 policyKey += '||' + eselSeverity
1019
1020 # if not in the table, fall back to the original key
1021 if policyKey not in policyTable:
1022 policyKey = policyKey.replace('||'+eselSeverity, '')
1023
Justin Thalere34c43a2018-05-25 19:37:55 -05001024 if policyKey not in policyTable:
1025 policyKey = messageID
Justin Thaler22b1bb52018-03-15 13:31:32 -05001026 else:
1027 policyKey = messageID
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001028 else:
1029 policyKey = messageID
1030 event = {}
1031 eventNum = str(count)
1032 if policyKey in policyTable:
1033 for pkey in policyTable[policyKey]:
1034 if(type(policyTable[policyKey][pkey])== bool):
1035 event[pkey] = boolToString(policyTable[policyKey][pkey])
1036 else:
1037 if (i2creadFail and pkey == 'Message'):
1038 event[pkey] = policyTable[policyKey][pkey] + ' ' +i2cdevice
1039 else:
1040 event[pkey] = policyTable[policyKey][pkey]
1041 event['timestamp'] = selEntries[key]['Timestamp']
1042 event['resolved'] = bool(selEntries[key]['Resolved'])
1043 if(hasEsel):
1044 if args.devdebug:
1045 event['eselParts'] = eselParts
1046 event['raweSEL'] = esel
1047 event['logNum'] = key.split('/')[-1]
1048 eventDict['event' + eventNum] = event
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001049
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001050 else:
1051 severity = str(selEntries[key]['Severity']).split('.')[-1]
1052 if severity == 'Error':
1053 severity = 'Critical'
1054 eventDict['event'+eventNum] = {}
1055 eventDict['event' + eventNum]['error'] = "error: Not found in policy table: " + policyKey
1056 eventDict['event' + eventNum]['timestamp'] = selEntries[key]['Timestamp']
1057 eventDict['event' + eventNum]['Severity'] = severity
1058 if(hasEsel):
1059 if args.devdebug:
1060 eventDict['event' +eventNum]['eselParts'] = eselParts
1061 eventDict['event' +eventNum]['raweSEL'] = esel
1062 eventDict['event' +eventNum]['logNum'] = key.split('/')[-1]
1063 eventDict['event' +eventNum]['resolved'] = bool(selEntries[key]['Resolved'])
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001064 count += 1
1065 return eventDict
1066
1067
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001068def selDisplay(events, args):
Justin Thalere412dc22018-01-12 16:28:24 -06001069 """
1070 displays alerts in human readable format
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001071
Justin Thalere412dc22018-01-12 16:28:24 -06001072 @param events: Dictionary containing events
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001073 @return:
1074 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001075 activeAlerts = []
1076 historyAlerts = []
1077 sortedEntries = sortSELs(events)
1078 logNumList = sortedEntries[0]
1079 eventKeyDict = sortedEntries[1]
1080 keylist = ['Entry', 'ID', 'Timestamp', 'Serviceable', 'Severity','Message']
1081 if(args.devdebug):
1082 colNames = ['Entry', 'ID', 'Timestamp', 'Serviceable', 'Severity','Message', 'eSEL contents']
1083 keylist.append('eSEL')
1084 else:
1085 colNames = ['Entry', 'ID', 'Timestamp', 'Serviceable', 'Severity', 'Message']
1086 for log in logNumList:
1087 selDict = {}
1088 alert = events[eventKeyDict[str(log)]]
1089 if('error' in alert):
1090 selDict['Entry'] = alert['logNum']
1091 selDict['ID'] = 'Unknown'
1092 selDict['Timestamp'] = datetime.datetime.fromtimestamp(int(alert['timestamp']/1000)).strftime("%Y-%m-%d %H:%M:%S")
1093 msg = alert['error']
1094 polMsg = msg.split("policy table:")[0]
1095 msg = msg.split("policy table:")[1]
1096 msgPieces = msg.split("||")
1097 err = msgPieces[0]
1098 if(err.find("org.open_power.")!=-1):
1099 err = err.split("org.open_power.")[1]
1100 elif(err.find("xyz.openbmc_project.")!=-1):
1101 err = err.split("xyz.openbmc_project.")[1]
1102 else:
1103 err = msgPieces[0]
1104 callout = ""
1105 if len(msgPieces) >1:
1106 callout = msgPieces[1]
1107 if(callout.find("/org/open_power/")!=-1):
1108 callout = callout.split("/org/open_power/")[1]
1109 elif(callout.find("/xyz/openbmc_project/")!=-1):
1110 callout = callout.split("/xyz/openbmc_project/")[1]
1111 else:
1112 callout = msgPieces[1]
1113 selDict['Message'] = polMsg +"policy table: "+ err + "||" + callout
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001114 selDict['Serviceable'] = 'Unknown'
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001115 selDict['Severity'] = alert['Severity']
1116 else:
1117 selDict['Entry'] = alert['logNum']
1118 selDict['ID'] = alert['CommonEventID']
1119 selDict['Timestamp'] = datetime.datetime.fromtimestamp(int(alert['timestamp']/1000)).strftime("%Y-%m-%d %H:%M:%S")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001120 selDict['Message'] = alert['Message']
1121 selDict['Serviceable'] = alert['Serviceable']
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001122 selDict['Severity'] = alert['Severity']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001123
1124
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001125 eselOrder = ['refCode','signatureDescription', 'eselType', 'devdesc', 'calloutType', 'procedure']
1126 if ('eselParts' in alert and args.devdebug):
1127 eselOutput = ""
1128 for item in eselOrder:
1129 if item in alert['eselParts']:
1130 eselOutput = eselOutput + item + ": " + alert['eselParts'][item] + " | "
1131 selDict['eSEL'] = eselOutput
1132 else:
1133 if args.devdebug:
1134 selDict['eSEL'] = "None"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001135
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001136 if not alert['resolved']:
1137 activeAlerts.append(selDict)
1138 else:
1139 historyAlerts.append(selDict)
1140 mergedOutput = activeAlerts + historyAlerts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001141 colWidth = setColWidth(keylist, len(colNames), dict(enumerate(mergedOutput)), colNames)
1142
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001143 output = ""
1144 if(len(activeAlerts)>0):
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001145 row = ""
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001146 output +="----Active Alerts----\n"
1147 for i in range(0, len(colNames)):
1148 if i!=0: row =row + "| "
1149 row = row + colNames[i].ljust(colWidth[i])
1150 output += row + "\n"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001151
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001152 for i in range(0,len(activeAlerts)):
1153 row = ""
1154 for j in range(len(activeAlerts[i])):
1155 if (j != 0): row = row + "| "
1156 row = row + activeAlerts[i][keylist[j]].ljust(colWidth[j])
1157 output += row + "\n"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001158
1159 if(len(historyAlerts)>0):
1160 row = ""
1161 output+= "----Historical Alerts----\n"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001162 for i in range(len(colNames)):
1163 if i!=0: row =row + "| "
1164 row = row + colNames[i].ljust(colWidth[i])
1165 output += row + "\n"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001166
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001167 for i in range(0, len(historyAlerts)):
1168 row = ""
1169 for j in range(len(historyAlerts[i])):
1170 if (j != 0): row = row + "| "
1171 row = row + historyAlerts[i][keylist[j]].ljust(colWidth[j])
1172 output += row + "\n"
1173# print(events[eventKeyDict[str(log)]])
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001174 return output
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001175
Justin Thalere412dc22018-01-12 16:28:24 -06001176
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001177def selPrint(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001178 """
1179 prints out all bmc alerts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001180
Justin Thalere412dc22018-01-12 16:28:24 -06001181 @param host: string, the hostname or IP address of the bmc
1182 @param args: contains additional arguments used by the fru sub command
1183 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001184 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1185 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001186 if(args.policyTableLoc is None):
1187 if os.path.exists('policyTable.json'):
1188 ptableLoc = "policyTable.json"
1189 elif os.path.exists('/opt/ibm/ras/lib/policyTable.json'):
1190 ptableLoc = '/opt/ibm/ras/lib/policyTable.json'
1191 else:
1192 ptableLoc = 'lib/policyTable.json'
1193 else:
1194 ptableLoc = args.policyTableLoc
1195 policyTable = loadPolicyTable(ptableLoc)
1196 rawselEntries = ""
1197 if(hasattr(args, 'fileloc') and args.fileloc is not None):
1198 if os.path.exists(args.fileloc):
1199 with open(args.fileloc, 'r') as selFile:
1200 selLines = selFile.readlines()
1201 rawselEntries = ''.join(selLines)
1202 else:
1203 print("Error: File not found")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001204 sys.exit(1)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001205 else:
1206 rawselEntries = sel(host, args, session)
1207 loadFailed = False
1208 try:
1209 selEntries = json.loads(rawselEntries)
1210 except ValueError:
1211 loadFailed = True
1212 if loadFailed:
1213 cleanSels = json.dumps(rawselEntries).replace('\\n', '')
1214 #need to load json twice as original content was string escaped a second time
1215 selEntries = json.loads(json.loads(cleanSels))
1216 selEntries = selEntries['data']
Justin Thalere412dc22018-01-12 16:28:24 -06001217
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001218 if 'description' in selEntries:
1219 if(args.json):
1220 return("{\n\t\"numAlerts\": 0\n}")
1221 else:
1222 return("No log entries found")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001223
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001224 else:
1225 if(len(policyTable)>0):
1226 events = parseAlerts(policyTable, selEntries, args)
1227 if(args.json):
1228 events["numAlerts"] = len(events)
1229 retValue = str(json.dumps(events, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False))
1230 return retValue
1231 elif(hasattr(args, 'fullSel')):
1232 return events
1233 else:
1234 #get log numbers to order event entries sequentially
1235 return selDisplay(events, args)
1236 else:
1237 if(args.json):
1238 return selEntries
1239 else:
1240 print("error: Policy Table not found.")
1241 return selEntries
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001242
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001243def selList(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001244 """
1245 prints out all all bmc alerts, or only prints out the specified alerts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001246
Justin Thalere412dc22018-01-12 16:28:24 -06001247 @param host: string, the hostname or IP address of the bmc
1248 @param args: contains additional arguments used by the fru sub command
1249 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001250 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1251 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001252 return(sel(host, args, session))
1253
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001254
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001255def selClear(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001256 """
1257 clears all alerts
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001258
Justin Thalere412dc22018-01-12 16:28:24 -06001259 @param host: string, the hostname or IP address of the bmc
1260 @param args: contains additional arguments used by the fru sub command
1261 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001262 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1263 """
Matt Spinler47b13e92019-01-04 14:58:53 -06001264 url="https://"+host+"/xyz/openbmc_project/logging/action/DeleteAll"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001265 data = "{\"data\": [] }"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001266
Justin Thalere412dc22018-01-12 16:28:24 -06001267 try:
Justin Thaler27197622019-01-23 14:42:11 -06001268 res = session.post(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001269 except(requests.exceptions.Timeout):
1270 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001271 if res.status_code == 200:
1272 return "The Alert Log has been cleared. Please allow a few minutes for the action to complete."
1273 else:
1274 print("Unable to clear the logs, trying to clear 1 at a time")
1275 sels = json.loads(sel(host, args, session))['data']
1276 for key in sels:
1277 if 'callout' not in key:
1278 logNum = key.split('/')[-1]
1279 url = "https://"+ host+ "/xyz/openbmc_project/logging/entry/"+logNum+"/action/Delete"
1280 try:
Justin Thaler27197622019-01-23 14:42:11 -06001281 session.post(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001282 except(requests.exceptions.Timeout):
1283 return connectionErrHandler(args.json, "Timeout", None)
1284 sys.exit(1)
1285 except(requests.exceptions.ConnectionError) as err:
1286 return connectionErrHandler(args.json, "ConnectionError", err)
1287 sys.exit(1)
1288 return ('Sel clearing complete')
1289
1290def selSetResolved(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001291 """
1292 sets a sel entry to resolved
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001293
Justin Thalere412dc22018-01-12 16:28:24 -06001294 @param host: string, the hostname or IP address of the bmc
1295 @param args: contains additional arguments used by the fru sub command
1296 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001297 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1298 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001299 url="https://"+host+"/xyz/openbmc_project/logging/entry/" + str(args.selNum) + "/attr/Resolved"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001300 data = "{\"data\": 1 }"
Justin Thalere412dc22018-01-12 16:28:24 -06001301 try:
Justin Thaler27197622019-01-23 14:42:11 -06001302 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001303 except(requests.exceptions.Timeout):
1304 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001305 if res.status_code == 200:
1306 return "Sel entry "+ str(args.selNum) +" is now set to resolved"
1307 else:
1308 return "Unable to set the alert to resolved"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001309
Justin Thalere412dc22018-01-12 16:28:24 -06001310def selResolveAll(host, args, session):
1311 """
1312 sets a sel entry to resolved
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001313
Justin Thalere412dc22018-01-12 16:28:24 -06001314 @param host: string, the hostname or IP address of the bmc
1315 @param args: contains additional arguments used by the fru sub command
1316 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001317 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1318 """
Justin Thalere412dc22018-01-12 16:28:24 -06001319 rawselEntries = sel(host, args, session)
1320 loadFailed = False
1321 try:
1322 selEntries = json.loads(rawselEntries)
1323 except ValueError:
1324 loadFailed = True
1325 if loadFailed:
1326 cleanSels = json.dumps(rawselEntries).replace('\\n', '')
1327 #need to load json twice as original content was string escaped a second time
1328 selEntries = json.loads(json.loads(cleanSels))
1329 selEntries = selEntries['data']
1330
1331 if 'description' in selEntries:
1332 if(args.json):
1333 return("{\n\t\"selsResolved\": 0\n}")
1334 else:
1335 return("No log entries found")
1336 else:
1337 d = vars(args)
1338 successlist = []
1339 failedlist = []
1340 for key in selEntries:
1341 if 'callout' not in key:
1342 d['selNum'] = key.split('/')[-1]
1343 resolved = selSetResolved(host,args,session)
1344 if 'Sel entry' in resolved:
1345 successlist.append(d['selNum'])
1346 else:
1347 failedlist.append(d['selNum'])
1348 output = ""
1349 successlist.sort()
1350 failedlist.sort()
1351 if len(successlist)>0:
1352 output = "Successfully resolved: " +', '.join(successlist) +"\n"
1353 if len(failedlist)>0:
1354 output += "Failed to resolve: " + ', '.join(failedlist) + "\n"
1355 return output
1356
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001357def chassisPower(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001358 """
1359 called by the chassis function. Controls the power state of the chassis, or gets the status
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001360
Justin Thalere412dc22018-01-12 16:28:24 -06001361 @param host: string, the hostname or IP address of the bmc
1362 @param args: contains additional arguments used by the fru sub command
1363 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001364 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1365 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001366 if(args.powcmd == 'on'):
Justin Thaler22b1bb52018-03-15 13:31:32 -05001367 if checkFWactivation(host, args, session):
1368 return ("Chassis Power control disabled during firmware activation")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001369 print("Attempting to Power on...:")
1370 url="https://"+host+"/xyz/openbmc_project/state/host0/attr/RequestedHostTransition"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001371 data = '{"data":"xyz.openbmc_project.State.Host.Transition.On"}'
Justin Thalere412dc22018-01-12 16:28:24 -06001372 try:
Justin Thaler27197622019-01-23 14:42:11 -06001373 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001374 except(requests.exceptions.Timeout):
1375 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001376 return res.text
Justin Thalere412dc22018-01-12 16:28:24 -06001377 elif(args.powcmd == 'softoff'):
Justin Thaler22b1bb52018-03-15 13:31:32 -05001378 if checkFWactivation(host, args, session):
1379 return ("Chassis Power control disabled during firmware activation")
Justin Thalere412dc22018-01-12 16:28:24 -06001380 print("Attempting to Power off gracefully...:")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001381 url="https://"+host+"/xyz/openbmc_project/state/host0/attr/RequestedHostTransition"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001382 data = '{"data":"xyz.openbmc_project.State.Host.Transition.Off"}'
Justin Thalere412dc22018-01-12 16:28:24 -06001383 try:
Justin Thaler27197622019-01-23 14:42:11 -06001384 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001385 except(requests.exceptions.Timeout):
1386 return(connectionErrHandler(args.json, "Timeout", None))
1387 return res.text
1388 elif(args.powcmd == 'hardoff'):
Justin Thaler22b1bb52018-03-15 13:31:32 -05001389 if checkFWactivation(host, args, session):
1390 return ("Chassis Power control disabled during firmware activation")
Justin Thalere412dc22018-01-12 16:28:24 -06001391 print("Attempting to Power off immediately...:")
1392 url="https://"+host+"/xyz/openbmc_project/state/chassis0/attr/RequestedPowerTransition"
Justin Thalere412dc22018-01-12 16:28:24 -06001393 data = '{"data":"xyz.openbmc_project.State.Chassis.Transition.Off"}'
1394 try:
Justin Thaler27197622019-01-23 14:42:11 -06001395 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001396 except(requests.exceptions.Timeout):
1397 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001398 return res.text
1399 elif(args.powcmd == 'status'):
1400 url="https://"+host+"/xyz/openbmc_project/state/chassis0/attr/CurrentPowerState"
Justin Thalere412dc22018-01-12 16:28:24 -06001401 try:
Justin Thaler27197622019-01-23 14:42:11 -06001402 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001403 except(requests.exceptions.Timeout):
1404 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001405 chassisState = json.loads(res.text)['data'].split('.')[-1]
1406 url="https://"+host+"/xyz/openbmc_project/state/host0/attr/CurrentHostState"
Justin Thalere412dc22018-01-12 16:28:24 -06001407 try:
Justin Thaler27197622019-01-23 14:42:11 -06001408 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001409 except(requests.exceptions.Timeout):
1410 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001411 hostState = json.loads(res.text)['data'].split('.')[-1]
1412 url="https://"+host+"/xyz/openbmc_project/state/bmc0/attr/CurrentBMCState"
Justin Thalere412dc22018-01-12 16:28:24 -06001413 try:
Justin Thaler27197622019-01-23 14:42:11 -06001414 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001415 except(requests.exceptions.Timeout):
1416 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001417 bmcState = json.loads(res.text)['data'].split('.')[-1]
1418 if(args.json):
1419 outDict = {"Chassis Power State" : chassisState, "Host Power State" : hostState, "BMC Power State":bmcState}
1420 return json.dumps(outDict, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False)
1421 else:
1422 return "Chassis Power State: " +chassisState + "\nHost Power State: " + hostState + "\nBMC Power State: " + bmcState
1423 else:
1424 return "Invalid chassis power command"
1425
Justin Thalere412dc22018-01-12 16:28:24 -06001426
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001427def chassisIdent(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001428 """
1429 called by the chassis function. Controls the identify led of the chassis. Sets or gets the state
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001430
Justin Thalere412dc22018-01-12 16:28:24 -06001431 @param host: string, the hostname or IP address of the bmc
1432 @param args: contains additional arguments used by the fru sub command
1433 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001434 @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 -06001435 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001436 if(args.identcmd == 'on'):
1437 print("Attempting to turn identify light on...:")
1438 url="https://"+host+"/xyz/openbmc_project/led/groups/enclosure_identify/attr/Asserted"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001439 data = '{"data":true}'
Justin Thalere412dc22018-01-12 16:28:24 -06001440 try:
Justin Thaler27197622019-01-23 14:42:11 -06001441 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001442 except(requests.exceptions.Timeout):
1443 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001444 return res.text
1445 elif(args.identcmd == 'off'):
1446 print("Attempting to turn identify light off...:")
1447 url="https://"+host+"/xyz/openbmc_project/led/groups/enclosure_identify/attr/Asserted"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001448 data = '{"data":false}'
Justin Thalere412dc22018-01-12 16:28:24 -06001449 try:
Justin Thaler27197622019-01-23 14:42:11 -06001450 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001451 except(requests.exceptions.Timeout):
1452 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001453 return res.text
1454 elif(args.identcmd == 'status'):
1455 url="https://"+host+"/xyz/openbmc_project/led/groups/enclosure_identify"
Justin Thalere412dc22018-01-12 16:28:24 -06001456 try:
Justin Thaler27197622019-01-23 14:42:11 -06001457 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06001458 except(requests.exceptions.Timeout):
1459 return(connectionErrHandler(args.json, "Timeout", None))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001460 status = json.loads(res.text)['data']
1461 if(args.json):
1462 return status
1463 else:
1464 if status['Asserted'] == 0:
1465 return "Identify light is off"
1466 else:
1467 return "Identify light is blinking"
1468 else:
1469 return "Invalid chassis identify command"
1470
Justin Thalere412dc22018-01-12 16:28:24 -06001471
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001472def chassis(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001473 """
1474 controls the different chassis commands
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001475
Justin Thalere412dc22018-01-12 16:28:24 -06001476 @param host: string, the hostname or IP address of the bmc
1477 @param args: contains additional arguments used by the fru sub command
1478 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001479 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1480 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001481 if(hasattr(args, 'powcmd')):
1482 result = chassisPower(host,args,session)
1483 elif(hasattr(args, 'identcmd')):
1484 result = chassisIdent(host, args, session)
1485 else:
Justin Thaler22b1bb52018-03-15 13:31:32 -05001486 return "This feature is not yet implemented"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001487 return result
Justin Thalere412dc22018-01-12 16:28:24 -06001488
Ravi Tejad8be0b42020-03-18 14:31:46 -05001489def dumpRetrieve(host, args, session):
1490 """
1491 Downloads dump of given dump type
1492
1493 @param host: string, the hostname or IP address of the bmc
1494 @param args: contains additional arguments used by the collectServiceData sub command
1495 @param session: the active session to use
1496 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1497 """
1498 dumpType = args.dumpType
1499 if (args.dumpType=="SystemDump"):
1500 dumpResp=systemDumpRetrieve(host,args,session)
1501 elif(args.dumpType=="bmc"):
1502 dumpResp=bmcDumpRetrieve(host,args,session)
1503 return dumpResp
1504
1505def dumpList(host, args, session):
1506 """
1507 Lists dump of the given dump type
1508
1509 @param host: string, the hostname or IP address of the bmc
1510 @param args: contains additional arguments used by the collectServiceData sub command
1511 @param session: the active session to use
1512 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1513 """
1514 if (args.dumpType=="SystemDump"):
1515 dumpResp=systemDumpList(host,args,session)
1516 elif(args.dumpType=="bmc"):
1517 dumpResp=bmcDumpList(host,args,session)
1518 return dumpResp
1519
1520def dumpDelete(host, args, session):
1521 """
1522 Deletes dump of the given dump type
1523
1524 @param host: string, the hostname or IP address of the bmc
1525 @param args: contains additional arguments used by the collectServiceData sub command
1526 @param session: the active session to use
1527 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1528 """
1529 if (args.dumpType=="SystemDump"):
1530 dumpResp=systemDumpDelete(host,args,session)
1531 elif(args.dumpType=="bmc"):
1532 dumpResp=bmcDumpDelete(host,args,session)
1533 return dumpResp
1534
1535def dumpDeleteAll(host, args, session):
1536 """
1537 Deletes all dumps of the given dump type
1538
1539 @param host: string, the hostname or IP address of the bmc
1540 @param args: contains additional arguments used by the collectServiceData sub command
1541 @param session: the active session to use
1542 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1543 """
1544 if (args.dumpType=="SystemDump"):
1545 dumpResp=systemDumpDeleteAll(host,args,session)
1546 elif(args.dumpType=="bmc"):
1547 dumpResp=bmcDumpDeleteAll(host,args,session)
1548 return dumpResp
1549
1550def dumpCreate(host, args, session):
1551 """
1552 Creates dump for the given dump type
1553
1554 @param host: string, the hostname or IP address of the bmc
1555 @param args: contains additional arguments used by the collectServiceData sub command
1556 @param session: the active session to use
1557 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1558 """
1559 if (args.dumpType=="SystemDump"):
1560 dumpResp=systemDumpCreate(host,args,session)
1561 elif(args.dumpType=="bmc"):
1562 dumpResp=bmcDumpDelete(host,args,session)
1563 return dumpResp
1564
1565
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001566def bmcDumpRetrieve(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001567 """
1568 Downloads a dump file from the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001569
Justin Thalere412dc22018-01-12 16:28:24 -06001570 @param host: string, the hostname or IP address of the bmc
1571 @param args: contains additional arguments used by the collectServiceData sub command
1572 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001573 @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 -06001574 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001575 dumpNum = args.dumpNum
1576 if (args.dumpSaveLoc is not None):
1577 saveLoc = args.dumpSaveLoc
1578 else:
Justin Thalercf1deae2018-05-25 19:35:21 -05001579 saveLoc = tempfile.gettempdir()
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001580 url ='https://'+host+'/download/dump/' + str(dumpNum)
1581 try:
Justin Thaler27197622019-01-23 14:42:11 -06001582 r = session.get(url, headers=jsonHeader, stream=True, verify=False, timeout=baseTimeout)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001583 if (args.dumpSaveLoc is not None):
1584 if os.path.exists(saveLoc):
1585 if saveLoc[-1] != os.path.sep:
1586 saveLoc = saveLoc + os.path.sep
1587 filename = saveLoc + host+'-dump' + str(dumpNum) + '.tar.xz'
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001588
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001589 else:
1590 return 'Invalid save location specified'
1591 else:
Justin Thalercf1deae2018-05-25 19:35:21 -05001592 filename = tempfile.gettempdir()+os.sep + host+'-dump' + str(dumpNum) + '.tar.xz'
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001593
1594 with open(filename, 'wb') as f:
1595 for chunk in r.iter_content(chunk_size =1024):
1596 if chunk:
1597 f.write(chunk)
1598 return 'Saved as ' + filename
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001599
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001600 except(requests.exceptions.Timeout):
1601 return connectionErrHandler(args.json, "Timeout", None)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001602
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001603 except(requests.exceptions.ConnectionError) as err:
1604 return connectionErrHandler(args.json, "ConnectionError", err)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001605
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001606def bmcDumpList(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001607 """
1608 Lists the number of dump files on the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001609
Justin Thalere412dc22018-01-12 16:28:24 -06001610 @param host: string, the hostname or IP address of the bmc
1611 @param args: contains additional arguments used by the collectServiceData sub command
1612 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001613 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1614 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001615 url ='https://'+host+'/xyz/openbmc_project/dump/list'
1616 try:
Justin Thaler27197622019-01-23 14:42:11 -06001617 r = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thaler3a5771b2019-01-23 14:31:52 -06001618 dumpList = r.json()
1619 return dumpList
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001620 except(requests.exceptions.Timeout):
1621 return connectionErrHandler(args.json, "Timeout", None)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001622
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001623 except(requests.exceptions.ConnectionError) as err:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001624 return connectionErrHandler(args.json, "ConnectionError", err)
1625
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001626def bmcDumpDelete(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001627 """
1628 Deletes BMC dump files from the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001629
Justin Thalere412dc22018-01-12 16:28:24 -06001630 @param host: string, the hostname or IP address of the bmc
1631 @param args: contains additional arguments used by the collectServiceData sub command
1632 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001633 @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 -06001634 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001635 dumpList = []
1636 successList = []
1637 failedList = []
1638 if args.dumpNum is not None:
1639 if isinstance(args.dumpNum, list):
1640 dumpList = args.dumpNum
1641 else:
1642 dumpList.append(args.dumpNum)
1643 for dumpNum in dumpList:
1644 url ='https://'+host+'/xyz/openbmc_project/dump/entry/'+str(dumpNum)+'/action/Delete'
1645 try:
Justin Thaler27197622019-01-23 14:42:11 -06001646 r = session.post(url, headers=jsonHeader, json = {"data": []}, verify=False, timeout=baseTimeout)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001647 if r.status_code == 200:
1648 successList.append(str(dumpNum))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001649 else:
1650 failedList.append(str(dumpNum))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001651 except(requests.exceptions.Timeout):
1652 return connectionErrHandler(args.json, "Timeout", None)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001653 except(requests.exceptions.ConnectionError) as err:
1654 return connectionErrHandler(args.json, "ConnectionError", err)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001655 output = "Successfully deleted dumps: " + ', '.join(successList)
1656 if(len(failedList)>0):
1657 output+= '\nFailed to delete dumps: ' + ', '.join(failedList)
1658 return output
1659 else:
1660 return 'You must specify an entry number to delete'
1661
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001662def bmcDumpDeleteAll(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001663 """
1664 Deletes All BMC dump files from the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001665
Justin Thalere412dc22018-01-12 16:28:24 -06001666 @param host: string, the hostname or IP address of the bmc
1667 @param args: contains additional arguments used by the collectServiceData sub command
1668 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001669 @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 -06001670 """
1671 dumpResp = bmcDumpList(host, args, session)
1672 if 'FQPSPIN0000M' in dumpResp or 'FQPSPIN0001M'in dumpResp:
1673 return dumpResp
Justin Thaler3a5771b2019-01-23 14:31:52 -06001674 dumpList = dumpResp['data']
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001675 d = vars(args)
1676 dumpNums = []
1677 for dump in dumpList:
Alvin Wang28bd09d2019-10-28 13:23:58 +08001678 dumpNum = dump.strip().split('/')[-1]
1679 if dumpNum.isdigit():
1680 dumpNums.append(int(dumpNum))
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001681 d['dumpNum'] = dumpNums
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001682
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001683 return bmcDumpDelete(host, args, session)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001684
Justin Thalere412dc22018-01-12 16:28:24 -06001685
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001686def bmcDumpCreate(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06001687 """
1688 Creates a bmc dump file
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001689
Justin Thalere412dc22018-01-12 16:28:24 -06001690 @param host: string, the hostname or IP address of the bmc
1691 @param args: contains additional arguments used by the collectServiceData sub command
1692 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001693 @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 -06001694 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001695 url = 'https://'+host+'/xyz/openbmc_project/dump/action/CreateDump'
1696 try:
Justin Thaler27197622019-01-23 14:42:11 -06001697 r = session.post(url, headers=jsonHeader, json = {"data": []}, verify=False, timeout=baseTimeout)
Matt Spinlereae05b02019-01-24 12:59:34 -06001698 if(r.status_code == 200 and not args.json):
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001699 return ('Dump successfully created')
Justin Thaler3a5771b2019-01-23 14:31:52 -06001700 elif(args.json):
1701 return r.json()
Justin Thalerf9aee3e2017-12-05 12:11:09 -06001702 else:
1703 return ('Failed to create dump')
1704 except(requests.exceptions.Timeout):
1705 return connectionErrHandler(args.json, "Timeout", None)
1706 except(requests.exceptions.ConnectionError) as err:
1707 return connectionErrHandler(args.json, "ConnectionError", err)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001708
Ravi Tejad8be0b42020-03-18 14:31:46 -05001709def systemDumpRetrieve(host, args, session):
1710 """
1711 Downloads system dump
1712
1713 @param host: string, the hostname or IP address of the bmc
1714 @param args: contains additional arguments used by the collectServiceData sub command
1715 @param session: the active session to use
1716 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1717 """
1718 NBDSetup(host,args,session)
1719 pipe = NBDPipe()
1720 pipe.openHTTPSocket(args)
1721 pipe.openTCPSocket()
1722 pipe.waitformessage()
1723
1724def systemDumpList(host, args, session):
1725 """
1726 Lists system dumps
1727
1728 @param host: string, the hostname or IP address of the bmc
1729 @param args: contains additional arguments used by the collectServiceData sub command
1730 @param session: the active session to use
1731 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1732 """
1733 print("in systemDumpList")
1734 url = "https://"+host+"/redfish/v1/Systems/system/LogServices/"+args.dumpType+"/Entries"
1735 try:
1736 r = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
1737 dumpList = r.json()
1738 return dumpList
1739 except(requests.exceptions.Timeout):
1740 return connectionErrHandler(args.json, "Timeout", None)
1741
1742 except(requests.exceptions.ConnectionError) as err:
1743 return connectionErrHandler(args.json, "ConnectionError", err)
1744
1745
1746def systemDumpDelete(host, args, session):
1747 """
1748 Deletes system dump
1749
1750 @param host: string, the hostname or IP address of the bmc
1751 @param args: contains additional arguments used by the collectServiceData sub command
1752 @param session: the active session to use
1753 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1754 """
1755 dumpList = []
1756 successList = []
1757 failedList = []
1758 if args.dumpNum is not None:
1759 if isinstance(args.dumpNum, list):
1760 dumpList = args.dumpNum
1761 else:
1762 dumpList.append(args.dumpNum)
1763 for dumpNum in dumpList:
1764 url = 'https://'+host+'/redfish/v1/Systems/system/LogServices/'+args.dumpType+'/Entries/'+ str(dumpNum)
1765 try:
1766 r = session.delete(url, headers=jsonHeader, json = {"data": []}, verify=False, timeout=baseTimeout)
1767 if r.status_code == 200:
1768 successList.append(str(dumpNum))
1769 else:
1770 failedList.append(str(dumpNum))
1771 except(requests.exceptions.Timeout):
1772 return connectionErrHandler(args.json, "Timeout", None)
1773 except(requests.exceptions.ConnectionError) as err:
1774 return connectionErrHandler(args.json, "ConnectionError", err)
1775 output = "Successfully deleted dumps: " + ', '.join(successList)
1776 if(len(failedList)>0):
1777 output+= '\nFailed to delete dumps: ' + ', '.join(failedList)
1778 return output
1779 else:
1780 return 'You must specify an entry number to delete'
1781
1782def systemDumpDeleteAll(host, args, session):
1783 """
1784 Deletes All system dumps
1785
1786 @param host: string, the hostname or IP address of the bmc
1787 @param args: contains additional arguments used by the collectServiceData sub command
1788 @param session: the active session to use
1789 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1790 """
1791 url = 'https://'+host+'/redfish/v1/Systems/system/LogServices/'+args.dumpType+'/Actions/LogService.ClearLog'
1792 try:
1793 r = session.post(url, headers=jsonHeader, json = {"data": []}, verify=False, timeout=baseTimeout)
1794 if(r.status_code == 200 and not args.json):
1795 return ('Dumps successfully cleared')
1796 elif(args.json):
1797 return r.json()
1798 else:
1799 return ('Failed to clear dumps')
1800 except(requests.exceptions.Timeout):
1801 return connectionErrHandler(args.json, "Timeout", None)
1802 except(requests.exceptions.ConnectionError) as err:
1803 return connectionErrHandler(args.json, "ConnectionError", err)
1804
1805def systemDumpCreate(host, args, session):
1806 """
1807 Creates a system dump
1808
1809 @param host: string, the hostname or IP address of the bmc
1810 @param args: contains additional arguments used by the collectServiceData sub command
1811 @param session: the active session to use
1812 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1813 """
1814 url = 'https://'+host+'/redfish/v1/Systems/system/LogServices/'+args.dumpType+'/Actions/Oem/Openbmc/LogService.CreateLog'
1815 try:
1816 r = session.post(url, headers=jsonHeader, json = {"data": []}, verify=False, timeout=baseTimeout)
1817 if(r.status_code == 200 and not args.json):
1818 return ('Dump successfully created')
1819 elif(args.json):
1820 return r.json()
1821 else:
1822 return ('Failed to create dump')
1823 except(requests.exceptions.Timeout):
1824 return connectionErrHandler(args.json, "Timeout", None)
1825 except(requests.exceptions.ConnectionError) as err:
1826 return connectionErrHandler(args.json, "ConnectionError", err)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001827
Justin Thaler666cf342019-01-23 14:44:27 -06001828def csdDumpInitiate(host, args, session):
1829 """
1830 Starts the process of getting the current list of dumps then initiates the creation of one.
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06001831
Justin Thaler666cf342019-01-23 14:44:27 -06001832 @param host: string, the hostname or IP address of the bmc
1833 @param args: contains additional arguments used by the collectServiceData sub command
1834 @param session: the active session to use
1835 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1836 """
1837 errorInfo = ""
1838 dumpcount = 0
1839 try:
1840 d = vars(args)
1841 d['json'] = True
1842 except Exception as e:
1843 errorInfo += "Failed to set the json flag to True \n Exception: {eInfo}\n".format(eInfo=e)
1844
1845 try:
1846 for i in range(3):
1847 dumpInfo = bmcDumpList(host, args, session)
1848 if 'data' in dumpInfo:
1849 dumpcount = len(dumpInfo['data'])
1850 break
1851 else:
1852 errorInfo+= "Dump List Message returned: " + json.dumps(dumpInfo,indent=0, separators=(',', ':')).replace('\n','') +"\n"
1853 except Exception as e:
1854 errorInfo+= "Failed to collect the list of dumps.\nException: {eInfo}\n".format(eInfo=e)
1855
1856 #Create a user initiated dump
1857 try:
1858 for i in range(3):
1859 dumpcreated = bmcDumpCreate(host, args, session)
1860 if 'message' in dumpcreated:
1861 if 'ok' in dumpcreated['message'].lower():
1862 break
1863 else:
1864 errorInfo+= "Dump create message returned: " + json.dumps(dumpInfo,indent=0, separators=(',', ':')).replace('\n','') +"\n"
1865 else:
1866 errorInfo+= "Dump create message returned: " + json.dumps(dumpInfo,indent=0, separators=(',', ':')).replace('\n','') +"\n"
1867 except Exception as e:
1868 errorInfo+= "Dump create exception encountered: {eInfo}\n".format(eInfo=e)
1869
1870 output = {}
1871 output['errors'] = errorInfo
1872 output['dumpcount'] = dumpcount
1873 return output
1874
1875def csdInventory(host, args,session, fileDir):
1876 """
1877 Collects the BMC inventory, retrying if necessary
1878
1879 @param host: string, the hostname or IP address of the bmc
1880 @param args: contains additional arguments used by the collectServiceData sub command
1881 @param session: the active session to use
1882 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1883 @param fileDir: string representation of the path to use for putting files created
1884 """
1885 errorInfo = "===========Inventory =============\n"
1886 output={}
1887 inventoryCollected = False
1888 try:
1889 for i in range(3):
1890 frulist = fruPrint(host, args, session)
1891 if 'Hardware' in frulist:
1892 inventoryCollected = True
1893 break
1894 else:
1895 errorInfo += json.dumps(frulist, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n'
1896 except Exception as e:
1897 errorInfo += "Inventory collection exception: {eInfo}\n".format(eInfo=e)
1898 if inventoryCollected:
1899 try:
1900 with open(fileDir +os.sep+'inventory.txt', 'w') as f:
1901 f.write(json.dumps(frulist, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n')
1902 print("Inventory collected and stored in " + fileDir + os.sep + "inventory.txt")
1903 output['fileLoc'] = fileDir+os.sep+'inventory.txt'
1904 except Exception as e:
1905 print("Failed to write inventory to file.")
1906 errorInfo += "Error writing inventory to the file. Exception: {eInfo}\n".format(eInfo=e)
1907
1908 output['errors'] = errorInfo
1909
1910 return output
1911
1912def csdSensors(host, args,session, fileDir):
1913 """
1914 Collects the BMC sensor readings, retrying if necessary
1915
1916 @param host: string, the hostname or IP address of the bmc
1917 @param args: contains additional arguments used by the collectServiceData sub command
1918 @param session: the active session to use
1919 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1920 @param fileDir: string representation of the path to use for putting files created
1921 """
1922 errorInfo = "===========Sensors =============\n"
1923 sensorsCollected = False
1924 output={}
1925 try:
1926 d = vars(args)
1927 d['json'] = False
1928 except Exception as e:
1929 errorInfo += "Failed to set the json flag to False \n Exception: {eInfo}\n".format(eInfo=e)
1930
1931 try:
1932 for i in range(3):
1933 sensorReadings = sensor(host, args, session)
1934 if 'OCC0' in sensorReadings:
1935 sensorsCollected = True
1936 break
1937 else:
1938 errorInfo += sensorReadings
1939 except Exception as e:
1940 errorInfo += "Sensor reading collection exception: {eInfo}\n".format(eInfo=e)
1941 if sensorsCollected:
1942 try:
1943 with open(fileDir +os.sep+'sensorReadings.txt', 'w') as f:
1944 f.write(sensorReadings)
1945 print("Sensor readings collected and stored in " + fileDir + os.sep+ "sensorReadings.txt")
1946 output['fileLoc'] = fileDir+os.sep+'sensorReadings.txt'
1947 except Exception as e:
1948 print("Failed to write sensor readings to file system.")
1949 errorInfo += "Error writing sensor readings to the file. Exception: {eInfo}\n".format(eInfo=e)
1950
1951 output['errors'] = errorInfo
1952 return output
1953
1954def csdLEDs(host,args, session, fileDir):
1955 """
1956 Collects the BMC LED status, retrying if necessary
1957
1958 @param host: string, the hostname or IP address of the bmc
1959 @param args: contains additional arguments used by the collectServiceData sub command
1960 @param session: the active session to use
1961 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
1962 @param fileDir: string representation of the path to use for putting files created
1963 """
1964 errorInfo = "===========LEDs =============\n"
1965 ledsCollected = False
1966 output={}
1967 try:
1968 d = vars(args)
1969 d['json'] = True
1970 except Exception as e:
1971 errorInfo += "Failed to set the json flag to False \n Exception: {eInfo}\n".format(eInfo=e)
1972 try:
1973 url="https://"+host+"/xyz/openbmc_project/led/enumerate"
1974 httpHeader = {'Content-Type':'application/json'}
1975 for i in range(3):
1976 try:
1977 ledRes = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
1978 if ledRes.status_code == 200:
1979 ledsCollected = True
1980 leds = ledRes.json()['data']
1981 break
1982 else:
1983 errorInfo += ledRes.text
1984 except(requests.exceptions.Timeout):
1985 errorInfo+=json.dumps( connectionErrHandler(args.json, "Timeout", None), sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n'
1986 except(requests.exceptions.ConnectionError) as err:
1987 errorInfo += json.dumps(connectionErrHandler(args.json, "ConnectionError", err), sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n'
1988 except Exception as e:
1989 errorInfo += "LED status collection exception: {eInfo}\n".format(eInfo=e)
1990
1991 if ledsCollected:
1992 try:
1993 with open(fileDir +os.sep+'ledStatus.txt', 'w') as f:
1994 f.write(json.dumps(leds, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n')
1995 print("LED status collected and stored in " + fileDir + os.sep+ "ledStatus.txt")
1996 output['fileLoc'] = fileDir+os.sep+'ledStatus.txt'
1997 except Exception as e:
1998 print("Failed to write LED status to file system.")
1999 errorInfo += "Error writing LED status to the file. Exception: {eInfo}\n".format(eInfo=e)
2000
2001 output['errors'] = errorInfo
2002 return output
2003
2004def csdSelShortList(host, args, session, fileDir):
2005 """
2006 Collects the BMC log entries, retrying if necessary
2007
2008 @param host: string, the hostname or IP address of the bmc
2009 @param args: contains additional arguments used by the collectServiceData sub command
2010 @param session: the active session to use
2011 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
2012 @param fileDir: string representation of the path to use for putting files created
2013 """
2014 errorInfo = "===========SEL Short List =============\n"
2015 selsCollected = False
2016 output={}
2017 try:
2018 d = vars(args)
2019 d['json'] = False
2020 except Exception as e:
2021 errorInfo += "Failed to set the json flag to False \n Exception: {eInfo}\n".format(eInfo=e)
2022
2023 try:
2024 for i in range(3):
2025 sels = selPrint(host,args,session)
2026 if '----Active Alerts----' in sels or 'No log entries found' in sels or '----Historical Alerts----' in sels:
2027 selsCollected = True
2028 break
2029 else:
2030 errorInfo += sels + '\n'
2031 except Exception as e:
2032 errorInfo += "SEL short list collection exception: {eInfo}\n".format(eInfo=e)
2033
2034 if selsCollected:
2035 try:
2036 with open(fileDir +os.sep+'SELshortlist.txt', 'w') as f:
2037 f.write(sels)
2038 print("SEL short list collected and stored in " + fileDir + os.sep+ "SELshortlist.txt")
2039 output['fileLoc'] = fileDir+os.sep+'SELshortlist.txt'
2040 except Exception as e:
2041 print("Failed to write SEL short list to file system.")
2042 errorInfo += "Error writing SEL short list to the file. Exception: {eInfo}\n".format(eInfo=e)
2043
2044 output['errors'] = errorInfo
2045 return output
2046
2047def csdParsedSels(host, args, session, fileDir):
2048 """
2049 Collects the BMC log entries, retrying if necessary
2050
2051 @param host: string, the hostname or IP address of the bmc
2052 @param args: contains additional arguments used by the collectServiceData sub command
2053 @param session: the active session to use
2054 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
2055 @param fileDir: string representation of the path to use for putting files created
2056 """
2057 errorInfo = "===========SEL Parsed List =============\n"
2058 selsCollected = False
2059 output={}
2060 try:
2061 d = vars(args)
2062 d['json'] = True
2063 d['fullEsel'] = True
2064 except Exception as e:
2065 errorInfo += "Failed to set the json flag to True \n Exception: {eInfo}\n".format(eInfo=e)
2066
2067 try:
2068 for i in range(3):
2069 parsedfullsels = json.loads(selPrint(host,args,session))
2070 if 'numAlerts' in parsedfullsels:
2071 selsCollected = True
2072 break
2073 else:
2074 errorInfo += parsedfullsels + '\n'
2075 except Exception as e:
2076 errorInfo += "Parsed full SELs collection exception: {eInfo}\n".format(eInfo=e)
2077
2078 if selsCollected:
2079 try:
2080 sortedSELs = sortSELs(parsedfullsels)
2081 with open(fileDir +os.sep+'parsedSELs.txt', 'w') as f:
2082 for log in sortedSELs[0]:
2083 esel = ""
2084 parsedfullsels[sortedSELs[1][str(log)]]['timestamp'] = datetime.datetime.fromtimestamp(int(parsedfullsels[sortedSELs[1][str(log)]]['timestamp']/1000)).strftime("%Y-%m-%d %H:%M:%S")
2085 if ('raweSEL' in parsedfullsels[sortedSELs[1][str(log)]] and args.devdebug):
2086 esel = parsedfullsels[sortedSELs[1][str(log)]]['raweSEL']
2087 del parsedfullsels[sortedSELs[1][str(log)]]['raweSEL']
2088 f.write(json.dumps(parsedfullsels[sortedSELs[1][str(log)]],sort_keys=True, indent=4, separators=(',', ': ')))
2089 if(args.devdebug and esel != ""):
2090 f.write(parseESEL(args, esel))
2091 print("Parsed SELs collected and stored in " + fileDir + os.sep+ "parsedSELs.txt")
2092 output['fileLoc'] = fileDir+os.sep+'parsedSELs.txt'
2093 except Exception as e:
2094 print("Failed to write fully parsed SELs to file system.")
2095 errorInfo += "Error writing fully parsed SELs to the file. Exception: {eInfo}\n".format(eInfo=e)
2096
2097 output['errors'] = errorInfo
2098 return output
2099
2100def csdFullEnumeration(host, args, session, fileDir):
2101 """
2102 Collects a full enumeration of /xyz/openbmc_project/, retrying if necessary
2103
2104 @param host: string, the hostname or IP address of the bmc
2105 @param args: contains additional arguments used by the collectServiceData sub command
2106 @param session: the active session to use
2107 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
2108 @param fileDir: string representation of the path to use for putting files created
2109 """
2110 errorInfo = "===========BMC Full Enumeration =============\n"
2111 bmcFullCollected = False
2112 output={}
2113 try:
2114 d = vars(args)
2115 d['json'] = True
2116 except Exception as e:
2117 errorInfo += "Failed to set the json flag to False \n Exception: {eInfo}\n".format(eInfo=e)
2118 try:
2119 print("Attempting to get a full BMC enumeration")
2120 url="https://"+host+"/xyz/openbmc_project/enumerate"
2121 httpHeader = {'Content-Type':'application/json'}
2122 for i in range(3):
2123 try:
2124 bmcRes = session.get(url, headers=jsonHeader, verify=False, timeout=180)
2125 if bmcRes.status_code == 200:
2126 bmcFullCollected = True
2127 fullEnumeration = bmcRes.json()
2128 break
2129 else:
2130 errorInfo += bmcRes.text
2131 except(requests.exceptions.Timeout):
2132 errorInfo+=json.dumps( connectionErrHandler(args.json, "Timeout", None), sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n'
2133 except(requests.exceptions.ConnectionError) as err:
2134 errorInfo += json.dumps(connectionErrHandler(args.json, "ConnectionError", err), sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n'
2135 except Exception as e:
2136 errorInfo += "RAW BMC data collection exception: {eInfo}\n".format(eInfo=e)
2137
2138 if bmcFullCollected:
2139 try:
2140 with open(fileDir +os.sep+'bmcFullRaw.txt', 'w') as f:
2141 f.write(json.dumps(fullEnumeration, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) + '\n')
2142 print("RAW BMC data collected and saved into " + fileDir + os.sep+ "bmcFullRaw.txt")
2143 output['fileLoc'] = fileDir+os.sep+'bmcFullRaw.txt'
2144 except Exception as e:
2145 print("Failed to write RAW BMC data to file system.")
2146 errorInfo += "Error writing RAW BMC data collection to the file. Exception: {eInfo}\n".format(eInfo=e)
2147
2148 output['errors'] = errorInfo
2149 return output
2150
2151def csdCollectAllDumps(host, args, session, fileDir):
2152 """
2153 Collects all of the bmc dump files and stores them in fileDir
2154
2155 @param host: string, the hostname or IP address of the bmc
2156 @param args: contains additional arguments used by the collectServiceData sub command
2157 @param session: the active session to use
2158 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
2159 @param fileDir: string representation of the path to use for putting files created
2160 """
2161
2162 errorInfo = "===========BMC Dump Collection =============\n"
2163 dumpListCollected = False
2164 output={}
2165 dumpList = {}
2166 try:
2167 d = vars(args)
2168 d['json'] = True
2169 d['dumpSaveLoc'] = fileDir
2170 except Exception as e:
2171 errorInfo += "Failed to set the json flag to True, or failed to set the dumpSave Location \n Exception: {eInfo}\n".format(eInfo=e)
2172
2173 print('Collecting bmc dump files')
2174
2175 try:
2176 for i in range(3):
2177 dumpResp = bmcDumpList(host, args, session)
2178 if 'message' in dumpResp:
2179 if 'ok' in dumpResp['message'].lower():
2180 dumpList = dumpResp['data']
2181 dumpListCollected = True
2182 break
2183 else:
2184 errorInfo += "Status was not OK when retrieving the list of dumps available. \n Response: \n{resp}\n".format(resp=dumpResp)
2185 else:
2186 errorInfo += "Invalid response received from the BMC while retrieving the list of dumps available.\n {resp}\n".format(resp=dumpResp)
2187 except Exception as e:
2188 errorInfo += "BMC dump list exception: {eInfo}\n".format(eInfo=e)
2189
2190 if dumpListCollected:
2191 output['fileList'] = []
2192 for dump in dumpList:
2193 try:
2194 if '/xyz/openbmc_project/dump/internal/manager' not in dump:
2195 d['dumpNum'] = int(dump.strip().split('/')[-1])
2196 print('retrieving dump file ' + str(d['dumpNum']))
2197 filename = bmcDumpRetrieve(host, args, session).split('Saved as ')[-1]
2198 output['fileList'].append(filename)
2199 except Exception as e:
2200 print("Unable to collect dump: {dumpInfo}".format(dumpInfo=dump))
2201 errorInfo += "Exception collecting a bmc dump {dumpInfo}\n {eInfo}\n".format(dumpInfo=dump, eInfo=e)
2202 output['errors'] = errorInfo
2203 return output
Justin Thalere412dc22018-01-12 16:28:24 -06002204
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002205def collectServiceData(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06002206 """
2207 Collects all data needed for service from the BMC
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002208
Justin Thalere412dc22018-01-12 16:28:24 -06002209 @param host: string, the hostname or IP address of the bmc
2210 @param args: contains additional arguments used by the collectServiceData sub command
2211 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002212 @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 -06002213 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002214
Justin Thaler22b1bb52018-03-15 13:31:32 -05002215 global toolVersion
Justin Thaler666cf342019-01-23 14:44:27 -06002216 filelist = []
2217 errorInfo = ""
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002218
Justin Thaler666cf342019-01-23 14:44:27 -06002219 #get current number of bmc dumps and create a new bmc dump
2220 dumpInitdata = csdDumpInitiate(host, args, session)
2221 dumpcount = dumpInitdata['dumpcount']
2222 errorInfo += dumpInitdata['errors']
2223 #create the directory to put files
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002224 try:
2225 args.silent = True
Justin Thalercf1deae2018-05-25 19:35:21 -05002226 myDir = tempfile.gettempdir()+os.sep + host + "--" + datetime.datetime.now().strftime("%Y-%m-%d_%H.%M.%S")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002227 os.makedirs(myDir)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002228
Justin Thaler666cf342019-01-23 14:44:27 -06002229 except Exception as e:
2230 print('Unable to create the temporary directory for data collection. Ensure sufficient privileges to create temporary directory. Aborting.')
2231 return("Python exception: {eInfo}".format(eInfo = e))
2232
2233 #Collect Inventory
2234 inventoryData = csdInventory(host, args, session, myDir)
2235 if 'fileLoc' in inventoryData:
2236 filelist.append(inventoryData['fileLoc'])
2237 errorInfo += inventoryData['errors']
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002238 #Read all the sensor and OCC status
Justin Thaler666cf342019-01-23 14:44:27 -06002239 sensorData = csdSensors(host,args,session,myDir)
2240 if 'fileLoc' in sensorData:
2241 filelist.append(sensorData['fileLoc'])
2242 errorInfo += sensorData['errors']
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002243 #Collect all of the LEDs status
Justin Thaler666cf342019-01-23 14:44:27 -06002244 ledStatus = csdLEDs(host, args, session, myDir)
2245 if 'fileLoc' in ledStatus:
2246 filelist.append(ledStatus['fileLoc'])
2247 errorInfo += ledStatus['errors']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002248
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002249 #Collect the bmc logs
Justin Thaler666cf342019-01-23 14:44:27 -06002250 selShort = csdSelShortList(host, args, session, myDir)
2251 if 'fileLoc' in selShort:
2252 filelist.append(selShort['fileLoc'])
2253 errorInfo += selShort['errors']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002254
Justin Thaler666cf342019-01-23 14:44:27 -06002255 parsedSELs = csdParsedSels(host, args, session, myDir)
2256 if 'fileLoc' in parsedSELs:
2257 filelist.append(parsedSELs['fileLoc'])
2258 errorInfo += parsedSELs['errors']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002259
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002260 #collect RAW bmc enumeration
Justin Thaler666cf342019-01-23 14:44:27 -06002261 bmcRaw = csdFullEnumeration(host, args, session, myDir)
2262 if 'fileLoc' in bmcRaw:
2263 filelist.append(bmcRaw['fileLoc'])
2264 errorInfo += bmcRaw['errors']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002265
Justin Thaler666cf342019-01-23 14:44:27 -06002266 #wait for new dump to finish being created
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002267 waitingForNewDump = True
2268 count = 0;
Justin Thaler666cf342019-01-23 14:44:27 -06002269 print("Waiting for new BMC dump to finish being created.")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002270 while(waitingForNewDump):
Justin Thaler666cf342019-01-23 14:44:27 -06002271 dumpList = bmcDumpList(host, args, session)['data']
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002272 if len(dumpList) > dumpcount:
2273 waitingForNewDump = False
2274 break;
2275 elif(count>30):
2276 print("Timed out waiting for bmc to make a new dump file. Dump space may be full.")
2277 break;
2278 else:
2279 time.sleep(2)
2280 count += 1
Justin Thaler666cf342019-01-23 14:44:27 -06002281
2282 #collect all of the dump files
2283 getBMCDumps = csdCollectAllDumps(host, args, session, myDir)
2284 if 'fileList' in getBMCDumps:
2285 filelist+= getBMCDumps['fileList']
2286 errorInfo += getBMCDumps['errors']
2287
2288 #write the runtime errors to a file
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002289 try:
Justin Thaler666cf342019-01-23 14:44:27 -06002290 with open(myDir +os.sep+'openbmctoolRuntimeErrors.txt', 'w') as f:
2291 f.write(errorInfo)
2292 print("OpenBMC tool runtime errors collected and stored in " + myDir + os.sep+ "openbmctoolRuntimeErrors.txt")
2293 filelist.append(myDir+os.sep+'openbmctoolRuntimeErrors.txt')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002294 except Exception as e:
Justin Thaler666cf342019-01-23 14:44:27 -06002295 print("Failed to write OpenBMC tool runtime errors to file system.")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002296
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002297 #create the zip file
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002298 try:
Justin Thalercf1deae2018-05-25 19:35:21 -05002299 filename = myDir.split(tempfile.gettempdir()+os.sep)[-1] + "_" + toolVersion + '_openbmc.zip'
Justin Thaler666cf342019-01-23 14:44:27 -06002300 zf = zipfile.ZipFile(myDir+os.sep + filename, 'w')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002301 for myfile in filelist:
2302 zf.write(myfile, os.path.basename(myfile))
2303 zf.close()
Justin Thaler666cf342019-01-23 14:44:27 -06002304 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 -06002305 except Exception as e:
2306 print("Failed to create zip file with collected information")
Justin Thaler666cf342019-01-23 14:44:27 -06002307 return "data collection finished"
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002308
Justin Thalere412dc22018-01-12 16:28:24 -06002309
2310def healthCheck(host, args, session):
2311 """
2312 runs a health check on the platform
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002313
Justin Thalere412dc22018-01-12 16:28:24 -06002314 @param host: string, the hostname or IP address of the bmc
2315 @param args: contains additional arguments used by the bmc sub command
2316 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002317 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
2318 """
Justin Thalere412dc22018-01-12 16:28:24 -06002319 #check fru status and get as json to easily work through
2320 d = vars(args)
2321 useJson = d['json']
2322 d['json'] = True
2323 d['verbose']= False
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002324
Justin Thalere412dc22018-01-12 16:28:24 -06002325 frus = json.loads(fruStatus(host, args, session))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002326
Justin Thalere412dc22018-01-12 16:28:24 -06002327 hwStatus= "OK"
2328 performanceStatus = "OK"
2329 for key in frus:
2330 if frus[key]["Functional"] == "No" and frus[key]["Present"] == "Yes":
2331 hwStatus= "Degraded"
Justin Thalerfb9c81c2018-07-16 11:14:37 -05002332 if("power_supply" in key or "powersupply" in key):
2333 gpuCount =0
2334 for comp in frus:
Justin Thalere412dc22018-01-12 16:28:24 -06002335 if "gv100card" in comp:
2336 gpuCount +=1
2337 if gpuCount > 4:
2338 hwStatus = "Critical"
2339 performanceStatus="Degraded"
2340 break;
2341 elif("fan" in key):
2342 hwStatus = "Degraded"
2343 else:
2344 performanceStatus = "Degraded"
2345 if useJson:
2346 output = {"Hardware Status": hwStatus, "Performance": performanceStatus}
2347 output = json.dumps(output, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False)
2348 else:
2349 output = ("Hardware Status: " + hwStatus +
2350 "\nPerformance: " +performanceStatus )
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002351
2352
Justin Thalere412dc22018-01-12 16:28:24 -06002353 #SW407886: Clear the duplicate entries
2354 #collect the dups
2355 d['devdebug'] = False
2356 sels = json.loads(selPrint(host, args, session))
2357 logNums2Clr = []
2358 oldestLogNum={"logNum": "bogus" ,"key" : ""}
2359 count = 0
2360 if sels['numAlerts'] > 0:
2361 for key in sels:
2362 if "numAlerts" in key:
2363 continue
2364 try:
2365 if "slave@00:00/00:00:00:06/sbefifo1-dev0/occ1-dev0" in sels[key]['Message']:
2366 count += 1
2367 if count > 1:
2368 #preserve first occurrence
2369 if sels[key]['timestamp'] < sels[oldestLogNum['key']]['timestamp']:
2370 oldestLogNum['key']=key
2371 oldestLogNum['logNum'] = sels[key]['logNum']
2372 else:
2373 oldestLogNum['key']=key
2374 oldestLogNum['logNum'] = sels[key]['logNum']
2375 logNums2Clr.append(sels[key]['logNum'])
2376 except KeyError:
2377 continue
2378 if(count >0):
2379 logNums2Clr.remove(oldestLogNum['logNum'])
2380 #delete the dups
2381 if count >1:
Justin Thalere412dc22018-01-12 16:28:24 -06002382 data = "{\"data\": [] }"
2383 for logNum in logNums2Clr:
2384 url = "https://"+ host+ "/xyz/openbmc_project/logging/entry/"+logNum+"/action/Delete"
2385 try:
Justin Thaler27197622019-01-23 14:42:11 -06002386 session.post(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002387 except(requests.exceptions.Timeout):
2388 deleteFailed = True
2389 except(requests.exceptions.ConnectionError) as err:
2390 deleteFailed = True
2391 #End of defect resolve code
2392 d['json'] = useJson
2393 return output
2394
2395
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002396
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002397def bmc(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06002398 """
2399 handles various bmc level commands, currently bmc rebooting
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002400
Justin Thalere412dc22018-01-12 16:28:24 -06002401 @param host: string, the hostname or IP address of the bmc
2402 @param args: contains additional arguments used by the bmc sub command
2403 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002404 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
2405 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002406 if(args.type is not None):
2407 return bmcReset(host, args, session)
Justin Thalere412dc22018-01-12 16:28:24 -06002408 if(args.info):
2409 return "Not implemented at this time"
2410
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002411
Justin Thalere412dc22018-01-12 16:28:24 -06002412
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002413def bmcReset(host, args, session):
Justin Thalere412dc22018-01-12 16:28:24 -06002414 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002415 controls resetting the bmc. warm reset reboots the bmc, cold reset removes the configuration and reboots.
2416
Justin Thalere412dc22018-01-12 16:28:24 -06002417 @param host: string, the hostname or IP address of the bmc
2418 @param args: contains additional arguments used by the bmcReset sub command
2419 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002420 @param args.json: boolean, if this flag is set to true, the output will be provided in json format for programmatic consumption
2421 """
Justin Thaler22b1bb52018-03-15 13:31:32 -05002422 if checkFWactivation(host, args, session):
2423 return ("BMC reset control disabled during firmware activation")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002424 if(args.type == "warm"):
2425 print("\nAttempting to reboot the BMC...:")
2426 url="https://"+host+"/xyz/openbmc_project/state/bmc0/attr/RequestedBMCTransition"
Justin Thalere412dc22018-01-12 16:28:24 -06002427 data = '{"data":"xyz.openbmc_project.State.BMC.Transition.Reboot"}'
Justin Thaler27197622019-01-23 14:42:11 -06002428 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002429 return res.text
2430 elif(args.type =="cold"):
Justin Thalere412dc22018-01-12 16:28:24 -06002431 print("\nAttempting to reboot the BMC...:")
2432 url="https://"+host+"/xyz/openbmc_project/state/bmc0/attr/RequestedBMCTransition"
Justin Thalere412dc22018-01-12 16:28:24 -06002433 data = '{"data":"xyz.openbmc_project.State.BMC.Transition.Reboot"}'
Justin Thaler27197622019-01-23 14:42:11 -06002434 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002435 return res.text
Justin Thalerf9aee3e2017-12-05 12:11:09 -06002436 else:
2437 return "invalid command"
Justin Thalere412dc22018-01-12 16:28:24 -06002438
2439def gardClear(host, args, session):
2440 """
2441 clears the gard records from the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002442
Justin Thalere412dc22018-01-12 16:28:24 -06002443 @param host: string, the hostname or IP address of the bmc
2444 @param args: contains additional arguments used by the gardClear sub command
2445 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002446 """
Justin Thalere412dc22018-01-12 16:28:24 -06002447 url="https://"+host+"/org/open_power/control/gard/action/Reset"
Justin Thalere412dc22018-01-12 16:28:24 -06002448 data = '{"data":[]}'
2449 try:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002450
Justin Thaler27197622019-01-23 14:42:11 -06002451 res = session.post(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002452 if res.status_code == 404:
2453 return "Command not supported by this firmware version"
2454 else:
2455 return res.text
2456 except(requests.exceptions.Timeout):
2457 return connectionErrHandler(args.json, "Timeout", None)
2458 except(requests.exceptions.ConnectionError) as err:
2459 return connectionErrHandler(args.json, "ConnectionError", err)
2460
2461def activateFWImage(host, args, session):
2462 """
2463 activates a firmware image on the bmc
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002464
Justin Thalere412dc22018-01-12 16:28:24 -06002465 @param host: string, the hostname or IP address of the bmc
2466 @param args: contains additional arguments used by the fwflash sub command
2467 @param session: the active session to use
2468 @param fwID: the unique ID of the fw image to activate
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002469 """
Justin Thalere412dc22018-01-12 16:28:24 -06002470 fwID = args.imageID
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002471
Justin Thalere412dc22018-01-12 16:28:24 -06002472 #determine the existing versions
Justin Thalere412dc22018-01-12 16:28:24 -06002473 url="https://"+host+"/xyz/openbmc_project/software/enumerate"
2474 try:
Justin Thaler27197622019-01-23 14:42:11 -06002475 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002476 except(requests.exceptions.Timeout):
2477 return connectionErrHandler(args.json, "Timeout", None)
2478 except(requests.exceptions.ConnectionError) as err:
2479 return connectionErrHandler(args.json, "ConnectionError", err)
2480 existingSoftware = json.loads(resp.text)['data']
2481 altVersionID = ''
2482 versionType = ''
2483 imageKey = '/xyz/openbmc_project/software/'+fwID
2484 if imageKey in existingSoftware:
2485 versionType = existingSoftware[imageKey]['Purpose']
2486 for key in existingSoftware:
2487 if imageKey == key:
2488 continue
2489 if 'Purpose' in existingSoftware[key]:
2490 if versionType == existingSoftware[key]['Purpose']:
2491 altVersionID = key.split('/')[-1]
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002492
2493
2494
2495
Justin Thalere412dc22018-01-12 16:28:24 -06002496 url="https://"+host+"/xyz/openbmc_project/software/"+ fwID + "/attr/Priority"
2497 url1="https://"+host+"/xyz/openbmc_project/software/"+ altVersionID + "/attr/Priority"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002498 data = "{\"data\": 0}"
Justin Thalere412dc22018-01-12 16:28:24 -06002499 data1 = "{\"data\": 1 }"
2500 try:
Justin Thaler27197622019-01-23 14:42:11 -06002501 resp = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
2502 resp1 = session.put(url1, headers=jsonHeader, data=data1, verify=False, timeout=baseTimeout)
Justin Thalere412dc22018-01-12 16:28:24 -06002503 except(requests.exceptions.Timeout):
2504 return connectionErrHandler(args.json, "Timeout", None)
2505 except(requests.exceptions.ConnectionError) as err:
2506 return connectionErrHandler(args.json, "ConnectionError", err)
2507 if(not args.json):
2508 if resp.status_code == 200 and resp1.status_code == 200:
Justin Thaler22b1bb52018-03-15 13:31:32 -05002509 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 -06002510 else:
2511 return "Firmware activation failed."
2512 else:
2513 return resp.text + resp1.text
Justin Thaler22b1bb52018-03-15 13:31:32 -05002514
2515def activateStatus(host, args, session):
2516 if checkFWactivation(host, args, session):
2517 return("Firmware is currently being activated. Do not reboot the BMC or start the Host OS")
2518 else:
2519 return("No firmware activations are pending")
2520
2521def extractFWimage(path, imageType):
2522 """
2523 extracts the bmc image and returns information about the package
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002524
Justin Thaler22b1bb52018-03-15 13:31:32 -05002525 @param path: the path and file name of the firmware image
2526 @param imageType: The type of image the user is trying to flash. Host or BMC
2527 @return: the image id associated with the package. returns an empty string on error.
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002528 """
Justin Thaler22b1bb52018-03-15 13:31:32 -05002529 f = tempfile.TemporaryFile()
2530 tmpDir = tempfile.gettempdir()
2531 newImageID = ""
2532 if os.path.exists(path):
2533 try:
2534 imageFile = tarfile.open(path,'r')
2535 contents = imageFile.getmembers()
2536 for tf in contents:
2537 if 'MANIFEST' in tf.name:
2538 imageFile.extract(tf.name, path=tmpDir)
2539 with open(tempfile.gettempdir() +os.sep+ tf.name, 'r') as imageInfo:
2540 for line in imageInfo:
2541 if 'purpose' in line:
2542 purpose = line.split('=')[1]
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002543 if imageType not in purpose.split('.')[-1]:
Justin Thaler22b1bb52018-03-15 13:31:32 -05002544 print('The specified image is not for ' + imageType)
2545 print('Please try again with the image for ' + imageType)
2546 return ""
2547 if 'version' == line.split('=')[0]:
2548 version = line.split('=')[1].strip().encode('utf-8')
2549 m = hashlib.sha512()
2550 m.update(version)
2551 newImageID = m.hexdigest()[:8]
2552 break
2553 try:
2554 os.remove(tempfile.gettempdir() +os.sep+ tf.name)
2555 except OSError:
2556 pass
2557 return newImageID
2558 except tarfile.ExtractError as e:
2559 print('Unable to extract information from the firmware file.')
2560 print('Ensure you have write access to the directory: ' + tmpDir)
2561 return newImageID
2562 except tarfile.TarError as e:
2563 print('This is not a valid firmware file.')
2564 return newImageID
2565 print("This is not a valid firmware file.")
2566 return newImageID
2567 else:
2568 print('The filename and path provided are not valid.')
2569 return newImageID
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002570
Justin Thaler22b1bb52018-03-15 13:31:32 -05002571def getAllFWImageIDs(fwInvDict):
2572 """
2573 gets a list of all the firmware image IDs
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002574
Justin Thaler22b1bb52018-03-15 13:31:32 -05002575 @param fwInvDict: the dictionary to search for FW image IDs
2576 @return: list containing string representation of the found image ids
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002577 """
Justin Thaler22b1bb52018-03-15 13:31:32 -05002578 idList = []
2579 for key in fwInvDict:
2580 if 'Version' in fwInvDict[key]:
2581 idList.append(key.split('/')[-1])
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002582 return idList
2583
Justin Thalere412dc22018-01-12 16:28:24 -06002584def fwFlash(host, args, session):
2585 """
2586 updates the bmc firmware and pnor firmware
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002587
Justin Thalere412dc22018-01-12 16:28:24 -06002588 @param host: string, the hostname or IP address of the bmc
2589 @param args: contains additional arguments used by the fwflash sub command
2590 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002591 """
Justin Thaler22b1bb52018-03-15 13:31:32 -05002592 d = vars(args)
Justin Thalere412dc22018-01-12 16:28:24 -06002593 if(args.type == 'bmc'):
2594 purp = 'BMC'
2595 else:
2596 purp = 'Host'
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002597
2598 #check power state of the machine. No concurrent FW updates allowed
Justin Thaler22b1bb52018-03-15 13:31:32 -05002599 d['powcmd'] = 'status'
2600 powerstate = chassisPower(host, args, session)
2601 if 'Chassis Power State: On' in powerstate:
2602 return("Aborting firmware update. Host is powered on. Please turn off the host and try again.")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002603
Justin Thaler22b1bb52018-03-15 13:31:32 -05002604 #determine the existing images on the bmc
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 oldsoftware = json.loads(resp.text)['data']
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002613
Justin Thaler22b1bb52018-03-15 13:31:32 -05002614 #Extract the tar and get information from the manifest file
2615 newversionID = extractFWimage(args.fileloc, purp)
2616 if newversionID == "":
2617 return "Unable to verify FW image."
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002618
2619
Justin Thaler22b1bb52018-03-15 13:31:32 -05002620 #check if the new image is already on the bmc
2621 if newversionID not in getAllFWImageIDs(oldsoftware):
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002622
Justin Thaler22b1bb52018-03-15 13:31:32 -05002623 #upload the file
2624 httpHeader = {'Content-Type':'application/octet-stream'}
Matt Spinler220c3c42019-01-04 15:09:29 -06002625 httpHeader.update(xAuthHeader)
Justin Thaler22b1bb52018-03-15 13:31:32 -05002626 url="https://"+host+"/upload/image"
2627 data=open(args.fileloc,'rb').read()
2628 print("Uploading file to BMC")
Justin Thalere412dc22018-01-12 16:28:24 -06002629 try:
Justin Thaler22b1bb52018-03-15 13:31:32 -05002630 resp = session.post(url, headers=httpHeader, data=data, verify=False)
Justin Thalere412dc22018-01-12 16:28:24 -06002631 except(requests.exceptions.Timeout):
2632 return connectionErrHandler(args.json, "Timeout", None)
2633 except(requests.exceptions.ConnectionError) as err:
2634 return connectionErrHandler(args.json, "ConnectionError", err)
Justin Thaler22b1bb52018-03-15 13:31:32 -05002635 if resp.status_code != 200:
2636 return "Failed to upload the file to the bmc"
Justin Thalere412dc22018-01-12 16:28:24 -06002637 else:
Justin Thaler22b1bb52018-03-15 13:31:32 -05002638 print("Upload complete.")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002639
Justin Thaler22b1bb52018-03-15 13:31:32 -05002640 #verify bmc processed the image
2641 software ={}
2642 for i in range(0, 5):
Justin Thaler22b1bb52018-03-15 13:31:32 -05002643 url="https://"+host+"/xyz/openbmc_project/software/enumerate"
2644 try:
Justin Thaler27197622019-01-23 14:42:11 -06002645 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thaler22b1bb52018-03-15 13:31:32 -05002646 except(requests.exceptions.Timeout):
2647 return connectionErrHandler(args.json, "Timeout", None)
2648 except(requests.exceptions.ConnectionError) as err:
2649 return connectionErrHandler(args.json, "ConnectionError", err)
2650 software = json.loads(resp.text)['data']
2651 #check if bmc is done processing the new image
2652 if (newversionID in getAllFWImageIDs(software)):
Justin Thalere412dc22018-01-12 16:28:24 -06002653 break
Justin Thaler22b1bb52018-03-15 13:31:32 -05002654 else:
2655 time.sleep(15)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002656
Justin Thaler22b1bb52018-03-15 13:31:32 -05002657 #activate the new image
2658 print("Activating new image: "+newversionID)
2659 url="https://"+host+"/xyz/openbmc_project/software/"+ newversionID + "/attr/RequestedActivation"
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002660 data = '{"data":"xyz.openbmc_project.Software.Activation.RequestedActivations.Active"}'
Justin Thaler22b1bb52018-03-15 13:31:32 -05002661 try:
Justin Thaler27197622019-01-23 14:42:11 -06002662 resp = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Justin Thaler22b1bb52018-03-15 13:31:32 -05002663 except(requests.exceptions.Timeout):
2664 return connectionErrHandler(args.json, "Timeout", None)
2665 except(requests.exceptions.ConnectionError) as err:
2666 return connectionErrHandler(args.json, "ConnectionError", err)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002667
Justin Thaler22b1bb52018-03-15 13:31:32 -05002668 #wait for the activation to complete, timeout after ~1 hour
2669 i=0
2670 while i < 360:
2671 url="https://"+host+"/xyz/openbmc_project/software/"+ newversionID
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002672 data = '{"data":"xyz.openbmc_project.Software.Activation.RequestedActivations.Active"}'
Justin Thaler22b1bb52018-03-15 13:31:32 -05002673 try:
Justin Thaler27197622019-01-23 14:42:11 -06002674 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thaler22b1bb52018-03-15 13:31:32 -05002675 except(requests.exceptions.Timeout):
2676 return connectionErrHandler(args.json, "Timeout", None)
2677 except(requests.exceptions.ConnectionError) as err:
2678 return connectionErrHandler(args.json, "ConnectionError", err)
2679 fwInfo = json.loads(resp.text)['data']
2680 if 'Activating' not in fwInfo['Activation'] and 'Activating' not in fwInfo['RequestedActivation']:
2681 print('')
2682 break
2683 else:
2684 sys.stdout.write('.')
2685 sys.stdout.flush()
2686 time.sleep(10) #check every 10 seconds
2687 return "Firmware flash and activation completed. Please reboot the bmc and then boot the host OS for the changes to take effect. "
2688 else:
2689 print("This image has been found on the bmc. Activating image: " + newversionID)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002690
Justin Thaler22b1bb52018-03-15 13:31:32 -05002691 d['imageID'] = newversionID
2692 return activateFWImage(host, args, session)
Justin Thalere412dc22018-01-12 16:28:24 -06002693
Justin Thaler3d71d402018-07-24 14:35:39 -05002694def getFWInventoryAttributes(rawFWInvItem, ID):
2695 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002696 gets and lists all of the firmware in the system.
2697
Justin Thaler3d71d402018-07-24 14:35:39 -05002698 @return: returns a dictionary containing the image attributes
2699 """
2700 reqActivation = rawFWInvItem["RequestedActivation"].split('.')[-1]
2701 pendingActivation = ""
2702 if reqActivation == "None":
2703 pendingActivation = "No"
2704 else:
2705 pendingActivation = "Yes"
2706 firmwareAttr = {ID: {
2707 "Purpose": rawFWInvItem["Purpose"].split('.')[-1],
2708 "Version": rawFWInvItem["Version"],
2709 "RequestedActivation": pendingActivation,
2710 "ID": ID}}
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002711
Justin Thaler3d71d402018-07-24 14:35:39 -05002712 if "ExtendedVersion" in rawFWInvItem:
2713 firmwareAttr[ID]['ExtendedVersion'] = rawFWInvItem['ExtendedVersion'].split(',')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002714 else:
Justin Thaler3d71d402018-07-24 14:35:39 -05002715 firmwareAttr[ID]['ExtendedVersion'] = ""
2716 return firmwareAttr
2717
2718def parseFWdata(firmwareDict):
2719 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002720 creates a dictionary with parsed firmware data
2721
Justin Thaler3d71d402018-07-24 14:35:39 -05002722 @return: returns a dictionary containing the image attributes
2723 """
2724 firmwareInfoDict = {"Functional": {}, "Activated":{}, "NeedsActivated":{}}
2725 for key in firmwareDict['data']:
2726 #check for valid endpoint
2727 if "Purpose" in firmwareDict['data'][key]:
2728 id = key.split('/')[-1]
2729 if firmwareDict['data'][key]['Activation'].split('.')[-1] == "Active":
2730 fwActivated = True
2731 else:
2732 fwActivated = False
Justin Thalercb68e062019-03-26 19:04:52 -05002733 if 'Priority' in firmwareDict['data'][key]:
2734 if firmwareDict['data'][key]['Priority'] == 0:
2735 firmwareInfoDict['Functional'].update(getFWInventoryAttributes(firmwareDict['data'][key], id))
2736 elif firmwareDict['data'][key]['Priority'] >= 0 and fwActivated:
2737 firmwareInfoDict['Activated'].update(getFWInventoryAttributes(firmwareDict['data'][key], id))
2738 else:
2739 firmwareInfoDict['NeedsActivated'].update(getFWInventoryAttributes(firmwareDict['data'][key], id))
Justin Thaler3d71d402018-07-24 14:35:39 -05002740 else:
Justin Thalercb68e062019-03-26 19:04:52 -05002741 firmwareInfoDict['NeedsActivated'].update(getFWInventoryAttributes(firmwareDict['data'][key], id))
Justin Thaler3d71d402018-07-24 14:35:39 -05002742 emptySections = []
2743 for key in firmwareInfoDict:
2744 if len(firmwareInfoDict[key])<=0:
2745 emptySections.append(key)
2746 for key in emptySections:
2747 del firmwareInfoDict[key]
2748 return firmwareInfoDict
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002749
Justin Thaler3d71d402018-07-24 14:35:39 -05002750def displayFWInvenory(firmwareInfoDict, args):
2751 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002752 gets and lists all of the firmware in the system.
2753
Justin Thaler3d71d402018-07-24 14:35:39 -05002754 @return: returns a string containing all of the firmware information
2755 """
2756 output = ""
2757 if not args.json:
2758 for key in firmwareInfoDict:
2759 for subkey in firmwareInfoDict[key]:
2760 firmwareInfoDict[key][subkey]['ExtendedVersion'] = str(firmwareInfoDict[key][subkey]['ExtendedVersion'])
2761 if not args.verbose:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002762 output = "---Running Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002763 colNames = ["Purpose", "Version", "ID"]
2764 keylist = ["Purpose", "Version", "ID"]
2765 output += tableDisplay(keylist, colNames, firmwareInfoDict["Functional"])
2766 if "Activated" in firmwareInfoDict:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002767 output += "\n---Available Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002768 output += tableDisplay(keylist, colNames, firmwareInfoDict["Activated"])
2769 if "NeedsActivated" in firmwareInfoDict:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002770 output += "\n---Needs Activated Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002771 output += tableDisplay(keylist, colNames, firmwareInfoDict["NeedsActivated"])
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002772
Justin Thaler3d71d402018-07-24 14:35:39 -05002773 else:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002774 output = "---Running Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002775 colNames = ["Purpose", "Version", "ID", "Pending Activation", "Extended Version"]
2776 keylist = ["Purpose", "Version", "ID", "RequestedActivation", "ExtendedVersion"]
2777 output += tableDisplay(keylist, colNames, firmwareInfoDict["Functional"])
2778 if "Activated" in firmwareInfoDict:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002779 output += "\n---Available Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002780 output += tableDisplay(keylist, colNames, firmwareInfoDict["Activated"])
2781 if "NeedsActivated" in firmwareInfoDict:
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002782 output += "\n---Needs Activated Images---\n"
Justin Thaler3d71d402018-07-24 14:35:39 -05002783 output += tableDisplay(keylist, colNames, firmwareInfoDict["NeedsActivated"])
2784 return output
2785 else:
2786 return str(json.dumps(firmwareInfoDict, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False))
2787
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002788def firmwareList(host, args, session):
Justin Thaler3d71d402018-07-24 14:35:39 -05002789 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002790 gets and lists all of the firmware in the system.
2791
Justin Thaler3d71d402018-07-24 14:35:39 -05002792 @return: returns a string containing all of the firmware information
2793 """
Justin Thaler3d71d402018-07-24 14:35:39 -05002794 url="https://{hostname}/xyz/openbmc_project/software/enumerate".format(hostname=host)
2795 try:
Justin Thaler27197622019-01-23 14:42:11 -06002796 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Justin Thaler3d71d402018-07-24 14:35:39 -05002797 except(requests.exceptions.Timeout):
2798 return(connectionErrHandler(args.json, "Timeout", None))
2799 firmwareDict = json.loads(res.text)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002800
Justin Thaler3d71d402018-07-24 14:35:39 -05002801 #sort the received information
2802 firmwareInfoDict = parseFWdata(firmwareDict)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002803
Justin Thaler3d71d402018-07-24 14:35:39 -05002804 #display the information
2805 return displayFWInvenory(firmwareInfoDict, args)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002806
2807
Adriana Kobylak5af2fad2018-11-08 12:33:43 -06002808def deleteFWVersion(host, args, session):
2809 """
2810 deletes a firmware version on the BMC
2811
2812 @param host: string, the hostname or IP address of the BMC
2813 @param args: contains additional arguments used by the fwflash sub command
2814 @param session: the active session to use
2815 @param fwID: the unique ID of the fw version to delete
2816 """
2817 fwID = args.versionID
2818
2819 print("Deleting version: "+fwID)
2820 url="https://"+host+"/xyz/openbmc_project/software/"+ fwID + "/action/Delete"
Adriana Kobylak5af2fad2018-11-08 12:33:43 -06002821 data = "{\"data\": [] }"
2822
2823 try:
Justin Thaler27197622019-01-23 14:42:11 -06002824 res = session.post(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Adriana Kobylak5af2fad2018-11-08 12:33:43 -06002825 except(requests.exceptions.Timeout):
2826 return(connectionErrHandler(args.json, "Timeout", None))
2827 if res.status_code == 200:
2828 return ('The firmware version has been deleted')
2829 else:
2830 return ('Unable to delete the specified firmware version')
2831
2832
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05002833def restLogging(host, args, session):
2834 """
2835 Called by the logging function. Turns REST API logging on/off.
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002836
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05002837 @param host: string, the hostname or IP address of the bmc
2838 @param args: contains additional arguments used by the logging sub command
2839 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002840 @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 -05002841 """
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05002842 url="https://"+host+"/xyz/openbmc_project/logging/rest_api_logs/attr/Enabled"
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05002843
2844 if(args.rest_logging == 'on'):
2845 data = '{"data": 1}'
2846 elif(args.rest_logging == 'off'):
2847 data = '{"data": 0}'
2848 else:
2849 return "Invalid logging rest_api command"
2850
2851 try:
Justin Thaler27197622019-01-23 14:42:11 -06002852 res = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05002853 except(requests.exceptions.Timeout):
2854 return(connectionErrHandler(args.json, "Timeout", None))
2855 return res.text
2856
2857
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002858def remoteLogging(host, args, session):
2859 """
2860 Called by the logging function. View config information for/disable remote logging (rsyslog).
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002861
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002862 @param host: string, the hostname or IP address of the bmc
2863 @param args: contains additional arguments used by the logging sub command
2864 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002865 @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 -05002866 """
2867
2868 url="https://"+host+"/xyz/openbmc_project/logging/config/remote"
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002869
2870 try:
2871 if(args.remote_logging == 'view'):
Justin Thaler27197622019-01-23 14:42:11 -06002872 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002873 elif(args.remote_logging == 'disable'):
Justin Thaler27197622019-01-23 14:42:11 -06002874 res = session.put(url + '/attr/Port', headers=jsonHeader, json = {"data": 0}, verify=False, timeout=baseTimeout)
2875 res = session.put(url + '/attr/Address', headers=jsonHeader, json = {"data": ""}, verify=False, timeout=baseTimeout)
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002876 else:
2877 return "Invalid logging remote_logging command"
2878 except(requests.exceptions.Timeout):
2879 return(connectionErrHandler(args.json, "Timeout", None))
2880 return res.text
2881
2882
2883def remoteLoggingConfig(host, args, session):
2884 """
2885 Called by the logging function. Configures remote logging (rsyslog).
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002886
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002887 @param host: string, the hostname or IP address of the bmc
2888 @param args: contains additional arguments used by the logging sub command
2889 @param session: the active session to use
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06002890 @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 -05002891 """
2892
2893 url="https://"+host+"/xyz/openbmc_project/logging/config/remote"
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002894
2895 try:
Justin Thaler27197622019-01-23 14:42:11 -06002896 res = session.put(url + '/attr/Port', headers=jsonHeader, json = {"data": args.port}, verify=False, timeout=baseTimeout)
2897 res = session.put(url + '/attr/Address', headers=jsonHeader, json = {"data": args.address}, verify=False, timeout=baseTimeout)
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002898 except(requests.exceptions.Timeout):
2899 return(connectionErrHandler(args.json, "Timeout", None))
2900 return res.text
2901
Marri Devender Rao82590dc2019-06-06 04:54:22 -05002902def redfishSupportPresent(host, session):
2903 url = "https://" + host + "/redfish/v1"
2904 try:
2905 resp = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
2906 except(requests.exceptions.Timeout):
2907 return False
2908 except(requests.exceptions.ConnectionError) as err:
2909 return False
2910 if resp.status_code != 200:
2911 return False
2912 else:
2913 return True
Ratan Gupta9166cd22018-10-01 18:09:40 +05302914
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002915def certificateUpdate(host, args, session):
2916 """
2917 Called by certificate management function. update server/client/authority certificates
2918 Example:
2919 certificate update server https -f cert.pem
2920 certificate update authority ldap -f Root-CA.pem
2921 certificate update client ldap -f cert.pem
2922 @param host: string, the hostname or IP address of the bmc
2923 @param args: contains additional arguments used by the certificate update sub command
2924 @param session: the active session to use
2925 """
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002926 httpHeader = {'Content-Type': 'application/octet-stream'}
Matt Spinler220c3c42019-01-04 15:09:29 -06002927 httpHeader.update(xAuthHeader)
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002928 data = open(args.fileloc, 'rb').read()
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002929 try:
Marri Devender Rao82590dc2019-06-06 04:54:22 -05002930 if redfishSupportPresent(host, session):
Marri Devender Rao62db08a2019-08-22 03:16:02 -05002931 if(args.type.lower() == 'server' and args.service.lower() != "https"):
2932 return "Invalid service type"
2933 if(args.type.lower() == 'client' and args.service.lower() != "ldap"):
2934 return "Invalid service type"
2935 if(args.type.lower() == 'authority' and args.service.lower() != "ldap"):
2936 return "Invalid service type"
Marri Devender Rao82590dc2019-06-06 04:54:22 -05002937 url = "";
2938 if(args.type.lower() == 'server'):
2939 url = "https://" + host + \
2940 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"
2941 elif(args.type.lower() == 'client'):
2942 url = "https://" + host + \
2943 "/redfish/v1/AccountService/LDAP/Certificates"
2944 elif(args.type.lower() == 'authority'):
2945 url = "https://" + host + \
2946 "/redfish/v1/Managers/bmc/Truststore/Certificates"
2947 else:
2948 return "Unsupported certificate type"
2949 resp = session.post(url, headers=httpHeader, data=data,
2950 verify=False)
2951 else:
2952 url = "https://" + host + "/xyz/openbmc_project/certs/" + \
2953 args.type.lower() + "/" + args.service.lower()
2954 resp = session.put(url, headers=httpHeader, data=data, verify=False)
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002955 except(requests.exceptions.Timeout):
2956 return(connectionErrHandler(args.json, "Timeout", None))
2957 except(requests.exceptions.ConnectionError) as err:
2958 return connectionErrHandler(args.json, "ConnectionError", err)
2959 if resp.status_code != 200:
2960 print(resp.text)
2961 return "Failed to update the certificate"
2962 else:
Marri Devender Rao82590dc2019-06-06 04:54:22 -05002963 print("Update complete.")
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002964
2965def certificateDelete(host, args, session):
2966 """
2967 Called by certificate management function to delete certificate
2968 Example:
2969 certificate delete server https
2970 certificate delete authority ldap
2971 certificate delete client ldap
2972 @param host: string, the hostname or IP address of the bmc
2973 @param args: contains additional arguments used by the certificate delete sub command
2974 @param session: the active session to use
2975 """
Marri Devender Rao77e78682019-07-17 03:18:35 -05002976 if redfishSupportPresent(host, session):
2977 return "Not supported, please use certificate replace instead";
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002978 httpHeader = {'Content-Type': 'multipart/form-data'}
Matt Spinler220c3c42019-01-04 15:09:29 -06002979 httpHeader.update(xAuthHeader)
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05002980 url = "https://" + host + "/xyz/openbmc_project/certs/" + args.type.lower() + "/" + args.service.lower()
2981 print("Deleting certificate url=" + url)
2982 try:
2983 resp = session.delete(url, headers=httpHeader)
2984 except(requests.exceptions.Timeout):
2985 return(connectionErrHandler(args.json, "Timeout", None))
2986 except(requests.exceptions.ConnectionError) as err:
2987 return connectionErrHandler(args.json, "ConnectionError", err)
2988 if resp.status_code != 200:
2989 print(resp.text)
2990 return "Failed to delete the certificate"
2991 else:
Marri Devender Rao77e78682019-07-17 03:18:35 -05002992 print("Delete complete.")
Deepak Kodihalli02d53282018-09-18 06:53:31 -05002993
Marri Devender Raodfe81ad2019-07-01 05:38:09 -05002994def certificateReplace(host, args, session):
2995 """
2996 Called by certificate management function. replace server/client/
2997 authority certificates
2998 Example:
2999 certificate replace server https -f cert.pem
3000 certificate replace authority ldap -f Root-CA.pem
3001 certificate replace client ldap -f cert.pem
3002 @param host: string, the hostname or IP address of the bmc
3003 @param args: contains additional arguments used by the certificate
3004 replace sub command
3005 @param session: the active session to use
3006 """
3007 cert = open(args.fileloc, 'rb').read()
3008 try:
3009 if redfishSupportPresent(host, session):
3010 httpHeader = {'Content-Type': 'application/json'}
3011 httpHeader.update(xAuthHeader)
3012 url = "";
Marri Devender Rao62db08a2019-08-22 03:16:02 -05003013 if(args.type.lower() == 'server' and args.service.lower() != "https"):
3014 return "Invalid service type"
3015 if(args.type.lower() == 'client' and args.service.lower() != "ldap"):
3016 return "Invalid service type"
3017 if(args.type.lower() == 'authority' and args.service.lower() != "ldap"):
3018 return "Invalid service type"
Marri Devender Raodfe81ad2019-07-01 05:38:09 -05003019 if(args.type.lower() == 'server'):
3020 url = "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/1"
3021 elif(args.type.lower() == 'client'):
3022 url = "/redfish/v1/AccountService/LDAP/Certificates/1"
3023 elif(args.type.lower() == 'authority'):
3024 url = "/redfish/v1/Managers/bmc/Truststore/Certificates/1"
3025 replaceUrl = "https://" + host + \
3026 "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate"
3027 data ={"CertificateUri":{"@odata.id":url}, "CertificateType":"PEM",
3028 "CertificateString":cert}
3029 resp = session.post(replaceUrl, headers=httpHeader, json=data, verify=False)
3030 else:
3031 httpHeader = {'Content-Type': 'application/octet-stream'}
3032 httpHeader.update(xAuthHeader)
3033 url = "https://" + host + "/xyz/openbmc_project/certs/" + \
3034 args.type.lower() + "/" + args.service.lower()
3035 resp = session.delete(url, headers=httpHeader)
3036 resp = session.put(url, headers=httpHeader, data=cert, verify=False)
3037 except(requests.exceptions.Timeout):
3038 return(connectionErrHandler(args.json, "Timeout", None))
3039 except(requests.exceptions.ConnectionError) as err:
3040 return connectionErrHandler(args.json, "ConnectionError", err)
3041 if resp.status_code != 200:
3042 print(resp.text)
3043 return "Failed to replace the certificate"
3044 else:
3045 print("Replace complete.")
3046 return resp.text
3047
Marri Devender Rao34646402019-07-01 05:46:03 -05003048def certificateDisplay(host, args, session):
3049 """
3050 Called by certificate management function. display server/client/
3051 authority certificates
3052 Example:
3053 certificate display server
3054 certificate display authority
3055 certificate display client
3056 @param host: string, the hostname or IP address of the bmc
3057 @param args: contains additional arguments used by the certificate
3058 display sub command
3059 @param session: the active session to use
3060 """
3061 if not redfishSupportPresent(host, session):
3062 return "Not supported";
3063
3064 httpHeader = {'Content-Type': 'application/octet-stream'}
3065 httpHeader.update(xAuthHeader)
3066 if(args.type.lower() == 'server'):
3067 url = "https://" + host + \
3068 "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/1"
3069 elif(args.type.lower() == 'client'):
3070 url = "https://" + host + \
3071 "/redfish/v1/AccountService/LDAP/Certificates/1"
3072 elif(args.type.lower() == 'authority'):
3073 url = "https://" + host + \
3074 "/redfish/v1/Managers/bmc/Truststore/Certificates/1"
3075 try:
3076 resp = session.get(url, headers=httpHeader, verify=False)
3077 except(requests.exceptions.Timeout):
3078 return(connectionErrHandler(args.json, "Timeout", None))
3079 except(requests.exceptions.ConnectionError) as err:
3080 return connectionErrHandler(args.json, "ConnectionError", err)
3081 if resp.status_code != 200:
3082 print(resp.text)
3083 return "Failed to display the certificate"
3084 else:
3085 print("Display complete.")
3086 return resp.text
3087
Marri Devender Raoa208ff82019-07-01 05:51:27 -05003088def certificateList(host, args, session):
3089 """
3090 Called by certificate management function.
3091 Example:
3092 certificate list
3093 @param host: string, the hostname or IP address of the bmc
3094 @param args: contains additional arguments used by the certificate
3095 list sub command
3096 @param session: the active session to use
3097 """
3098 if not redfishSupportPresent(host, session):
3099 return "Not supported";
3100
3101 httpHeader = {'Content-Type': 'application/octet-stream'}
3102 httpHeader.update(xAuthHeader)
3103 url = "https://" + host + \
3104 "/redfish/v1/CertificateService/CertificateLocations/"
3105 try:
3106 resp = session.get(url, headers=httpHeader, verify=False)
3107 except(requests.exceptions.Timeout):
3108 return(connectionErrHandler(args.json, "Timeout", None))
3109 except(requests.exceptions.ConnectionError) as err:
3110 return connectionErrHandler(args.json, "ConnectionError", err)
3111 if resp.status_code != 200:
3112 print(resp.text)
3113 return "Failed to list certificates"
3114 else:
3115 print("List certificates complete.")
3116 return resp.text
3117
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05003118def certificateGenerateCSR(host, args, session):
3119 """
3120 Called by certificate management function. Generate CSR for server/
3121 client certificates
3122 Example:
Marri Devender Raodf0e1a42019-09-09 08:18:27 -05003123 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
3124 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 -05003125 @param host: string, the hostname or IP address of the bmc
3126 @param args: contains additional arguments used by the certificate replace sub command
3127 @param session: the active session to use
3128 """
3129 if not redfishSupportPresent(host, session):
3130 return "Not supported";
3131
3132 httpHeader = {'Content-Type': 'application/octet-stream'}
3133 httpHeader.update(xAuthHeader)
3134 url = "";
3135 if(args.type.lower() == 'server'):
3136 url = "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/"
Marri Devender Rao88064f02019-08-19 09:00:30 -05003137 usage_list = ["ServerAuthentication"]
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05003138 elif(args.type.lower() == 'client'):
3139 url = "/redfish/v1/AccountService/LDAP/Certificates/"
Marri Devender Rao88064f02019-08-19 09:00:30 -05003140 usage_list = ["ClientAuthentication"]
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05003141 elif(args.type.lower() == 'authority'):
3142 url = "/redfish/v1/Managers/bmc/Truststore/Certificates/"
3143 print("Generating CSR url=" + url)
3144 generateCSRUrl = "https://" + host + \
3145 "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR"
3146 try:
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05003147 alt_name_list = args.alternativeNames.split(",")
3148 data ={"CertificateCollection":{"@odata.id":url},
3149 "CommonName":args.commonName, "City":args.city,
3150 "Country":args.country, "Organization":args.organization,
3151 "OrganizationalUnit":args.organizationUnit, "State":args.state,
Marri Devender Raodf0e1a42019-09-09 08:18:27 -05003152 "KeyPairAlgorithm":args.keyPairAlgorithm, "KeyCurveId":args.keyCurveId,
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05003153 "AlternativeNames":alt_name_list, "ContactPerson":args.contactPerson,
3154 "Email":args.email, "GivenName":args.givenname, "Initials":args.initials,
3155 "KeyUsage":usage_list, "Surname":args.surname,
3156 "UnstructuredName":args.unstructuredname}
3157 resp = session.post(generateCSRUrl, headers=httpHeader,
3158 json=data, verify=False)
3159 except(requests.exceptions.Timeout):
3160 return(connectionErrHandler(args.json, "Timeout", None))
3161 except(requests.exceptions.ConnectionError) as err:
3162 return connectionErrHandler(args.json, "ConnectionError", err)
3163 if resp.status_code != 200:
3164 print(resp.text)
3165 return "Failed to generate CSR"
3166 else:
3167 print("GenerateCSR complete.")
3168 return resp.text
3169
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003170def enableLDAPConfig(host, args, session):
Ratan Gupta9166cd22018-10-01 18:09:40 +05303171 """
3172 Called by the ldap function. Configures LDAP.
3173
3174 @param host: string, the hostname or IP address of the bmc
3175 @param args: contains additional arguments used by the ldap subcommand
3176 @param session: the active session to use
3177 @param args.json: boolean, if this flag is set to true, the output will
3178 be provided in json format for programmatic consumption
3179 """
3180
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003181 if(isRedfishSupport):
3182 return enableLDAP(host, args, session)
3183 else:
3184 return enableLegacyLDAP(host, args, session)
3185
3186def enableLegacyLDAP(host, args, session):
3187 """
3188 Called by the ldap function. Configures LDAP on Lagecy systems.
3189
3190 @param host: string, the hostname or IP address of the bmc
3191 @param args: contains additional arguments used by the ldap subcommand
3192 @param session: the active session to use
3193 @param args.json: boolean, if this flag is set to true, the output will
3194 be provided in json format for programmatic consumption
3195 """
3196
Ratan Gupta9166cd22018-10-01 18:09:40 +05303197 url='https://'+host+'/xyz/openbmc_project/user/ldap/action/CreateConfig'
Ratan Gupta9166cd22018-10-01 18:09:40 +05303198 scope = {
3199 'sub' : 'xyz.openbmc_project.User.Ldap.Create.SearchScope.sub',
3200 'one' : 'xyz.openbmc_project.User.Ldap.Create.SearchScope.one',
3201 'base': 'xyz.openbmc_project.User.Ldap.Create.SearchScope.base'
3202 }
3203
3204 serverType = {
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003205 'ActiveDirectory' : 'xyz.openbmc_project.User.Ldap.Create.Type.ActiveDirectory',
3206 'OpenLDAP' : 'xyz.openbmc_project.User.Ldap.Create.Type.OpenLdap'
Ratan Gupta9166cd22018-10-01 18:09:40 +05303207 }
3208
3209 data = {"data": [args.uri, args.bindDN, args.baseDN, args.bindPassword, scope[args.scope], serverType[args.serverType]]}
3210
3211 try:
Justin Thaler27197622019-01-23 14:42:11 -06003212 res = session.post(url, headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
Ratan Gupta9166cd22018-10-01 18:09:40 +05303213 except(requests.exceptions.Timeout):
3214 return(connectionErrHandler(args.json, "Timeout", None))
3215 except(requests.exceptions.ConnectionError) as err:
3216 return connectionErrHandler(args.json, "ConnectionError", err)
3217
3218 return res.text
3219
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003220def enableLDAP(host, args, session):
3221 """
3222 Called by the ldap function. Configures LDAP for systems with latest user-manager design changes
3223
3224 @param host: string, the hostname or IP address of the bmc
3225 @param args: contains additional arguments used by the ldap subcommand
3226 @param session: the active session to use
3227 @param args.json: boolean, if this flag is set to true, the output will
3228 be provided in json format for programmatic consumption
3229 """
3230
3231 scope = {
3232 'sub' : 'xyz.openbmc_project.User.Ldap.Config.SearchScope.sub',
3233 'one' : 'xyz.openbmc_project.User.Ldap.Config.SearchScope.one',
3234 'base': 'xyz.openbmc_project.User.Ldap.Config.SearchScope.base'
3235 }
3236
3237 serverType = {
3238 'ActiveDirectory' : 'xyz.openbmc_project.User.Ldap.Config.Type.ActiveDirectory',
3239 'OpenLDAP' : 'xyz.openbmc_project.User.Ldap.Config.Type.OpenLdap'
3240 }
3241
3242 url = "https://"+host+"/xyz/openbmc_project/user/ldap/"
3243
3244 serverTypeEnabled = getLDAPTypeEnabled(host,session)
3245 serverTypeToBeEnabled = args.serverType
3246
3247 #If the given LDAP type is already enabled, then return
3248 if (serverTypeToBeEnabled == serverTypeEnabled):
3249 return("Server type " + serverTypeToBeEnabled + " is already enabled...")
3250
3251 try:
3252
3253 # Copy the role map from the currently enabled LDAP server type
3254 # to the newly enabled server type
3255 # Disable the currently enabled LDAP server type. Unless
3256 # it is disabled, we cannot enable a new LDAP server type
3257 if (serverTypeEnabled is not None):
3258
3259 if (serverTypeToBeEnabled != serverTypeEnabled):
3260 res = syncRoleMap(host,args,session,serverTypeEnabled,serverTypeToBeEnabled)
3261
3262 data = "{\"data\": 0 }"
3263 res = session.put(url + serverTypeMap[serverTypeEnabled] + '/attr/Enabled', headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
3264
3265 data = {"data": args.baseDN}
3266 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/LDAPBaseDN', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
3267 if (res.status_code != requests.codes.ok):
3268 print("Updates to the property LDAPBaseDN failed...")
3269 return(res.text)
3270
3271 data = {"data": args.bindDN}
3272 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/LDAPBindDN', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
3273 if (res.status_code != requests.codes.ok):
3274 print("Updates to the property LDAPBindDN failed...")
3275 return(res.text)
3276
3277 data = {"data": args.bindPassword}
3278 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/LDAPBindDNPassword', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
3279 if (res.status_code != requests.codes.ok):
3280 print("Updates to the property LDAPBindDNPassword failed...")
3281 return(res.text)
3282
3283 data = {"data": scope[args.scope]}
3284 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/LDAPSearchScope', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
3285 if (res.status_code != requests.codes.ok):
3286 print("Updates to the property LDAPSearchScope failed...")
3287 return(res.text)
3288
3289 data = {"data": args.uri}
3290 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/LDAPServerURI', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
3291 if (res.status_code != requests.codes.ok):
3292 print("Updates to the property LDAPServerURI failed...")
3293 return(res.text)
3294
3295 data = {"data": args.groupAttrName}
3296 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/GroupNameAttribute', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
3297 if (res.status_code != requests.codes.ok):
3298 print("Updates to the property GroupNameAttribute failed...")
3299 return(res.text)
3300
3301 data = {"data": args.userAttrName}
3302 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/UserNameAttribute', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
3303 if (res.status_code != requests.codes.ok):
3304 print("Updates to the property UserNameAttribute failed...")
3305 return(res.text)
3306
3307 #After updating the properties, enable the new server type
3308 data = "{\"data\": 1 }"
3309 res = session.put(url + serverTypeMap[serverTypeToBeEnabled] + '/attr/Enabled', headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
3310
3311 except(requests.exceptions.Timeout):
3312 return(connectionErrHandler(args.json, "Timeout", None))
3313 except(requests.exceptions.ConnectionError) as err:
3314 return connectionErrHandler(args.json, "ConnectionError", err)
3315 return res.text
Ratan Gupta9166cd22018-10-01 18:09:40 +05303316
3317def disableLDAP(host, args, session):
3318 """
3319 Called by the ldap function. Deletes the LDAP Configuration.
3320
3321 @param host: string, the hostname or IP address of the bmc
3322 @param args: contains additional arguments used by the ldap subcommand
3323 @param session: the active session to use
3324 @param args.json: boolean, if this flag is set to true, the output
3325 will be provided in json format for programmatic consumption
3326 """
3327
Ratan Gupta9166cd22018-10-01 18:09:40 +05303328 try:
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05003329 if (isRedfishSupport) :
3330
3331 url = "https://"+host+"/xyz/openbmc_project/user/ldap/"
3332
3333 serverTypeEnabled = getLDAPTypeEnabled(host,session)
3334
3335 if (serverTypeEnabled is not None):
3336 #To keep the role map in sync,
3337 #If the server type being disabled has role map, then
3338 # - copy the role map to the other server type(s)
3339 for serverType in serverTypeMap.keys():
3340 if (serverType != serverTypeEnabled):
3341 res = syncRoleMap(host,args,session,serverTypeEnabled,serverType)
3342
3343 #Disable the currently enabled LDAP server type
3344 data = "{\"data\": 0 }"
3345 res = session.put(url + serverTypeMap[serverTypeEnabled] + '/attr/Enabled', headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
3346
3347 else:
3348 return("LDAP server has not been enabled...")
3349
3350 else :
3351 url='https://'+host+'/xyz/openbmc_project/user/ldap/config/action/delete'
3352 data = {"data": []}
3353 res = session.post(url, headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
3354
Ratan Gupta9166cd22018-10-01 18:09:40 +05303355 except(requests.exceptions.Timeout):
3356 return(connectionErrHandler(args.json, "Timeout", None))
3357 except(requests.exceptions.ConnectionError) as err:
3358 return connectionErrHandler(args.json, "ConnectionError", err)
3359
3360 return res.text
3361
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003362def enableDHCP(host, args, session):
3363
3364 """
3365 Called by the network function. Enables DHCP.
3366
3367 @param host: string, the hostname or IP address of the bmc
3368 @param args: contains additional arguments used by the ldap subcommand
3369 args.json: boolean, if this flag is set to true, the output
3370 will be provided in json format for programmatic consumption
3371 @param session: the active session to use
3372 """
3373
3374 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3375 "/attr/DHCPEnabled"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003376 data = "{\"data\": 1 }"
3377 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003378 res = session.put(url, headers=jsonHeader, data=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003379 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003380
3381 except(requests.exceptions.Timeout):
3382 return(connectionErrHandler(args.json, "Timeout", None))
3383 except(requests.exceptions.ConnectionError) as err:
3384 return connectionErrHandler(args.json, "ConnectionError", err)
3385 if res.status_code == 403:
3386 return "The specified Interface"+"("+args.Interface+")"+\
3387 " doesn't exist"
3388
3389 return res.text
3390
3391
3392def disableDHCP(host, args, session):
3393 """
3394 Called by the network function. Disables DHCP.
3395
3396 @param host: string, the hostname or IP address of the bmc
3397 @param args: contains additional arguments used by the ldap subcommand
3398 args.json: boolean, if this flag is set to true, the output
3399 will be provided in json format for programmatic consumption
3400 @param session: the active session to use
3401 """
3402
3403 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3404 "/attr/DHCPEnabled"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003405 data = "{\"data\": 0 }"
3406 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003407 res = session.put(url, headers=jsonHeader, data=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003408 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003409 except(requests.exceptions.Timeout):
3410 return(connectionErrHandler(args.json, "Timeout", None))
3411 except(requests.exceptions.ConnectionError) as err:
3412 return connectionErrHandler(args.json, "ConnectionError", err)
3413 if res.status_code == 403:
3414 return "The specified Interface"+"("+args.Interface+")"+\
3415 " doesn't exist"
3416 return res.text
3417
3418
3419def getHostname(host, args, session):
3420
3421 """
3422 Called by the network function. Prints out the Hostname.
3423
3424 @param host: string, the hostname or IP address of the bmc
3425 @param args: contains additional arguments used by the ldap subcommand
3426 args.json: boolean, if this flag is set to true, the output
3427 will be provided in json format for programmatic consumption
3428 @param session: the active session to use
3429 """
3430
3431 url = "https://"+host+"/xyz/openbmc_project/network/config/attr/HostName"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003432
3433 try:
Justin Thaler27197622019-01-23 14:42:11 -06003434 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003435 except(requests.exceptions.Timeout):
3436 return(connectionErrHandler(args.json, "Timeout", None))
3437 except(requests.exceptions.ConnectionError) as err:
3438 return connectionErrHandler(args.json, "ConnectionError", err)
3439
3440 return res.text
3441
3442
3443def setHostname(host, args, session):
3444 """
3445 Called by the network function. Sets the Hostname.
3446
3447 @param host: string, the hostname or IP address of the bmc
3448 @param args: contains additional arguments used by the ldap subcommand
3449 args.json: boolean, if this flag is set to true, the output
3450 will be provided in json format for programmatic consumption
3451 @param session: the active session to use
3452 """
3453
3454 url = "https://"+host+"/xyz/openbmc_project/network/config/attr/HostName"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003455
3456 data = {"data": args.HostName}
3457
3458 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003459 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003460 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003461 except(requests.exceptions.Timeout):
3462 return(connectionErrHandler(args.json, "Timeout", None))
3463 except(requests.exceptions.ConnectionError) as err:
3464 return connectionErrHandler(args.json, "ConnectionError", err)
3465
3466 return res.text
3467
3468
3469def getDomainName(host, args, session):
3470
3471 """
3472 Called by the network function. Prints out the DomainName.
3473
3474 @param host: string, the hostname or IP address of the bmc
3475 @param args: contains additional arguments used by the ldap subcommand
3476 args.json: boolean, if this flag is set to true, the output
3477 will be provided in json format for programmatic consumption
3478 @param session: the active session to use
3479 """
3480
3481 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3482 "/attr/DomainName"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003483
3484 try:
Justin Thaler27197622019-01-23 14:42:11 -06003485 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003486 except(requests.exceptions.Timeout):
3487 return(connectionErrHandler(args.json, "Timeout", None))
3488 except(requests.exceptions.ConnectionError) as err:
3489 return connectionErrHandler(args.json, "ConnectionError", err)
3490 if res.status_code == 404:
Sunitha Harishf9bb2fa2019-09-19 01:48:00 -05003491 return "The DomainName is not configured on Interface"+"("+args.Interface+")"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003492
3493 return res.text
3494
3495
3496def setDomainName(host, args, session):
3497 """
3498 Called by the network function. Sets the DomainName.
3499
3500 @param host: string, the hostname or IP address of the bmc
3501 @param args: contains additional arguments used by the ldap subcommand
3502 args.json: boolean, if this flag is set to true, the output
3503 will be provided in json format for programmatic consumption
3504 @param session: the active session to use
3505 """
3506
3507 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3508 "/attr/DomainName"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003509
3510 data = {"data": args.DomainName.split(",")}
3511
3512 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003513 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003514 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003515 except(requests.exceptions.Timeout):
3516 return(connectionErrHandler(args.json, "Timeout", None))
3517 except(requests.exceptions.ConnectionError) as err:
3518 return connectionErrHandler(args.json, "ConnectionError", err)
3519 if res.status_code == 403:
3520 return "The specified Interface"+"("+args.Interface+")"+\
3521 " doesn't exist"
3522
3523 return res.text
3524
3525
3526def getMACAddress(host, args, session):
3527
3528 """
3529 Called by the network function. Prints out the MACAddress.
3530
3531 @param host: string, the hostname or IP address of the bmc
3532 @param args: contains additional arguments used by the ldap subcommand
3533 args.json: boolean, if this flag is set to true, the output
3534 will be provided in json format for programmatic consumption
3535 @param session: the active session to use
3536 """
3537
3538 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3539 "/attr/MACAddress"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003540
3541 try:
Justin Thaler27197622019-01-23 14:42:11 -06003542 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003543 except(requests.exceptions.Timeout):
3544 return(connectionErrHandler(args.json, "Timeout", None))
3545 except(requests.exceptions.ConnectionError) as err:
3546 return connectionErrHandler(args.json, "ConnectionError", err)
3547 if res.status_code == 404:
3548 return "The specified Interface"+"("+args.Interface+")"+\
3549 " doesn't exist"
3550
3551 return res.text
3552
3553
3554def setMACAddress(host, args, session):
3555 """
3556 Called by the network function. Sets the MACAddress.
3557
3558 @param host: string, the hostname or IP address of the bmc
3559 @param args: contains additional arguments used by the ldap subcommand
3560 args.json: boolean, if this flag is set to true, the output
3561 will be provided in json format for programmatic consumption
3562 @param session: the active session to use
3563 """
3564
3565 url = "https://"+host+"/xyz/openbmc_project/network/"+args.Interface+\
3566 "/attr/MACAddress"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003567
3568 data = {"data": args.MACAddress}
3569
3570 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003571 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003572 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003573 except(requests.exceptions.Timeout):
3574 return(connectionErrHandler(args.json, "Timeout", None))
3575 except(requests.exceptions.ConnectionError) as err:
3576 return connectionErrHandler(args.json, "ConnectionError", err)
3577 if res.status_code == 403:
3578 return "The specified Interface"+"("+args.Interface+")"+\
3579 " doesn't exist"
3580
3581 return res.text
3582
3583
3584def getDefaultGateway(host, args, session):
3585
3586 """
3587 Called by the network function. Prints out the DefaultGateway.
3588
3589 @param host: string, the hostname or IP address of the bmc
3590 @param args: contains additional arguments used by the ldap subcommand
3591 args.json: boolean, if this flag is set to true, the output
3592 will be provided in json format for programmatic consumption
3593 @param session: the active session to use
3594 """
3595
3596 url = "https://"+host+"/xyz/openbmc_project/network/config/attr/DefaultGateway"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003597
3598 try:
Justin Thaler27197622019-01-23 14:42:11 -06003599 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003600 except(requests.exceptions.Timeout):
3601 return(connectionErrHandler(args.json, "Timeout", None))
3602 except(requests.exceptions.ConnectionError) as err:
3603 return connectionErrHandler(args.json, "ConnectionError", err)
3604 if res.status_code == 404:
3605 return "Failed to get Default Gateway info!!"
3606
3607 return res.text
3608
3609
3610def setDefaultGateway(host, args, session):
3611 """
3612 Called by the network function. Sets the DefaultGateway.
3613
3614 @param host: string, the hostname or IP address of the bmc
3615 @param args: contains additional arguments used by the ldap subcommand
3616 args.json: boolean, if this flag is set to true, the output
3617 will be provided in json format for programmatic consumption
3618 @param session: the active session to use
3619 """
3620
3621 url = "https://"+host+"/xyz/openbmc_project/network/config/attr/DefaultGateway"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003622
3623 data = {"data": args.DefaultGW}
3624
3625 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003626 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003627 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003628 except(requests.exceptions.Timeout):
3629 return(connectionErrHandler(args.json, "Timeout", None))
3630 except(requests.exceptions.ConnectionError) as err:
3631 return connectionErrHandler(args.json, "ConnectionError", err)
3632 if res.status_code == 403:
3633 return "Failed to set Default Gateway!!"
3634
3635 return res.text
3636
3637
3638def viewNWConfig(host, args, session):
3639 """
3640 Called by the ldap function. Prints out network configured properties
3641
3642 @param host: string, the hostname or IP address of the bmc
3643 @param args: contains additional arguments used by the ldap subcommand
3644 args.json: boolean, if this flag is set to true, the output
3645 will be provided in json format for programmatic consumption
3646 @param session: the active session to use
3647 @return returns LDAP's configured properties.
3648 """
3649 url = "https://"+host+"/xyz/openbmc_project/network/enumerate"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003650 try:
Justin Thaler27197622019-01-23 14:42:11 -06003651 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003652 except(requests.exceptions.Timeout):
3653 return(connectionErrHandler(args.json, "Timeout", None))
3654 except(requests.exceptions.ConnectionError) as err:
3655 return connectionErrHandler(args.json, "ConnectionError", err)
3656 except(requests.exceptions.RequestException) as err:
3657 return connectionErrHandler(args.json, "RequestException", err)
3658 if res.status_code == 404:
3659 return "LDAP server config has not been created"
3660 return res.text
3661
3662
3663def getDNS(host, args, session):
3664
3665 """
3666 Called by the network function. Prints out DNS servers on the interface
3667
3668 @param host: string, the hostname or IP address of the bmc
3669 @param args: contains additional arguments used by the ldap subcommand
3670 args.json: boolean, if this flag is set to true, the output
3671 will be provided in json format for programmatic consumption
3672 @param session: the active session to use
3673 """
3674
3675 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
3676 + "/attr/Nameservers"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003677
3678 try:
Justin Thaler27197622019-01-23 14:42:11 -06003679 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003680 except(requests.exceptions.Timeout):
3681 return(connectionErrHandler(args.json, "Timeout", None))
3682 except(requests.exceptions.ConnectionError) as err:
3683 return connectionErrHandler(args.json, "ConnectionError", err)
3684 if res.status_code == 404:
Sunitha Harishf9bb2fa2019-09-19 01:48:00 -05003685 return "The NameServer is not configured on Interface"+"("+args.Interface+")"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003686
3687 return res.text
3688
3689
3690def setDNS(host, args, session):
3691 """
3692 Called by the network function. Sets DNS servers on the interface.
3693
3694 @param host: string, the hostname or IP address of the bmc
3695 @param args: contains additional arguments used by the ldap subcommand
3696 args.json: boolean, if this flag is set to true, the output
3697 will be provided in json format for programmatic consumption
3698 @param session: the active session to use
3699 """
3700
3701 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
3702 + "/attr/Nameservers"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003703
3704 data = {"data": args.DNSServers.split(",")}
3705
3706 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003707 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003708 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003709 except(requests.exceptions.Timeout):
3710 return(connectionErrHandler(args.json, "Timeout", None))
3711 except(requests.exceptions.ConnectionError) as err:
3712 return connectionErrHandler(args.json, "ConnectionError", err)
3713 if res.status_code == 403:
3714 return "The specified Interface"+"("+args.Interface+")" +\
3715 " doesn't exist"
3716
3717 return res.text
3718
3719
3720def getNTP(host, args, session):
3721
3722 """
3723 Called by the network function. Prints out NTP servers on the interface
3724
3725 @param host: string, the hostname or IP address of the bmc
3726 @param args: contains additional arguments used by the ldap subcommand
3727 args.json: boolean, if this flag is set to true, the output
3728 will be provided in json format for programmatic consumption
3729 @param session: the active session to use
3730 """
3731
3732 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
3733 + "/attr/NTPServers"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003734 try:
Justin Thaler27197622019-01-23 14:42:11 -06003735 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003736 except(requests.exceptions.Timeout):
3737 return(connectionErrHandler(args.json, "Timeout", None))
3738 except(requests.exceptions.ConnectionError) as err:
3739 return connectionErrHandler(args.json, "ConnectionError", err)
3740 if res.status_code == 404:
Sunitha Harishf9bb2fa2019-09-19 01:48:00 -05003741 return "The NTPServer is not configured on Interface"+"("+args.Interface+")"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003742
3743 return res.text
3744
3745
3746def setNTP(host, args, session):
3747 """
3748 Called by the network function. Sets NTP servers on the interface.
3749
3750 @param host: string, the hostname or IP address of the bmc
3751 @param args: contains additional arguments used by the ldap subcommand
3752 args.json: boolean, if this flag is set to true, the output
3753 will be provided in json format for programmatic consumption
3754 @param session: the active session to use
3755 """
3756
3757 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
3758 + "/attr/NTPServers"
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003759
3760 data = {"data": args.NTPServers.split(",")}
3761
3762 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003763 res = session.put(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003764 timeout=baseTimeout)
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06003765 except(requests.exceptions.Timeout):
3766 return(connectionErrHandler(args.json, "Timeout", None))
3767 except(requests.exceptions.ConnectionError) as err:
3768 return connectionErrHandler(args.json, "ConnectionError", err)
3769 if res.status_code == 403:
3770 return "The specified Interface"+"("+args.Interface+")" +\
3771 " doesn't exist"
3772
3773 return res.text
3774
3775
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003776def addIP(host, args, session):
3777 """
3778 Called by the network function. Configures IP address on given interface
3779
3780 @param host: string, the hostname or IP address of the bmc
3781 @param args: contains additional arguments used by the ldap subcommand
3782 args.json: boolean, if this flag is set to true, the output
3783 will be provided in json format for programmatic consumption
3784 @param session: the active session to use
3785 """
3786
3787 url = "https://" + host + "/xyz/openbmc_project/network/" + args.Interface\
3788 + "/action/IP"
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003789 protocol = {
3790 'ipv4': 'xyz.openbmc_project.Network.IP.Protocol.IPv4',
3791 'ipv6': 'xyz.openbmc_project.Network.IP.Protocol.IPv6'
3792 }
3793
3794 data = {"data": [protocol[args.type], args.address, int(args.prefixLength),
3795 args.gateway]}
3796
3797 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003798 res = session.post(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003799 timeout=baseTimeout)
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003800 except(requests.exceptions.Timeout):
3801 return(connectionErrHandler(args.json, "Timeout", None))
3802 except(requests.exceptions.ConnectionError) as err:
3803 return connectionErrHandler(args.json, "ConnectionError", err)
3804 if res.status_code == 404:
3805 return "The specified Interface" + "(" + args.Interface + ")" +\
3806 " doesn't exist"
3807
3808 return res.text
3809
3810
3811def getIP(host, args, session):
3812 """
3813 Called by the network function. Prints out IP address of given interface
3814
3815 @param host: string, the hostname or IP address of the bmc
3816 @param args: contains additional arguments used by the ldap subcommand
3817 args.json: boolean, if this flag is set to true, the output
3818 will be provided in json format for programmatic consumption
3819 @param session: the active session to use
3820 """
3821
3822 url = "https://" + host+"/xyz/openbmc_project/network/" + args.Interface +\
3823 "/enumerate"
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003824 try:
Justin Thaler27197622019-01-23 14:42:11 -06003825 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003826 except(requests.exceptions.Timeout):
3827 return(connectionErrHandler(args.json, "Timeout", None))
3828 except(requests.exceptions.ConnectionError) as err:
3829 return connectionErrHandler(args.json, "ConnectionError", err)
3830 if res.status_code == 404:
3831 return "The specified Interface" + "(" + args.Interface + ")" +\
3832 " doesn't exist"
3833
3834 return res.text
3835
3836
3837def deleteIP(host, args, session):
3838 """
3839 Called by the network function. Deletes the IP address from given Interface
3840
3841 @param host: string, the hostname or IP address of the bmc
3842 @param args: contains additional arguments used by the ldap subcommand
3843 @param session: the active session to use
3844 @param args.json: boolean, if this flag is set to true, the output
3845 will be provided in json format for programmatic consumption
3846 """
3847
3848 url = "https://"+host+"/xyz/openbmc_project/network/" + args.Interface+\
3849 "/enumerate"
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003850 data = {"data": []}
3851 try:
Justin Thaler27197622019-01-23 14:42:11 -06003852 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003853 except(requests.exceptions.Timeout):
3854 return(connectionErrHandler(args.json, "Timeout", None))
3855 except(requests.exceptions.ConnectionError) as err:
3856 return connectionErrHandler(args.json, "ConnectionError", err)
3857 if res.status_code == 404:
3858 return "The specified Interface" + "(" + args.Interface + ")" +\
3859 " doesn't exist"
3860 objDict = json.loads(res.text)
3861 if not objDict['data']:
3862 return "No object found for given address on given Interface"
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003863 for obj in objDict['data']:
Sunitha Harish0baf6372019-07-31 03:59:03 -05003864 try:
3865 if args.address in objDict['data'][obj]['Address']:
3866 url = "https://"+host+obj+"/action/Delete"
3867 try:
3868 res = session.post(url, headers=jsonHeader, json=data,
3869 verify=False, timeout=baseTimeout)
3870 except(requests.exceptions.Timeout):
3871 return(connectionErrHandler(args.json, "Timeout", None))
3872 except(requests.exceptions.ConnectionError) as err:
3873 return connectionErrHandler(args.json, "ConnectionError", err)
3874 return res.text
3875 else:
3876 continue
3877 except KeyError:
Sunitha Harishf9bb2fa2019-09-19 01:48:00 -05003878 continue
3879 return "No object found for address " + args.address + \
3880 " on Interface(" + args.Interface + ")"
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06003881
3882
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003883def addVLAN(host, args, session):
3884 """
3885 Called by the network function. Creates VLAN on given interface.
3886
3887 @param host: string, the hostname or IP address of the bmc
3888 @param args: contains additional arguments used by the ldap subcommand
3889 args.json: boolean, if this flag is set to true, the output
3890 will be provided in json format for programmatic consumption
3891 @param session: the active session to use
3892 """
3893
3894 url = "https://" + host+"/xyz/openbmc_project/network/action/VLAN"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003895
Sunitha Harish0baf6372019-07-31 03:59:03 -05003896 data = {"data": [args.Interface,int(args.Identifier)]}
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003897 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06003898 res = session.post(url, headers=jsonHeader, json=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06003899 timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003900 except(requests.exceptions.Timeout):
3901 return(connectionErrHandler(args.json, "Timeout", None))
3902 except(requests.exceptions.ConnectionError) as err:
3903 return connectionErrHandler(args.json, "ConnectionError", err)
3904 if res.status_code == 400:
Sunitha Harish0baf6372019-07-31 03:59:03 -05003905 return "Adding VLAN to interface" + "(" + args.Interface + ")" +\
3906 " failed"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003907
3908 return res.text
3909
3910
3911def deleteVLAN(host, args, session):
3912 """
3913 Called by the network function. Creates VLAN on given interface.
3914
3915 @param host: string, the hostname or IP address of the bmc
3916 @param args: contains additional arguments used by the ldap subcommand
3917 args.json: boolean, if this flag is set to true, the output
3918 will be provided in json format for programmatic consumption
3919 @param session: the active session to use
3920 """
3921
Sunitha Harish577a5032019-08-08 06:27:40 -05003922 url = "https://" + host+"/xyz/openbmc_project/network/"+args.Interface+"/action/Delete"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003923 data = {"data": []}
3924
3925 try:
Justin Thaler27197622019-01-23 14:42:11 -06003926 res = session.post(url, headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003927 except(requests.exceptions.Timeout):
3928 return(connectionErrHandler(args.json, "Timeout", None))
3929 except(requests.exceptions.ConnectionError) as err:
3930 return connectionErrHandler(args.json, "ConnectionError", err)
3931 if res.status_code == 404:
Sunitha Harish577a5032019-08-08 06:27:40 -05003932 return "The specified VLAN"+"("+args.Interface+")" +" doesn't exist"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003933
3934 return res.text
3935
3936
3937def viewDHCPConfig(host, args, session):
3938 """
3939 Called by the network function. Shows DHCP configured Properties.
3940
3941 @param host: string, the hostname or IP address of the bmc
3942 @param args: contains additional arguments used by the ldap subcommand
3943 args.json: boolean, if this flag is set to true, the output
3944 will be provided in json format for programmatic consumption
3945 @param session: the active session to use
3946 """
3947
3948 url="https://"+host+"/xyz/openbmc_project/network/config/dhcp"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003949
3950 try:
Justin Thaler27197622019-01-23 14:42:11 -06003951 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003952 except(requests.exceptions.Timeout):
3953 return(connectionErrHandler(args.json, "Timeout", None))
3954 except(requests.exceptions.ConnectionError) as err:
3955 return connectionErrHandler(args.json, "ConnectionError", err)
3956
3957 return res.text
3958
3959
3960def configureDHCP(host, args, session):
3961 """
3962 Called by the network function. Configures/updates DHCP Properties.
3963
3964 @param host: string, the hostname or IP address of the bmc
3965 @param args: contains additional arguments used by the ldap subcommand
3966 args.json: boolean, if this flag is set to true, the output
3967 will be provided in json format for programmatic consumption
3968 @param session: the active session to use
3969 """
3970
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003971
3972 try:
3973 url="https://"+host+"/xyz/openbmc_project/network/config/dhcp"
3974 if(args.DNSEnabled == True):
3975 data = '{"data": 1}'
3976 else:
3977 data = '{"data": 0}'
Matt Spinler220c3c42019-01-04 15:09:29 -06003978 res = session.put(url + '/attr/DNSEnabled', headers=jsonHeader,
Justin Thaler27197622019-01-23 14:42:11 -06003979 data=data, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003980 if(args.HostNameEnabled == True):
3981 data = '{"data": 1}'
3982 else:
3983 data = '{"data": 0}'
Matt Spinler220c3c42019-01-04 15:09:29 -06003984 res = session.put(url + '/attr/HostNameEnabled', headers=jsonHeader,
Justin Thaler27197622019-01-23 14:42:11 -06003985 data=data, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003986 if(args.NTPEnabled == True):
3987 data = '{"data": 1}'
3988 else:
3989 data = '{"data": 0}'
Matt Spinler220c3c42019-01-04 15:09:29 -06003990 res = session.put(url + '/attr/NTPEnabled', headers=jsonHeader,
Justin Thaler27197622019-01-23 14:42:11 -06003991 data=data, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003992 if(args.SendHostNameEnabled == True):
3993 data = '{"data": 1}'
3994 else:
3995 data = '{"data": 0}'
Matt Spinler220c3c42019-01-04 15:09:29 -06003996 res = session.put(url + '/attr/SendHostNameEnabled', headers=jsonHeader,
Justin Thaler27197622019-01-23 14:42:11 -06003997 data=data, verify=False, timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06003998 except(requests.exceptions.Timeout):
3999 return(connectionErrHandler(args.json, "Timeout", None))
4000 except(requests.exceptions.ConnectionError) as err:
4001 return connectionErrHandler(args.json, "ConnectionError", err)
4002
4003 return res.text
4004
4005
4006def nwReset(host, args, session):
4007
4008 """
4009 Called by the network function. Resets networks setting to factory defaults.
4010
4011 @param host: string, the hostname or IP address of the bmc
4012 @param args: contains additional arguments used by the ldap subcommand
4013 args.json: boolean, if this flag is set to true, the output
4014 will be provided in json format for programmatic consumption
4015 @param session: the active session to use
4016 """
4017
4018 url = "https://"+host+"/xyz/openbmc_project/network/action/Reset"
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004019 data = '{"data":[] }'
4020 try:
Matt Spinler220c3c42019-01-04 15:09:29 -06004021 res = session.post(url, headers=jsonHeader, data=data, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06004022 timeout=baseTimeout)
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004023
4024 except(requests.exceptions.Timeout):
4025 return(connectionErrHandler(args.json, "Timeout", None))
4026 except(requests.exceptions.ConnectionError) as err:
4027 return connectionErrHandler(args.json, "ConnectionError", err)
4028
4029 return res.text
4030
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004031def getLDAPTypeEnabled(host,session):
4032
4033 """
4034 Called by LDAP related functions to find the LDAP server type that has been enabled.
4035 Returns None if LDAP has not been configured.
4036
4037 @param host: string, the hostname or IP address of the bmc
4038 @param session: the active session to use
4039 """
4040
4041 enabled = False
4042 url = 'https://'+host+'/xyz/openbmc_project/user/ldap/'
4043 for key,value in serverTypeMap.items():
4044 data = {"data": []}
4045 try:
4046 res = session.get(url + value + '/attr/Enabled', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
4047 except(requests.exceptions.Timeout):
4048 print(connectionErrHandler(args.json, "Timeout", None))
4049 return
4050 except(requests.exceptions.ConnectionError) as err:
4051 print(connectionErrHandler(args.json, "ConnectionError", err))
4052 return
4053
4054 enabled = res.json()['data']
4055 if (enabled):
4056 return key
4057
4058def syncRoleMap(host,args,session,fromServerType,toServerType):
4059
4060 """
4061 Called by LDAP related functions to sync the role maps
4062 Returns False if LDAP has not been configured.
4063
4064 @param host: string, the hostname or IP address of the bmc
4065 @param session: the active session to use
4066 @param fromServerType : Server type whose role map has to be copied
4067 @param toServerType : Server type to which role map has to be copied
4068 """
4069
4070 url = "https://"+host+"/xyz/openbmc_project/user/ldap/"
4071
4072 try:
4073 #Note: If the fromServerType has no role map, then
4074 #the toServerType will not have any role map.
4075
4076 #delete the privilege mapping from the toServerType and
4077 #then copy the privilege mapping from fromServerType to
4078 #toServerType.
4079 args.serverType = toServerType
4080 res = deleteAllPrivilegeMapping(host, args, session)
4081
4082 data = {"data": []}
4083 res = session.get(url + serverTypeMap[fromServerType] + '/role_map/enumerate', headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
4084 #Previously enabled server type has no role map
4085 if (res.status_code != requests.codes.ok):
4086
4087 #fromServerType has no role map; So, no need to copy
4088 #role map to toServerType.
4089 return
4090
4091 objDict = json.loads(res.text)
4092 dataDict = objDict['data']
4093 for key,value in dataDict.items():
4094 data = {"data": [value["GroupName"], value["Privilege"]]}
4095 res = session.post(url + serverTypeMap[toServerType] + '/action/Create', headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
4096
4097 except(requests.exceptions.Timeout):
4098 return(connectionErrHandler(args.json, "Timeout", None))
4099 except(requests.exceptions.ConnectionError) as err:
4100 return connectionErrHandler(args.json, "ConnectionError", err)
4101 return res.text
4102
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004103
Ratan Guptafeee6372018-10-17 23:25:51 +05304104def createPrivilegeMapping(host, args, session):
4105 """
4106 Called by the ldap function. Creates the group and the privilege mapping.
4107
4108 @param host: string, the hostname or IP address of the bmc
4109 @param args: contains additional arguments used by the ldap subcommand
4110 @param session: the active session to use
4111 @param args.json: boolean, if this flag is set to true, the output
4112 will be provided in json format for programmatic consumption
4113 """
4114
Ratan Guptafeee6372018-10-17 23:25:51 +05304115 try:
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004116 if (isRedfishSupport):
4117 url = 'https://'+host+'/xyz/openbmc_project/user/ldap/'
4118
4119 #To maintain the interface compatibility between op930 and op940, the server type has been made
4120 #optional. If the server type is not specified, then create the role-mapper for the currently
4121 #enabled server type.
4122 serverType = args.serverType
4123 if (serverType is None):
4124 serverType = getLDAPTypeEnabled(host,session)
4125 if (serverType is None):
4126 return("LDAP server has not been enabled. Please specify LDAP serverType to proceed further...")
4127
4128 data = {"data": [args.groupName,args.privilege]}
4129 res = session.post(url + serverTypeMap[serverType] + '/action/Create', headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
4130
4131 else:
4132 url = 'https://'+host+'/xyz/openbmc_project/user/ldap/action/Create'
4133 data = {"data": [args.groupName,args.privilege]}
4134 res = session.post(url, headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
4135
Ratan Guptafeee6372018-10-17 23:25:51 +05304136 except(requests.exceptions.Timeout):
4137 return(connectionErrHandler(args.json, "Timeout", None))
4138 except(requests.exceptions.ConnectionError) as err:
4139 return connectionErrHandler(args.json, "ConnectionError", err)
4140 return res.text
4141
4142def listPrivilegeMapping(host, args, session):
4143 """
4144 Called by the ldap function. Lists the group and the privilege mapping.
4145
4146 @param host: string, the hostname or IP address of the bmc
4147 @param args: contains additional arguments used by the ldap subcommand
4148 @param session: the active session to use
4149 @param args.json: boolean, if this flag is set to true, the output
4150 will be provided in json format for programmatic consumption
4151 """
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004152
4153 if (isRedfishSupport):
4154 serverType = args.serverType
4155 if (serverType is None):
4156 serverType = getLDAPTypeEnabled(host,session)
4157 if (serverType is None):
4158 return("LDAP has not been enabled. Please specify LDAP serverType to proceed further...")
4159
4160 url = 'https://'+host+'/xyz/openbmc_project/user/ldap/'+serverTypeMap[serverType]+'/role_map/enumerate'
4161
4162 else:
4163 url = 'https://'+host+'/xyz/openbmc_project/user/ldap/enumerate'
4164
Ratan Guptafeee6372018-10-17 23:25:51 +05304165 data = {"data": []}
4166
4167 try:
Justin Thaler27197622019-01-23 14:42:11 -06004168 res = session.get(url, headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
Ratan Guptafeee6372018-10-17 23:25:51 +05304169 except(requests.exceptions.Timeout):
4170 return(connectionErrHandler(args.json, "Timeout", None))
4171 except(requests.exceptions.ConnectionError) as err:
4172 return connectionErrHandler(args.json, "ConnectionError", err)
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004173
Ratan Guptafeee6372018-10-17 23:25:51 +05304174 return res.text
4175
4176def deletePrivilegeMapping(host, args, session):
4177 """
4178 Called by the ldap function. Deletes the mapping associated with the group.
4179
4180 @param host: string, the hostname or IP address of the bmc
4181 @param args: contains additional arguments used by the ldap subcommand
4182 @param session: the active session to use
4183 @param args.json: boolean, if this flag is set to true, the output
4184 will be provided in json format for programmatic consumption
4185 """
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004186
4187 ldapNameSpaceObjects = listPrivilegeMapping(host, args, session)
Ratan Guptafeee6372018-10-17 23:25:51 +05304188 ldapNameSpaceObjects = json.loads(ldapNameSpaceObjects)["data"]
4189 path = ''
Ratan Guptafeee6372018-10-17 23:25:51 +05304190 data = {"data": []}
4191
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004192 if (isRedfishSupport):
4193 if (args.serverType is None):
4194 serverType = getLDAPTypeEnabled(host,session)
4195 if (serverType is None):
4196 return("LDAP has not been enabled. Please specify LDAP serverType to proceed further...")
4197 # search for the object having the mapping for the given group
4198 for key,value in ldapNameSpaceObjects.items():
4199 if value['GroupName'] == args.groupName:
4200 path = key
4201 break
4202
4203 if path == '':
4204 return "No privilege mapping found for this group."
4205
4206 # delete the object
4207 url = 'https://'+host+path+'/action/Delete'
4208
4209 else:
4210 # not interested in the config objet
4211 ldapNameSpaceObjects.pop('/xyz/openbmc_project/user/ldap/config', None)
4212
4213 # search for the object having the mapping for the given group
4214 for key,value in ldapNameSpaceObjects.items():
4215 if value['GroupName'] == args.groupName:
4216 path = key
4217 break
4218
4219 if path == '':
4220 return "No privilege mapping found for this group."
4221
4222 # delete the object
4223 url = 'https://'+host+path+'/action/delete'
4224
Ratan Guptafeee6372018-10-17 23:25:51 +05304225 try:
Justin Thaler27197622019-01-23 14:42:11 -06004226 res = session.post(url, headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
Ratan Guptafeee6372018-10-17 23:25:51 +05304227 except(requests.exceptions.Timeout):
4228 return(connectionErrHandler(args.json, "Timeout", None))
4229 except(requests.exceptions.ConnectionError) as err:
4230 return connectionErrHandler(args.json, "ConnectionError", err)
4231 return res.text
Ratan Gupta9166cd22018-10-01 18:09:40 +05304232
Sivas SRR78835272018-11-27 05:27:19 -06004233def deleteAllPrivilegeMapping(host, args, session):
4234 """
4235 Called by the ldap function. Deletes all the privilege mapping and group defined.
4236 @param host: string, the hostname or IP address of the bmc
4237 @param args: contains additional arguments used by the ldap subcommand
4238 @param session: the active session to use
4239 @param args.json: boolean, if this flag is set to true, the output
4240 will be provided in json format for programmatic consumption
4241 """
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004242
Sivas SRR78835272018-11-27 05:27:19 -06004243 ldapNameSpaceObjects = listPrivilegeMapping(host, args, session)
4244 ldapNameSpaceObjects = json.loads(ldapNameSpaceObjects)["data"]
4245 path = ''
Sivas SRR78835272018-11-27 05:27:19 -06004246 data = {"data": []}
4247
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004248 if (isRedfishSupport):
4249 if (args.serverType is None):
4250 serverType = getLDAPTypeEnabled(host,session)
4251 if (serverType is None):
4252 return("LDAP has not been enabled. Please specify LDAP serverType to proceed further...")
4253
4254 else:
4255 # Remove the config object.
4256 ldapNameSpaceObjects.pop('/xyz/openbmc_project/user/ldap/config', None)
4257
Sivas SRR78835272018-11-27 05:27:19 -06004258 try:
4259 # search for GroupName property and delete if it is available.
4260 for path in ldapNameSpaceObjects.keys():
4261 # delete the object
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004262 url = 'https://'+host+path+'/action/Delete'
Justin Thaler27197622019-01-23 14:42:11 -06004263 res = session.post(url, headers=jsonHeader, json = data, verify=False, timeout=baseTimeout)
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004264
Sivas SRR78835272018-11-27 05:27:19 -06004265 except(requests.exceptions.Timeout):
4266 return(connectionErrHandler(args.json, "Timeout", None))
4267 except(requests.exceptions.ConnectionError) as err:
4268 return connectionErrHandler(args.json, "ConnectionError", err)
4269 return res.text
4270
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06004271def viewLDAPConfig(host, args, session):
4272 """
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004273 Called by the ldap function. Prints out active LDAP configuration properties
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06004274
4275 @param host: string, the hostname or IP address of the bmc
4276 @param args: contains additional arguments used by the ldap subcommand
4277 args.json: boolean, if this flag is set to true, the output
4278 will be provided in json format for programmatic consumption
4279 @param session: the active session to use
4280 @return returns LDAP's configured properties.
4281 """
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004282
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06004283 try:
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004284 if (isRedfishSupport):
4285
4286 url = "https://"+host+"/xyz/openbmc_project/user/ldap/"
4287
4288 serverTypeEnabled = getLDAPTypeEnabled(host,session)
4289
4290 if (serverTypeEnabled is not None):
4291 data = {"data": []}
4292 res = session.get(url + serverTypeMap[serverTypeEnabled], headers=jsonHeader, json=data, verify=False, timeout=baseTimeout)
4293 else:
4294 return("LDAP server has not been enabled...")
4295
4296 else :
4297 url = "https://"+host+"/xyz/openbmc_project/user/ldap/config"
4298 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
4299
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06004300 except(requests.exceptions.Timeout):
4301 return(connectionErrHandler(args.json, "Timeout", None))
4302 except(requests.exceptions.ConnectionError) as err:
4303 return connectionErrHandler(args.json, "ConnectionError", err)
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06004304 if res.status_code == 404:
4305 return "LDAP server config has not been created"
4306 return res.text
4307
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06004308def str2bool(v):
4309 if v.lower() in ('yes', 'true', 't', 'y', '1'):
4310 return True
4311 elif v.lower() in ('no', 'false', 'f', 'n', '0'):
4312 return False
4313 else:
4314 raise argparse.ArgumentTypeError('Boolean value expected.')
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06004315
Matt Spinler7d426c22018-09-24 14:42:07 -05004316def localUsers(host, args, session):
4317 """
4318 Enables and disables local BMC users.
4319
4320 @param host: string, the hostname or IP address of the bmc
4321 @param args: contains additional arguments used by the logging sub command
4322 @param session: the active session to use
4323 """
4324
Matt Spinler7d426c22018-09-24 14:42:07 -05004325 url="https://{hostname}/xyz/openbmc_project/user/enumerate".format(hostname=host)
4326 try:
Justin Thaler27197622019-01-23 14:42:11 -06004327 res = session.get(url, headers=jsonHeader, verify=False, timeout=baseTimeout)
Matt Spinler7d426c22018-09-24 14:42:07 -05004328 except(requests.exceptions.Timeout):
4329 return(connectionErrHandler(args.json, "Timeout", None))
4330 usersDict = json.loads(res.text)
4331
4332 if not usersDict['data']:
4333 return "No users found"
4334
4335 output = ""
4336 for user in usersDict['data']:
Matt Spinler015adc22018-10-23 14:30:19 -05004337
4338 # Skip LDAP and another non-local users
4339 if 'UserEnabled' not in usersDict['data'][user]:
4340 continue
4341
Matt Spinler7d426c22018-09-24 14:42:07 -05004342 name = user.split('/')[-1]
4343 url = "https://{hostname}{user}/attr/UserEnabled".format(hostname=host, user=user)
4344
4345 if args.local_users == "queryenabled":
4346 try:
Justin Thaler27197622019-01-23 14:42:11 -06004347 res = session.get(url, headers=jsonHeader,verify=False, timeout=baseTimeout)
Matt Spinler7d426c22018-09-24 14:42:07 -05004348 except(requests.exceptions.Timeout):
4349 return(connectionErrHandler(args.json, "Timeout", None))
4350
4351 result = json.loads(res.text)
4352 output += ("User: {name} Enabled: {result}\n").format(name=name, result=result['data'])
4353
4354 elif args.local_users in ["enableall", "disableall"]:
4355 action = ""
4356 if args.local_users == "enableall":
4357 data = '{"data": true}'
4358 action = "Enabling"
4359 else:
4360 data = '{"data": false}'
4361 action = "Disabling"
4362
4363 output += "{action} {name}\n".format(action=action, name=name)
4364
4365 try:
Justin Thaler27197622019-01-23 14:42:11 -06004366 resp = session.put(url, headers=jsonHeader, data=data, verify=False, timeout=baseTimeout)
Matt Spinler7d426c22018-09-24 14:42:07 -05004367 except(requests.exceptions.Timeout):
4368 return connectionErrHandler(args.json, "Timeout", None)
4369 except(requests.exceptions.ConnectionError) as err:
4370 return connectionErrHandler(args.json, "ConnectionError", err)
4371 else:
4372 return "Invalid local users argument"
4373
4374 return output
4375
Marri Devender Rao2c2a5162018-11-05 08:57:11 -06004376def setPassword(host, args, session):
4377 """
4378 Set local user password
4379 @param host: string, the hostname or IP address of the bmc
4380 @param args: contains additional arguments used by the logging sub
4381 command
4382 @param session: the active session to use
4383 @param args.json: boolean, if this flag is set to true, the output
4384 will be provided in json format for programmatic consumption
4385 @return: Session object
4386 """
Marri Devender Rao2c2a5162018-11-05 08:57:11 -06004387 try:
Sunitha Harishc99faba2019-07-19 06:55:22 -05004388 if(isRedfishSupport):
4389 url = "https://" + host + "/redfish/v1/AccountService/Accounts/"+ \
4390 args.user
4391 data = {"Password":args.password}
4392 res = session.patch(url, headers=jsonHeader, json=data,
4393 verify=False, timeout=baseTimeout)
4394 else:
4395 url = "https://" + host + "/xyz/openbmc_project/user/" + args.user + \
4396 "/action/SetPassword"
4397 res = session.post(url, headers=jsonHeader,
Marri Devender Rao2c2a5162018-11-05 08:57:11 -06004398 json={"data": [args.password]}, verify=False,
Justin Thaler27197622019-01-23 14:42:11 -06004399 timeout=baseTimeout)
Marri Devender Rao2c2a5162018-11-05 08:57:11 -06004400 except(requests.exceptions.Timeout):
4401 return(connectionErrHandler(args.json, "Timeout", None))
4402 except(requests.exceptions.ConnectionError) as err:
4403 return connectionErrHandler(args.json, "ConnectionError", err)
4404 except(requests.exceptions.RequestException) as err:
4405 return connectionErrHandler(args.json, "RequestException", err)
Sunitha Harishc99faba2019-07-19 06:55:22 -05004406 return res.status_code
Matthew Barth368e83c2019-02-01 13:48:25 -06004407
4408def getThermalZones(host, args, session):
4409 """
4410 Get the available thermal control zones
4411 @param host: string, the hostname or IP address of the bmc
4412 @param args: contains additional arguments used to get the thermal
4413 control zones
4414 @param session: the active session to use
4415 @return: Session object
4416 """
4417 url = "https://" + host + "/xyz/openbmc_project/control/thermal/enumerate"
4418
4419 try:
4420 res = session.get(url, headers=jsonHeader, verify=False, timeout=30)
4421 except(requests.exceptions.Timeout):
4422 return(connectionErrHandler(args.json, "Timeout", None))
4423 except(requests.exceptions.ConnectionError) as err:
4424 return connectionErrHandler(args.json, "ConnectionError", err)
4425 except(requests.exceptions.RequestException) as err:
4426 return connectionErrHandler(args.json, "RequestException", err)
4427
4428 if (res.status_code == 404):
Matthew Barth0939e822019-09-27 15:47:50 -05004429 return "No thermal control zones found"
Matthew Barth368e83c2019-02-01 13:48:25 -06004430
4431 zonesDict = json.loads(res.text)
4432 if not zonesDict['data']:
4433 return "No thermal control zones found"
4434 for zone in zonesDict['data']:
4435 z = ",".join(str(zone.split('/')[-1]) for zone in zonesDict['data'])
4436
4437 return "Zones: [ " + z + " ]"
4438
4439
4440def getThermalMode(host, args, session):
4441 """
4442 Get thermal control mode
4443 @param host: string, the hostname or IP address of the bmc
4444 @param args: contains additional arguments used to get the thermal
4445 control mode
4446 @param session: the active session to use
4447 @param args.zone: the zone to get the mode on
4448 @return: Session object
4449 """
4450 url = "https://" + host + "/xyz/openbmc_project/control/thermal/" + \
4451 args.zone
4452
4453 try:
4454 res = session.get(url, headers=jsonHeader, verify=False, timeout=30)
4455 except(requests.exceptions.Timeout):
4456 return(connectionErrHandler(args.json, "Timeout", None))
4457 except(requests.exceptions.ConnectionError) as err:
4458 return connectionErrHandler(args.json, "ConnectionError", err)
4459 except(requests.exceptions.RequestException) as err:
4460 return connectionErrHandler(args.json, "RequestException", err)
4461
4462 if (res.status_code == 404):
Matthew Barth0939e822019-09-27 15:47:50 -05004463 return "Thermal control zone(" + args.zone + ") not found"
Matthew Barth368e83c2019-02-01 13:48:25 -06004464
4465 propsDict = json.loads(res.text)
4466 if not propsDict['data']:
4467 return "No thermal control properties found on zone(" + args.zone + ")"
4468 curMode = "Current"
4469 supModes = "Supported"
4470 result = "\n"
4471 for prop in propsDict['data']:
4472 if (prop.casefold() == curMode.casefold()):
4473 result += curMode + " Mode: " + propsDict['data'][curMode] + "\n"
4474 if (prop.casefold() == supModes.casefold()):
4475 s = ", ".join(str(sup) for sup in propsDict['data'][supModes])
4476 result += supModes + " Modes: [ " + s + " ]\n"
4477
4478 return result
4479
4480def setThermalMode(host, args, session):
4481 """
4482 Set thermal control mode
4483 @param host: string, the hostname or IP address of the bmc
4484 @param args: contains additional arguments used for setting the thermal
4485 control mode
4486 @param session: the active session to use
4487 @param args.zone: the zone to set the mode on
4488 @param args.mode: the mode to enable
4489 @return: Session object
4490 """
4491 url = "https://" + host + "/xyz/openbmc_project/control/thermal/" + \
4492 args.zone + "/attr/Current"
4493
4494 # Check args.mode against supported modes using `getThermalMode` output
4495 modes = getThermalMode(host, args, session)
4496 modes = os.linesep.join([m for m in modes.splitlines() if m])
4497 modes = modes.replace("\n", ";").strip()
4498 modesDict = dict(m.split(': ') for m in modes.split(';'))
4499 sModes = ''.join(s for s in modesDict['Supported Modes'] if s not in '[ ]')
4500 if args.mode.casefold() not in \
4501 (m.casefold() for m in sModes.split(',')) or not args.mode:
4502 result = ("Unsupported mode('" + args.mode + "') given, " +
4503 "select a supported mode: \n" +
4504 getThermalMode(host, args, session))
4505 return result
4506
4507 data = '{"data":"' + args.mode + '"}'
4508 try:
4509 res = session.get(url, headers=jsonHeader, verify=False, timeout=30)
4510 except(requests.exceptions.Timeout):
4511 return(connectionErrHandler(args.json, "Timeout", None))
4512 except(requests.exceptions.ConnectionError) as err:
4513 return connectionErrHandler(args.json, "ConnectionError", err)
4514 except(requests.exceptions.RequestException) as err:
4515 return connectionErrHandler(args.json, "RequestException", err)
4516
4517 if (data and res.status_code != 404):
4518 try:
4519 res = session.put(url, headers=jsonHeader,
4520 data=data, verify=False,
4521 timeout=30)
4522 except(requests.exceptions.Timeout):
4523 return(connectionErrHandler(args.json, "Timeout", None))
4524 except(requests.exceptions.ConnectionError) as err:
4525 return connectionErrHandler(args.json, "ConnectionError", err)
4526 except(requests.exceptions.RequestException) as err:
4527 return connectionErrHandler(args.json, "RequestException", err)
4528
4529 if res.status_code == 403:
4530 return "The specified thermal control zone(" + args.zone + ")" + \
4531 " does not exist"
4532
4533 return res.text
4534 else:
4535 return "Setting thermal control mode(" + args.mode + ")" + \
Matthew Barth0939e822019-09-27 15:47:50 -05004536 " not supported or operation not available"
Matthew Barth368e83c2019-02-01 13:48:25 -06004537
4538
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004539def createCommandParser():
Justin Thalere412dc22018-01-12 16:28:24 -06004540 """
4541 creates the parser for the command line along with help for each command and subcommand
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004542
Justin Thalere412dc22018-01-12 16:28:24 -06004543 @return: returns the parser for the command line
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004544 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004545 parser = argparse.ArgumentParser(description='Process arguments')
Justin Thalere412dc22018-01-12 16:28:24 -06004546 parser.add_argument("-H", "--host", help='A hostname or IP for the BMC')
4547 parser.add_argument("-U", "--user", help='The username to login with')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004548 group = parser.add_mutually_exclusive_group()
4549 group.add_argument("-A", "--askpw", action='store_true', help='prompt for password')
4550 group.add_argument("-P", "--PW", help='Provide the password in-line')
Joseph Reynoldsa2d54c52019-06-11 22:02:57 -05004551 group.add_argument("-E", "--PWenvvar", action='store_true', help='Get password from envvar OPENBMCTOOL_PASSWORD')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004552 parser.add_argument('-j', '--json', action='store_true', help='output json data only')
4553 parser.add_argument('-t', '--policyTableLoc', help='The location of the policy table to parse alerts')
4554 parser.add_argument('-c', '--CerFormat', action='store_true', help=argparse.SUPPRESS)
4555 parser.add_argument('-T', '--procTime', action='store_true', help= argparse.SUPPRESS)
Justin Thalere412dc22018-01-12 16:28:24 -06004556 parser.add_argument('-V', '--version', action='store_true', help='Display the version number of the openbmctool')
4557 subparsers = parser.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004558
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004559 #fru command
4560 parser_inv = subparsers.add_parser("fru", help='Work with platform inventory')
Justin Thalere412dc22018-01-12 16:28:24 -06004561 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 -05004562 inv_subparser.required = True
4563 #fru print
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004564 inv_print = inv_subparser.add_parser("print", help="prints out a list of all FRUs")
4565 inv_print.set_defaults(func=fruPrint)
4566 #fru list [0....n]
4567 inv_list = inv_subparser.add_parser("list", help="print out details on selected FRUs. Specifying no items will list the entire inventory")
4568 inv_list.add_argument('items', nargs='?', help="print out details on selected FRUs. Specifying no items will list the entire inventory")
4569 inv_list.set_defaults(func=fruList)
4570 #fru status
4571 inv_status = inv_subparser.add_parser("status", help="prints out the status of all FRUs")
Justin Thalere412dc22018-01-12 16:28:24 -06004572 inv_status.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004573 inv_status.set_defaults(func=fruStatus)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004574
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004575 #sensors command
4576 parser_sens = subparsers.add_parser("sensors", help="Work with platform sensors")
Justin Thalere412dc22018-01-12 16:28:24 -06004577 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 -05004578 sens_subparser.required = True
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004579 #sensor print
4580 sens_print= sens_subparser.add_parser('print', help="prints out a list of all Sensors.")
4581 sens_print.set_defaults(func=sensor)
4582 #sensor list[0...n]
4583 sens_list=sens_subparser.add_parser("list", help="Lists all Sensors in the platform. Specify a sensor for full details. ")
4584 sens_list.add_argument("sensNum", nargs='?', help="The Sensor number to get full details on" )
4585 sens_list.set_defaults(func=sensor)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004586
Matthew Barth368e83c2019-02-01 13:48:25 -06004587 #thermal control commands
4588 parser_therm = subparsers.add_parser("thermal", help="Work with thermal control parameters")
4589 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')
4590 #thermal control zones
4591 parser_thermZones = therm_subparser.add_parser("zones", help="Get a list of available thermal control zones")
4592 parser_thermZones.set_defaults(func=getThermalZones)
4593 #thermal control modes
4594 parser_thermMode = therm_subparser.add_parser("modes", help="Work with thermal control modes")
4595 thermMode_sub = parser_thermMode.add_subparsers(title='subactions', description='Work with thermal control modes', help="Work with thermal control modes")
4596 #get thermal control mode
4597 parser_getThermMode = thermMode_sub.add_parser("get", help="Get current and supported thermal control modes")
4598 parser_getThermMode.add_argument('-z', '--zone', required=True, help='Thermal zone to work with')
4599 parser_getThermMode.set_defaults(func=getThermalMode)
4600 #set thermal control mode
4601 parser_setThermMode = thermMode_sub.add_parser("set", help="Set the thermal control mode")
4602 parser_setThermMode.add_argument('-z', '--zone', required=True, help='Thermal zone to work with')
4603 parser_setThermMode.add_argument('-m', '--mode', required=True, help='The supported thermal control mode')
4604 parser_setThermMode.set_defaults(func=setThermalMode)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004605
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004606 #sel command
4607 parser_sel = subparsers.add_parser("sel", help="Work with platform alerts")
Justin Thalere412dc22018-01-12 16:28:24 -06004608 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 -05004609 sel_subparser.required = True
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004610 #sel print
4611 sel_print = sel_subparser.add_parser("print", help="prints out a list of all sels in a condensed list")
4612 sel_print.add_argument('-d', '--devdebug', action='store_true', help=argparse.SUPPRESS)
4613 sel_print.add_argument('-v', '--verbose', action='store_true', help="Changes the output to being very verbose")
4614 sel_print.add_argument('-f', '--fileloc', help='Parse a file instead of the BMC output')
4615 sel_print.set_defaults(func=selPrint)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004616
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004617 #sel list
4618 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")
4619 sel_list.add_argument("selNum", nargs='?', type=int, help="The SEL entry to get details on")
4620 sel_list.set_defaults(func=selList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004621
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004622 sel_get = sel_subparser.add_parser("get", help="Gets the verbose details of a specified SEL entry")
4623 sel_get.add_argument('selNum', type=int, help="the number of the SEL entry to get")
4624 sel_get.set_defaults(func=selList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004625
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004626 sel_clear = sel_subparser.add_parser("clear", help="Clears all entries from the SEL")
4627 sel_clear.set_defaults(func=selClear)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004628
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004629 sel_setResolved = sel_subparser.add_parser("resolve", help="Sets the sel entry to resolved")
Justin Thalere412dc22018-01-12 16:28:24 -06004630 sel_setResolved.add_argument('-n', '--selNum', type=int, help="the number of the SEL entry to resolve")
4631 sel_ResolveAll_sub = sel_setResolved.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
4632 sel_ResolveAll = sel_ResolveAll_sub.add_parser('all', help='Resolve all SEL entries')
4633 sel_ResolveAll.set_defaults(func=selResolveAll)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004634 sel_setResolved.set_defaults(func=selSetResolved)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004635
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004636 parser_chassis = subparsers.add_parser("chassis", help="Work with chassis power and status")
Justin Thalere412dc22018-01-12 16:28:24 -06004637 chas_sub = parser_chassis.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004638
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004639 parser_chassis.add_argument('status', action='store_true', help='Returns the current status of the platform')
4640 parser_chassis.set_defaults(func=chassis)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004641
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004642 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 -06004643 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 -06004644 parser_chasPower.set_defaults(func=chassisPower)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004645
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004646 #control the chassis identify led
4647 parser_chasIdent = chas_sub.add_parser("identify", help="Control the chassis identify led")
4648 parser_chasIdent.add_argument('identcmd', choices=['on', 'off', 'status'], help='The control option for the led: on, off, blink, status')
4649 parser_chasIdent.set_defaults(func=chassisIdent)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004650
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004651 #collect service data
4652 parser_servData = subparsers.add_parser("collect_service_data", help="Collect all bmc data needed for service")
4653 parser_servData.add_argument('-d', '--devdebug', action='store_true', help=argparse.SUPPRESS)
4654 parser_servData.set_defaults(func=collectServiceData)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004655
Justin Thalere412dc22018-01-12 16:28:24 -06004656 #system quick health check
4657 parser_healthChk = subparsers.add_parser("health_check", help="Work with platform sensors")
4658 parser_healthChk.set_defaults(func=healthCheck)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004659
Ravi Tejad8be0b42020-03-18 14:31:46 -05004660 #work with dumps
4661 parser_bmcdump = subparsers.add_parser("dump", help="Work with dumps")
4662 parser_bmcdump.add_argument("-t", "--dumpType", default='bmc', choices=['bmc','SystemDump'],help="Type of dump")
Justin Thalere412dc22018-01-12 16:28:24 -06004663 bmcDump_sub = parser_bmcdump.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Justin Thaler53bf2f12018-07-16 14:05:32 -05004664 bmcDump_sub.required = True
Ravi Tejad8be0b42020-03-18 14:31:46 -05004665 dump_Create = bmcDump_sub.add_parser('create', help="Create a dump of given type")
4666 dump_Create.set_defaults(func=dumpCreate)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004667
Ravi Tejad8be0b42020-03-18 14:31:46 -05004668 dump_list = bmcDump_sub.add_parser('list', help="list all dumps")
4669 dump_list.set_defaults(func=dumpList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004670
Ravi Tejad8be0b42020-03-18 14:31:46 -05004671 parserdumpdelete = bmcDump_sub.add_parser('delete', help="Delete dump")
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004672 parserdumpdelete.add_argument("-n", "--dumpNum", nargs='*', type=int, help="The Dump entry to delete")
Ravi Tejad8be0b42020-03-18 14:31:46 -05004673 parserdumpdelete.set_defaults(func=dumpDelete)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004674
Justin Thalere412dc22018-01-12 16:28:24 -06004675 bmcDumpDelsub = parserdumpdelete.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Ravi Tejad8be0b42020-03-18 14:31:46 -05004676 deleteAllDumps = bmcDumpDelsub.add_parser('all', help='Delete all dumps')
4677 deleteAllDumps.set_defaults(func=dumpDeleteAll)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004678
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004679 parser_dumpretrieve = bmcDump_sub.add_parser('retrieve', help='Retrieve a dump file')
Ravi Tejad8be0b42020-03-18 14:31:46 -05004680 parser_dumpretrieve.add_argument("-n,", "--dumpNum", help="The Dump entry to retrieve")
4681 parser_dumpretrieve.add_argument("-s", "--dumpSaveLoc", help="The location to save the bmc dump file or file path for system dump")
4682 parser_dumpretrieve.set_defaults(func=dumpRetrieve)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004683
Justin Thaler22b1bb52018-03-15 13:31:32 -05004684 #bmc command for reseting the bmc
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004685 parser_bmc = subparsers.add_parser('bmc', help="Work with the bmc")
Justin Thalere412dc22018-01-12 16:28:24 -06004686 bmc_sub = parser_bmc.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004687 parser_BMCReset = bmc_sub.add_parser('reset', help='Reset the bmc' )
4688 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 -06004689 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.")
4690 parser_bmc.set_defaults(func=bmc)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004691
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004692 #add alias to the bmc command
4693 parser_mc = subparsers.add_parser('mc', help="Work with the management controller")
Justin Thalere412dc22018-01-12 16:28:24 -06004694 mc_sub = parser_mc.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004695 parser_MCReset = mc_sub.add_parser('reset', help='Reset the bmc' )
4696 parser_MCReset.add_argument('type', choices=['warm','cold'], help="Reboot the BMC")
4697 #parser_MCReset.add_argument('cold', action='store_true', help="Reboot the BMC and CLEAR the configuration")
4698 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 -06004699 parser_MCReset.set_defaults(func=bmcReset)
Justin Thalerf9aee3e2017-12-05 12:11:09 -06004700 parser_mc.set_defaults(func=bmc)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004701
Justin Thalere412dc22018-01-12 16:28:24 -06004702 #gard clear
4703 parser_gc = subparsers.add_parser("gardclear", help="Used to clear gard records")
4704 parser_gc.set_defaults(func=gardClear)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004705
Justin Thalere412dc22018-01-12 16:28:24 -06004706 #firmware_flash
4707 parser_fw = subparsers.add_parser("firmware", help="Work with the system firmware")
4708 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 -05004709 fwflash_subproc.required = True
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004710
Justin Thalere412dc22018-01-12 16:28:24 -06004711 fwflash = fwflash_subproc.add_parser('flash', help="Flash the system firmware")
4712 fwflash.add_argument('type', choices=['bmc', 'pnor'], help="image type to flash")
4713 fwflash.add_argument('-f', '--fileloc', required=True, help="The absolute path to the firmware image")
4714 fwflash.set_defaults(func=fwFlash)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004715
Justin Thaler22b1bb52018-03-15 13:31:32 -05004716 fwActivate = fwflash_subproc.add_parser('activate', help="Activate existing image on the bmc")
Justin Thalere412dc22018-01-12 16:28:24 -06004717 fwActivate.add_argument('imageID', help="The image ID to activate from the firmware list. Ex: 63c95399")
4718 fwActivate.set_defaults(func=activateFWImage)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004719
Justin Thaler22b1bb52018-03-15 13:31:32 -05004720 fwActivateStatus = fwflash_subproc.add_parser('activation_status', help="Check Status of activations")
4721 fwActivateStatus.set_defaults(func=activateStatus)
4722
Justin Thaler3d71d402018-07-24 14:35:39 -05004723 fwList = fwflash_subproc.add_parser('list', help="List all of the installed firmware")
4724 fwList.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
4725 fwList.set_defaults(func=firmwareList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004726
Justin Thaler3d71d402018-07-24 14:35:39 -05004727 fwprint = fwflash_subproc.add_parser('print', help="List all of the installed firmware")
4728 fwprint.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
4729 fwprint.set_defaults(func=firmwareList)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004730
Adriana Kobylak5af2fad2018-11-08 12:33:43 -06004731 fwDelete = fwflash_subproc.add_parser('delete', help="Delete an existing firmware version")
4732 fwDelete.add_argument('versionID', help="The version ID to delete from the firmware list. Ex: 63c95399")
4733 fwDelete.set_defaults(func=deleteFWVersion)
4734
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05004735 #logging
4736 parser_logging = subparsers.add_parser("logging", help="logging controls")
4737 logging_sub = parser_logging.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004738
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05004739 #turn rest api logging on/off
4740 parser_rest_logging = logging_sub.add_parser("rest_api", help="turn rest api logging on/off")
4741 parser_rest_logging.add_argument('rest_logging', choices=['on', 'off'], help='The control option for rest logging: on, off')
4742 parser_rest_logging.set_defaults(func=restLogging)
Deepak Kodihalli02d53282018-09-18 06:53:31 -05004743
4744 #remote logging
4745 parser_remote_logging = logging_sub.add_parser("remote_logging", help="Remote logging (rsyslog) commands")
4746 parser_remote_logging.add_argument('remote_logging', choices=['view', 'disable'], help='Remote logging (rsyslog) commands')
4747 parser_remote_logging.set_defaults(func=remoteLogging)
4748
4749 #configure remote logging
4750 parser_remote_logging_config = logging_sub.add_parser("remote_logging_config", help="Configure remote logging (rsyslog)")
4751 parser_remote_logging_config.add_argument("-a", "--address", required=True, help="Set IP address of rsyslog server")
4752 parser_remote_logging_config.add_argument("-p", "--port", required=True, type=int, help="Set Port of rsyslog server")
4753 parser_remote_logging_config.set_defaults(func=remoteLoggingConfig)
Dhruvaraj Subhashchandran64e7f6f2018-10-02 03:42:14 -05004754
4755 #certificate management
4756 parser_cert = subparsers.add_parser("certificate", help="Certificate management")
4757 certMgmt_subproc = parser_cert.add_subparsers(title='subcommands', description='valid certificate commands', help='sub-command help', dest='command')
4758
4759 certUpdate = certMgmt_subproc.add_parser('update', help="Update the certificate")
4760 certUpdate.add_argument('type', choices=['server', 'client', 'authority'], help="certificate type to update")
4761 certUpdate.add_argument('service', choices=['https', 'ldap'], help="Service to update")
4762 certUpdate.add_argument('-f', '--fileloc', required=True, help="The absolute path to the certificate file")
4763 certUpdate.set_defaults(func=certificateUpdate)
4764
4765 certDelete = certMgmt_subproc.add_parser('delete', help="Delete the certificate")
4766 certDelete.add_argument('type', choices=['server', 'client', 'authority'], help="certificate type to delete")
4767 certDelete.add_argument('service', choices=['https', 'ldap'], help="Service to delete the certificate")
4768 certDelete.set_defaults(func=certificateDelete)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06004769
Marri Devender Raodfe81ad2019-07-01 05:38:09 -05004770 certReplace = certMgmt_subproc.add_parser('replace',
4771 help="Replace the certificate")
4772 certReplace.add_argument('type', choices=['server', 'client', 'authority'],
4773 help="certificate type to replace")
4774 certReplace.add_argument('service', choices=['https', 'ldap'],
4775 help="Service to replace the certificate")
4776 certReplace.add_argument('-f', '--fileloc', required=True,
4777 help="The absolute path to the certificate file")
4778 certReplace.set_defaults(func=certificateReplace)
4779
Marri Devender Rao34646402019-07-01 05:46:03 -05004780 certDisplay = certMgmt_subproc.add_parser('display',
4781 help="Print the certificate")
4782 certDisplay.add_argument('type', choices=['server', 'client', 'authority'],
4783 help="certificate type to display")
4784 certDisplay.set_defaults(func=certificateDisplay)
4785
Marri Devender Raoa208ff82019-07-01 05:51:27 -05004786 certList = certMgmt_subproc.add_parser('list',
4787 help="Certificate list")
4788 certList.set_defaults(func=certificateList)
4789
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05004790 certGenerateCSR = certMgmt_subproc.add_parser('generatecsr', help="Generate CSR")
4791 certGenerateCSR.add_argument('type', choices=['server', 'client', 'authority'],
4792 help="Generate CSR")
4793 certGenerateCSR.add_argument('city',
4794 help="The city or locality of the organization making the request")
4795 certGenerateCSR.add_argument('commonName',
4796 help="The fully qualified domain name of the component that is being secured.")
4797 certGenerateCSR.add_argument('country',
4798 help="The country of the organization making the request")
4799 certGenerateCSR.add_argument('organization',
4800 help="The name of the organization making the request.")
4801 certGenerateCSR.add_argument('organizationUnit',
4802 help="The name of the unit or division of the organization making the request.")
4803 certGenerateCSR.add_argument('state',
4804 help="The state, province, or region of the organization making the request.")
4805 certGenerateCSR.add_argument('keyPairAlgorithm', choices=['RSA', 'EC'],
4806 help="The type of key pair for use with signing algorithms.")
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05004807 certGenerateCSR.add_argument('keyCurveId',
4808 help="The curve ID to be used with the key, if needed based on the value of the 'KeyPairAlgorithm' parameter.")
4809 certGenerateCSR.add_argument('contactPerson',
4810 help="The name of the user making the request")
4811 certGenerateCSR.add_argument('email',
4812 help="The email address of the contact within the organization")
4813 certGenerateCSR.add_argument('alternativeNames',
4814 help="Additional hostnames of the component that is being secured")
4815 certGenerateCSR.add_argument('givenname',
4816 help="The given name of the user making the request")
4817 certGenerateCSR.add_argument('surname',
4818 help="The surname of the user making the request")
4819 certGenerateCSR.add_argument('unstructuredname',
4820 help="he unstructured name of the subject")
4821 certGenerateCSR.add_argument('initials',
4822 help="The initials of the user making the request")
Marri Devender Rao3cdf8ae2019-07-01 06:01:40 -05004823 certGenerateCSR.set_defaults(func=certificateGenerateCSR)
4824
Matt Spinler7d426c22018-09-24 14:42:07 -05004825 # local users
4826 parser_users = subparsers.add_parser("local_users", help="Work with local users")
4827 parser_users.add_argument('local_users', choices=['disableall','enableall', 'queryenabled'], help="Disable, enable or query local user accounts")
4828 parser_users.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
4829 parser_users.set_defaults(func=localUsers)
4830
Ratan Gupta9166cd22018-10-01 18:09:40 +05304831 #LDAP
4832 parser_ldap = subparsers.add_parser("ldap", help="LDAP controls")
4833 ldap_sub = parser_ldap.add_subparsers(title='subcommands', description='valid subcommands',help="sub-command help", dest='command')
4834
4835 #configure and enable LDAP
4836 parser_ldap_config = ldap_sub.add_parser("enable", help="Configure and enables the LDAP")
4837 parser_ldap_config.add_argument("-a", "--uri", required=True, help="Set LDAP server URI")
4838 parser_ldap_config.add_argument("-B", "--bindDN", required=True, help="Set the bind DN of the LDAP server")
4839 parser_ldap_config.add_argument("-b", "--baseDN", required=True, help="Set the base DN of the LDAP server")
4840 parser_ldap_config.add_argument("-p", "--bindPassword", required=True, help="Set the bind password of the LDAP server")
4841 parser_ldap_config.add_argument("-S", "--scope", choices=['sub','one', 'base'],
4842 help='Specifies the search scope:subtree, one level or base object.')
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004843 parser_ldap_config.add_argument("-t", "--serverType", required=True, choices=['ActiveDirectory','OpenLDAP'],
Ratan Gupta9166cd22018-10-01 18:09:40 +05304844 help='Specifies the configured server is ActiveDirectory(AD) or OpenLdap')
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004845 parser_ldap_config.add_argument("-g","--groupAttrName", required=False, default='', help="Group Attribute Name")
4846 parser_ldap_config.add_argument("-u","--userAttrName", required=False, default='', help="User Attribute Name")
4847 parser_ldap_config.set_defaults(func=enableLDAPConfig)
Ratan Gupta9166cd22018-10-01 18:09:40 +05304848
4849 # disable LDAP
4850 parser_disable_ldap = ldap_sub.add_parser("disable", help="disables the LDAP")
4851 parser_disable_ldap.set_defaults(func=disableLDAP)
Nagaraju Goruganti7d1fe172018-11-13 06:09:29 -06004852 # view-config
4853 parser_ldap_config = \
4854 ldap_sub.add_parser("view-config", help="prints out a list of all \
4855 LDAPS's configured properties")
4856 parser_ldap_config.set_defaults(func=viewLDAPConfig)
Ratan Gupta9166cd22018-10-01 18:09:40 +05304857
Ratan Guptafeee6372018-10-17 23:25:51 +05304858 #create group privilege mapping
4859 parser_ldap_mapper = ldap_sub.add_parser("privilege-mapper", help="LDAP group privilege controls")
4860 parser_ldap_mapper_sub = parser_ldap_mapper.add_subparsers(title='subcommands', description='valid subcommands',
4861 help="sub-command help", dest='command')
4862
4863 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 -05004864 parser_ldap_mapper_create.add_argument("-t", "--serverType", choices=['ActiveDirectory','OpenLDAP'],
4865 help='Specifies the configured server is ActiveDirectory(AD) or OpenLdap')
Ratan Guptafeee6372018-10-17 23:25:51 +05304866 parser_ldap_mapper_create.add_argument("-g","--groupName",required=True,help="Group Name")
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004867 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 +05304868 parser_ldap_mapper_create.set_defaults(func=createPrivilegeMapping)
4869
4870 #list group privilege mapping
4871 parser_ldap_mapper_list = parser_ldap_mapper_sub.add_parser("list",help="List privilege mapping")
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004872 parser_ldap_mapper_list.add_argument("-t", "--serverType", choices=['ActiveDirectory','OpenLDAP'],
4873 help='Specifies the configured server is ActiveDirectory(AD) or OpenLdap')
Ratan Guptafeee6372018-10-17 23:25:51 +05304874 parser_ldap_mapper_list.set_defaults(func=listPrivilegeMapping)
4875
4876 #delete group privilege mapping
4877 parser_ldap_mapper_delete = parser_ldap_mapper_sub.add_parser("delete",help="Delete privilege mapping")
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004878 parser_ldap_mapper_delete.add_argument("-t", "--serverType", choices=['ActiveDirectory','OpenLDAP'],
4879 help='Specifies the configured server is ActiveDirectory(AD) or OpenLdap')
Ratan Guptafeee6372018-10-17 23:25:51 +05304880 parser_ldap_mapper_delete.add_argument("-g","--groupName",required=True,help="Group Name")
4881 parser_ldap_mapper_delete.set_defaults(func=deletePrivilegeMapping)
4882
Sivas SRR78835272018-11-27 05:27:19 -06004883 #deleteAll group privilege mapping
4884 parser_ldap_mapper_delete = parser_ldap_mapper_sub.add_parser("purge",help="Delete All privilege mapping")
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05004885 parser_ldap_mapper_delete.add_argument("-t", "--serverType", choices=['ActiveDirectory','OpenLDAP'],
4886 help='Specifies the configured server is ActiveDirectory(AD) or OpenLdap')
Sivas SRR78835272018-11-27 05:27:19 -06004887 parser_ldap_mapper_delete.set_defaults(func=deleteAllPrivilegeMapping)
4888
Marri Devender Rao2c2a5162018-11-05 08:57:11 -06004889 # set local user password
4890 parser_set_password = subparsers.add_parser("set_password",
4891 help="Set password of local user")
4892 parser_set_password.add_argument( "-p", "--password", required=True,
4893 help="Password of local user")
4894 parser_set_password.set_defaults(func=setPassword)
4895
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004896 # network
4897 parser_nw = subparsers.add_parser("network", help="network controls")
4898 nw_sub = parser_nw.add_subparsers(title='subcommands',
4899 description='valid subcommands',
4900 help="sub-command help",
4901 dest='command')
4902
4903 # enable DHCP
4904 parser_enable_dhcp = nw_sub.add_parser("enableDHCP",
4905 help="enables the DHCP on given "
4906 "Interface")
4907 parser_enable_dhcp.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004908 help="Name of the ethernet interface(it can"
4909 "be obtained by the "
4910 "command:network view-config)"
4911 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004912 parser_enable_dhcp.set_defaults(func=enableDHCP)
4913
4914 # disable DHCP
4915 parser_disable_dhcp = nw_sub.add_parser("disableDHCP",
4916 help="disables the DHCP on given "
4917 "Interface")
4918 parser_disable_dhcp.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004919 help="Name of the ethernet interface(it can"
4920 "be obtained by the "
4921 "command:network view-config)"
4922 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004923 parser_disable_dhcp.set_defaults(func=disableDHCP)
4924
4925 # get HostName
4926 parser_gethostname = nw_sub.add_parser("getHostName",
4927 help="prints out HostName")
4928 parser_gethostname.set_defaults(func=getHostname)
4929
4930 # set HostName
4931 parser_sethostname = nw_sub.add_parser("setHostName", help="sets HostName")
4932 parser_sethostname.add_argument("-H", "--HostName", required=True,
4933 help="A HostName for the BMC")
4934 parser_sethostname.set_defaults(func=setHostname)
4935
4936 # get domainname
4937 parser_getdomainname = nw_sub.add_parser("getDomainName",
4938 help="prints out DomainName of "
4939 "given Interface")
4940 parser_getdomainname.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004941 help="Name of the ethernet interface(it "
4942 "can be obtained by the "
4943 "command:network view-config)"
4944 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004945 parser_getdomainname.set_defaults(func=getDomainName)
4946
4947 # set domainname
4948 parser_setdomainname = nw_sub.add_parser("setDomainName",
4949 help="sets DomainName of given "
4950 "Interface")
4951 parser_setdomainname.add_argument("-D", "--DomainName", required=True,
4952 help="Ex: DomainName=Domain1,Domain2,...")
4953 parser_setdomainname.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004954 help="Name of the ethernet interface(it "
4955 "can be obtained by the "
4956 "command:network view-config)"
4957 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004958 parser_setdomainname.set_defaults(func=setDomainName)
4959
4960 # get MACAddress
4961 parser_getmacaddress = nw_sub.add_parser("getMACAddress",
4962 help="prints out MACAddress the "
4963 "given Interface")
4964 parser_getmacaddress.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004965 help="Name of the ethernet interface(it "
4966 "can be obtained by the "
4967 "command:network view-config)"
4968 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004969 parser_getmacaddress.set_defaults(func=getMACAddress)
4970
4971 # set MACAddress
4972 parser_setmacaddress = nw_sub.add_parser("setMACAddress",
4973 help="sets MACAddress")
4974 parser_setmacaddress.add_argument("-MA", "--MACAddress", required=True,
4975 help="A MACAddress for the given "
4976 "Interface")
4977 parser_setmacaddress.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06004978 help="Name of the ethernet interface(it can"
4979 "be obtained by the "
4980 "command:network view-config)"
4981 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06004982 parser_setmacaddress.set_defaults(func=setMACAddress)
4983
4984 # get DefaultGW
4985 parser_getdefaultgw = nw_sub.add_parser("getDefaultGW",
4986 help="prints out DefaultGateway "
4987 "the BMC")
4988 parser_getdefaultgw.set_defaults(func=getDefaultGateway)
4989
4990 # set DefaultGW
4991 parser_setdefaultgw = nw_sub.add_parser("setDefaultGW",
4992 help="sets DefaultGW")
4993 parser_setdefaultgw.add_argument("-GW", "--DefaultGW", required=True,
4994 help="A DefaultGateway for the BMC")
4995 parser_setdefaultgw.set_defaults(func=setDefaultGateway)
4996
4997 # view network Config
4998 parser_ldap_config = nw_sub.add_parser("view-config", help="prints out a "
4999 "list of all network's configured "
5000 "properties")
5001 parser_ldap_config.set_defaults(func=viewNWConfig)
5002
5003 # get DNS
5004 parser_getDNS = nw_sub.add_parser("getDNS",
5005 help="prints out DNS servers on the "
5006 "given interface")
5007 parser_getDNS.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06005008 help="Name of the ethernet interface(it can"
5009 "be obtained by the "
5010 "command:network view-config)"
5011 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06005012 parser_getDNS.set_defaults(func=getDNS)
5013
5014 # set DNS
5015 parser_setDNS = nw_sub.add_parser("setDNS",
5016 help="sets DNS servers on the given "
5017 "interface")
5018 parser_setDNS.add_argument("-d", "--DNSServers", required=True,
5019 help="Ex: DNSSERVERS=DNS1,DNS2,...")
5020 parser_setDNS.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06005021 help="Name of the ethernet interface(it can"
5022 "be obtained by the "
5023 "command:network view-config)"
5024 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06005025 parser_setDNS.set_defaults(func=setDNS)
5026
5027 # get NTP
5028 parser_getNTP = nw_sub.add_parser("getNTP",
5029 help="prints out NTP servers on the "
5030 "given interface")
5031 parser_getNTP.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06005032 help="Name of the ethernet interface(it can"
5033 "be obtained by the "
5034 "command:network view-config)"
5035 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06005036 parser_getNTP.set_defaults(func=getNTP)
5037
5038 # set NTP
5039 parser_setNTP = nw_sub.add_parser("setNTP",
5040 help="sets NTP servers on the given "
5041 "interface")
5042 parser_setNTP.add_argument("-N", "--NTPServers", required=True,
5043 help="Ex: NTPSERVERS=NTP1,NTP2,...")
5044 parser_setNTP.add_argument("-I", "--Interface", required=True,
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06005045 help="Name of the ethernet interface(it can"
5046 "be obtained by the "
5047 "command:network view-config)"
5048 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
Nagaraju Goruganti9908bcf2018-11-14 22:07:25 -06005049 parser_setNTP.set_defaults(func=setNTP)
5050
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06005051 # configure IP
5052 parser_ip_config = nw_sub.add_parser("addIP", help="Sets IP address to"
5053 "given interface")
5054 parser_ip_config.add_argument("-a", "--address", required=True,
5055 help="IP address of given interface")
5056 parser_ip_config.add_argument("-gw", "--gateway", required=False, default='',
5057 help="The gateway for given interface")
5058 parser_ip_config.add_argument("-l", "--prefixLength", required=True,
5059 help="The prefixLength of IP address")
Sunitha Harish0baf6372019-07-31 03:59:03 -05005060 parser_ip_config.add_argument("-p", "--type", required=True,
5061 choices=['ipv4', 'ipv6'],
Nagaraju Goruganti97a20602018-11-16 03:06:08 -06005062 help="The protocol type of the given"
5063 "IP address")
5064 parser_ip_config.add_argument("-I", "--Interface", required=True,
5065 help="Name of the ethernet interface(it can"
5066 "be obtained by the "
5067 "command:network view-config)"
5068 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
5069 parser_ip_config.set_defaults(func=addIP)
5070
5071 # getIP
5072 parser_getIP = nw_sub.add_parser("getIP", help="prints out IP address"
5073 "of given interface")
5074 parser_getIP.add_argument("-I", "--Interface", required=True,
5075 help="Name of the ethernet interface(it can"
5076 "be obtained by the command:network view-config)"
5077 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
5078 parser_getIP.set_defaults(func=getIP)
5079
5080 # rmIP
5081 parser_rmIP = nw_sub.add_parser("rmIP", help="deletes IP address"
5082 "of given interface")
5083 parser_rmIP.add_argument("-a", "--address", required=True,
5084 help="IP address to remove form given Interface")
5085 parser_rmIP.add_argument("-I", "--Interface", required=True,
5086 help="Name of the ethernet interface(it can"
5087 "be obtained by the command:network view-config)"
5088 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
5089 parser_rmIP.set_defaults(func=deleteIP)
5090
Nagaraju Gorugantif21d43c2018-11-19 10:47:19 -06005091 # add VLAN
5092 parser_create_vlan = nw_sub.add_parser("addVLAN", help="enables VLAN "
5093 "on given interface with given "
5094 "VLAN Identifier")
5095 parser_create_vlan.add_argument("-I", "--Interface", required=True,
5096 choices=['eth0', 'eth1'],
5097 help="Name of the ethernet interface")
5098 parser_create_vlan.add_argument("-n", "--Identifier", required=True,
5099 help="VLAN Identifier")
5100 parser_create_vlan.set_defaults(func=addVLAN)
5101
5102 # delete VLAN
5103 parser_delete_vlan = nw_sub.add_parser("deleteVLAN", help="disables VLAN "
5104 "on given interface with given "
5105 "VLAN Identifier")
5106 parser_delete_vlan.add_argument("-I", "--Interface", required=True,
5107 help="Name of the ethernet interface(it can"
5108 "be obtained by the "
5109 "command:network view-config)"
5110 "Ex: eth0 or eth1 or VLAN(VLAN=eth0_50 etc)")
5111 parser_delete_vlan.set_defaults(func=deleteVLAN)
5112
5113 # viewDHCPConfig
5114 parser_viewDHCPConfig = nw_sub.add_parser("viewDHCPConfig",
5115 help="Shows DHCP configured "
5116 "Properties")
5117 parser_viewDHCPConfig.set_defaults(func=viewDHCPConfig)
5118
5119 # configureDHCP
5120 parser_configDHCP = nw_sub.add_parser("configureDHCP",
5121 help="Configures/updates DHCP "
5122 "Properties")
5123 parser_configDHCP.add_argument("-d", "--DNSEnabled", type=str2bool,
5124 required=True, help="Sets DNSEnabled property")
5125 parser_configDHCP.add_argument("-n", "--HostNameEnabled", type=str2bool,
5126 required=True,
5127 help="Sets HostNameEnabled property")
5128 parser_configDHCP.add_argument("-t", "--NTPEnabled", type=str2bool,
5129 required=True,
5130 help="Sets NTPEnabled property")
5131 parser_configDHCP.add_argument("-s", "--SendHostNameEnabled", type=str2bool,
5132 required=True,
5133 help="Sets SendHostNameEnabled property")
5134 parser_configDHCP.set_defaults(func=configureDHCP)
5135
5136 # network factory reset
5137 parser_nw_reset = nw_sub.add_parser("nwReset",
5138 help="Resets networks setting to "
5139 "factory defaults. "
5140 "note:Reset settings will be applied "
5141 "after BMC reboot")
5142 parser_nw_reset.set_defaults(func=nwReset)
5143
Justin Thalerf9aee3e2017-12-05 12:11:09 -06005144 return parser
5145
Justin Thalerf9aee3e2017-12-05 12:11:09 -06005146def main(argv=None):
Justin Thalere412dc22018-01-12 16:28:24 -06005147 """
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06005148 main function for running the command line utility as a sub application
5149 """
5150 global toolVersion
Joy Onyerikwu182c3a32019-10-15 08:33:59 -05005151 toolVersion = "1.18"
Sunitha Harishc99faba2019-07-19 06:55:22 -05005152 global isRedfishSupport
RAJESWARAN THILLAIGOVINDAN87f087b2019-05-08 04:15:26 -05005153
Justin Thalerf9aee3e2017-12-05 12:11:09 -06005154 parser = createCommandParser()
Justin Thalerf9aee3e2017-12-05 12:11:09 -06005155 args = parser.parse_args(argv)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06005156
Justin Thalerf9aee3e2017-12-05 12:11:09 -06005157 totTimeStart = int(round(time.time()*1000))
5158
5159 if(sys.version_info < (3,0)):
5160 urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
5161 if sys.version_info >= (3,0):
5162 requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)
Justin Thalere412dc22018-01-12 16:28:24 -06005163 if (args.version):
Justin Thaler22b1bb52018-03-15 13:31:32 -05005164 print("Version: "+ toolVersion)
Justin Thalere412dc22018-01-12 16:28:24 -06005165 sys.exit(0)
5166 if (hasattr(args, 'fileloc') and args.fileloc is not None and 'print' in args.command):
Justin Thalerf9aee3e2017-12-05 12:11:09 -06005167 mysess = None
Justin Thalere412dc22018-01-12 16:28:24 -06005168 print(selPrint('N/A', args, mysess))
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06005169 else:
Justin Thalere412dc22018-01-12 16:28:24 -06005170 if(hasattr(args, 'host') and hasattr(args,'user')):
5171 if (args.askpw):
5172 pw = getpass.getpass()
5173 elif(args.PW is not None):
5174 pw = args.PW
Joseph Reynoldsa2d54c52019-06-11 22:02:57 -05005175 elif(args.PWenvvar):
5176 pw = os.environ['OPENBMCTOOL_PASSWORD']
Justin Thalere412dc22018-01-12 16:28:24 -06005177 else:
5178 print("You must specify a password")
5179 sys.exit()
5180 logintimeStart = int(round(time.time()*1000))
Joy Onyerikwu182c3a32019-10-15 08:33:59 -05005181 mysess = login(args.host, args.user, pw, args.json,
5182 args.command == 'set_password')
Sunitha Harish336cda22019-07-23 02:02:52 -05005183 if(mysess == None):
5184 print("Login Failed!")
5185 sys.exit()
Justin Thalera9415b42018-05-25 19:40:13 -05005186 if(sys.version_info < (3,0)):
5187 if isinstance(mysess, basestring):
5188 print(mysess)
5189 sys.exit(1)
5190 elif sys.version_info >= (3,0):
5191 if isinstance(mysess, str):
5192 print(mysess)
5193 sys.exit(1)
Justin Thalere412dc22018-01-12 16:28:24 -06005194 logintimeStop = int(round(time.time()*1000))
Sunitha Harishc99faba2019-07-19 06:55:22 -05005195 isRedfishSupport = redfishSupportPresent(args.host,mysess)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06005196 commandTimeStart = int(round(time.time()*1000))
Justin Thalere412dc22018-01-12 16:28:24 -06005197 output = args.func(args.host, args, mysess)
5198 commandTimeStop = int(round(time.time()*1000))
Justin Thaler761484a2019-03-26 19:20:23 -05005199 if isinstance(output, dict):
5200 print(json.dumps(output, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False))
5201 else:
5202 print(output)
Justin Thalere412dc22018-01-12 16:28:24 -06005203 if (mysess is not None):
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06005204 logout(args.host, args.user, pw, mysess, args.json)
5205 if(args.procTime):
Justin Thalere412dc22018-01-12 16:28:24 -06005206 print("Total time: " + str(int(round(time.time()*1000))- totTimeStart))
5207 print("loginTime: " + str(logintimeStop - logintimeStart))
5208 print("command Time: " + str(commandTimeStop - commandTimeStart))
5209 else:
Joseph Reynoldsa2d54c52019-06-11 22:02:57 -05005210 print("usage:\n"
5211 " OPENBMCTOOL_PASSWORD=secret # if using -E\n"
5212 " openbmctool.py [-h] -H HOST -U USER {-A | -P PW | -E} [-j]\n" +
Justin Thalere412dc22018-01-12 16:28:24 -06005213 "\t[-t POLICYTABLELOC] [-V]\n" +
Deepak Kodihalli22d4df02018-09-18 06:52:43 -05005214 "\t{fru,sensors,sel,chassis,collect_service_data, \
5215 health_check,dump,bmc,mc,gardclear,firmware,logging}\n" +
Justin Thalere412dc22018-01-12 16:28:24 -06005216 "\t...\n" +
5217 "openbmctool.py: error: the following arguments are required: -H/--host, -U/--user")
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06005218 sys.exit()
Justin Thalerf9aee3e2017-12-05 12:11:09 -06005219
Justin Thalerf9aee3e2017-12-05 12:11:09 -06005220if __name__ == '__main__':
Justin Thalere412dc22018-01-12 16:28:24 -06005221 """
5222 main function when called from the command line
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06005223
5224 """
Justin Thalerf9aee3e2017-12-05 12:11:09 -06005225 import sys
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -06005226
Justin Thalerf9aee3e2017-12-05 12:11:09 -06005227 isTTY = sys.stdout.isatty()
5228 assert sys.version_info >= (2,7)
5229 main()