idrac 0.1.31 → 0.1.38

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/idrac.py DELETED
@@ -1,500 +0,0 @@
1
- #!/usr/bin/python3
2
- #
3
- # DeviceFirmwareSimpleUpdateREDFISH. Python script using Redfish API to update a device firmware with DMTF action SimpleUpdate. Supported file image types are Windows DUPs, d7/d9 image or pm files.
4
- #
5
- # _author_ = Texas Roemer <Texas_Roemer@Dell.com>
6
- # _version_ = 21.0
7
- #
8
- # Copyright (c) 2018, Dell, Inc.
9
- #
10
- # This software is licensed to you under the GNU General Public License,
11
- # version 2 (GPLv2). There is NO WARRANTY for this software, express or
12
- # implied, including the implied warranties of MERCHANTABILITY or FITNESS
13
- # FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
14
- # along with this software; if not, see
15
- # http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
16
- #
17
-
18
- import argparse
19
- import getpass
20
- import json
21
- import logging
22
- import os
23
- import platform
24
- import re
25
- import requests
26
- import subprocess
27
- import sys
28
- import time
29
- import warnings
30
-
31
- from datetime import datetime
32
- from pprint import pprint
33
-
34
- warnings.filterwarnings("ignore")
35
-
36
-
37
- parser=argparse.ArgumentParser(description="Python script using Redfish API to update device firmware using DMTF standard action SimpleUpdate from a local directory. Note this script is only supported on iDRAC9 or older versions.")
38
- parser.add_argument('-ip',help='iDRAC IP address', required=False)
39
- parser.add_argument('-u', help='iDRAC username', required=False)
40
- parser.add_argument('-p', help='iDRAC password. If you do not pass in argument -p, script will prompt to enter user password which will not be echoed to the screen.', required=False)
41
- parser.add_argument('-x', help='Pass in X-Auth session token for executing Redfish calls. All Redfish calls will use X-Auth token instead of username/password', required=False)
42
- parser.add_argument('--ssl', help='SSL cert verification for all Redfish calls, pass in value \"true\" or \"false\". By default, this argument is not required and script ignores validating SSL cert for all Redfish calls.', required=False)
43
- parser.add_argument('--script-examples', action="store_true", help='Prints script examples')
44
- parser.add_argument('--get', help='Get current supported devices for firmware updates and their current firmware versions', action="store_true", required=False)
45
- parser.add_argument('--location', help='Pass in the local directory location of the firmware image', required=False)
46
- parser.add_argument('--image', help='Pass in the firmware image name', required=False)
47
- parser.add_argument('--reboot', help='Reboot the server to apply the update if needed. if argument not passed in, job ID will still be in scheduled state and execute on next manual server reboot. Note: If the update gets applied with no server reboot (Example: iDRAC, DIAGs, Driver pack), you don\'t need to pass in this argument. For more details on which devices update immediately, refer to Lifecycle Controller User Guide Update section.', action="store_true", required=False)
48
- parser.add_argument('--final-shutdown', help='Shutdown the server once the firmware update completes', dest="final_shutdown", required=False)
49
-
50
- args=vars(parser.parse_args())
51
- logging.basicConfig(format='%(message)s', stream=sys.stdout, level=logging.INFO)
52
-
53
- def script_examples():
54
- print("""\n- DeviceFirmwareSimpleUpdateREDFISH.py -ip 192.168.0.120 -u root -p calvin --get, this example will return current firmware versions for all devices supported for updates.
55
- \n- DeviceFirmwareSimpleUpdateREDFISH.py -ip 192.168.0.120 -u root -p calvin --location C:\\Downloads --image BIOS_422T0_WN64_1.4.9.EXE --reboot, this example will update BIOS firmware which BIOS DUP is located in C:\\Downloads directory
56
- \n- DeviceFirmwareSimpleUpdateREDFISH.py -ip 192.168.0.120 -u root -p calvin --location C:\\Downloads --image iDRAC-with-Lifecycle-Controller_Firmware_FPTF1_WN64_5.10.10.00_A00.EXE, this example will update iDRAC firmware immediately, no reboot needed since iDRAC is direct update.""")
57
- sys.exit(0)
58
-
59
- def check_supported_idrac_version():
60
- if args["x"]:
61
- response = requests.get('https://%s/redfish/v1/UpdateService' % idrac_ip, verify=verify_cert, headers={'X-Auth-Token': args["x"]})
62
- else:
63
- response = requests.get('https://%s/redfish/v1/UpdateService' % idrac_ip, verify=verify_cert, auth=(idrac_username, idrac_password))
64
- data = response.json()
65
- if response.status_code == 401:
66
- logging.warning("\n- WARNING, status code %s returned, check your iDRAC username/password is correct or iDRAC user has correct privileges to execute Redfish commands" % response.status_code)
67
- sys.exit(0)
68
- if response.status_code != 200:
69
- logging.warning("\n- WARNING, GET command failed to check supported iDRAC version, status code %s returned" % response.status_code)
70
- sys.exit(0)
71
- if idrac_version >= 10:
72
- logging.warning("\n- WARNING, iDRAC version detected does not support SimpleUpdate using HttpPushUri, please use either SimpleUpdate with ImageURI or MultpartUpload to perform firmware update")
73
- sys.exit(0)
74
-
75
-
76
- def get_server_generation():
77
- global idrac_version
78
- if args["x"]:
79
- response = requests.get('https://%s/redfish/v1/Managers/iDRAC.Embedded.1?$select=Model' % idrac_ip, verify=verify_cert, headers={'X-Auth-Token': args["x"]})
80
- else:
81
- response = requests.get('https://%s/redfish/v1/Managers/iDRAC.Embedded.1?$select=Model' % idrac_ip, verify=False,auth=(idrac_username,idrac_password))
82
- data = response.json()
83
- if response.status_code == 401:
84
- logging.error("\n- ERROR, status code 401 detected, check to make sure your iDRAC script session has correct username/password credentials or if using X-auth token, confirm the session is still active.")
85
- sys.exit(0)
86
- elif response.status_code != 200:
87
- logging.warning("\n- WARNING, unable to get current iDRAC version installed")
88
- sys.exit(0)
89
- if "12" in data["Model"] or "13" in data["Model"]:
90
- idrac_version = 8
91
- elif "14" in data["Model"] or "15" in data["Model"] or "16" in data["Model"]:
92
- idrac_version = 9
93
- else:
94
- idrac_version = 10
95
-
96
- def get_idrac_version():
97
- global idrac_fw_version
98
- if args["x"]:
99
- response = requests.get('https://%s/redfish/v1/Managers/iDRAC.Embedded.1?$select=FirmwareVersion' % idrac_ip, verify=verify_cert, headers={'X-Auth-Token': args["x"]})
100
- else:
101
- response = requests.get('https://%s/redfish/v1/Managers/iDRAC.Embedded.1?$select=FirmwareVersion' % idrac_ip, verify=verify_cert, auth=(idrac_username, idrac_password))
102
- data = response.json()
103
- if response.status_code != 200:
104
- logging.error("\n- FAIL, GET request failed to get iDRAC firmware version, error: \n%s" % data)
105
- sys.exit(0)
106
- idrac_fw_version = data["FirmwareVersion"].replace(".","")
107
-
108
- def get_FW_inventory():
109
- logging.info("\n- INFO, getting current firmware inventory for iDRAC %s -\n" % idrac_ip)
110
- if args["x"]:
111
- response = requests.get('https://%s/redfish/v1/UpdateService/FirmwareInventory?$expand=*($levels=1)' % idrac_ip, verify=verify_cert, headers={'X-Auth-Token': args["x"]})
112
- else:
113
- response = requests.get('https://%s/redfish/v1/UpdateService/FirmwareInventory?$expand=*($levels=1)' % idrac_ip, verify=verify_cert, auth=(idrac_username, idrac_password))
114
- data = response.json()
115
- if response.status_code != 200:
116
- logging.error("\n- ERROR, GET request failed to get firmware inventory, error: \n%s" % data)
117
- sys.exit(0)
118
- installed_devices = []
119
- for i in data['Members']:
120
- pprint(i)
121
- print("\n")
122
-
123
- def download_image_payload():
124
- global available_entry
125
- global http_push_uri
126
- global start_time
127
- start_time = datetime.now()
128
- logging.info("\n- INFO, downloading \"%s\" image, this may take a few minutes depending on the size of the payload" % args["image"])
129
- if args["x"]:
130
- response = requests.get('https://%s/redfish/v1/UpdateService' % idrac_ip, verify=verify_cert, headers={'X-Auth-Token': args["x"]})
131
- else:
132
- response = requests.get('https://%s/redfish/v1/UpdateService' % idrac_ip, verify=verify_cert, auth=(idrac_username, idrac_password))
133
- data = response.json()
134
- try:
135
- http_push_uri = data['HttpPushUri']
136
- except:
137
- http_push_uri = "/redfish/v1/UpdateService/FirmwareInventory"
138
- if args["x"]:
139
- response = requests.get('https://%s%s' % (idrac_ip, http_push_uri), verify=verify_cert, headers={'X-Auth-Token': args["x"]})
140
- else:
141
- response = requests.get('https://%s%s' % (idrac_ip, http_push_uri), verify=verify_cert, auth=(idrac_username, idrac_password))
142
- data = response.json()
143
- ImageLocation = args["location"]
144
- filename = args["image"]
145
- ImagePath = os.path.join(ImageLocation, filename)
146
- ETag = response.headers['ETag']
147
- url = 'https://%s%s' % (idrac_ip, http_push_uri)
148
- files = {'file': (filename, open(ImagePath, 'rb'), 'multipart/form-data')}
149
- if args["x"]:
150
- headers = {'X-Auth-Token': args["x"], "if-match": ETag}
151
- response = requests.post(url, files=files, headers=headers, verify=verify_cert)
152
- else:
153
- headers = {"if-match": ETag}
154
- response = requests.post(url, files=files, verify=verify_cert,auth=(idrac_username,idrac_password), headers=headers)
155
- try:
156
- post_command_response_output = response.json()
157
- except:
158
- logging.error("- FAIL, SimpleUpdate using HttpPushUri is not supported on this iDRAC release")
159
- sys.exit(0)
160
- if response.status_code == 201:
161
- logging.info("\n- PASS: POST command passed successfully to download image")
162
- else:
163
- logging.error("\n- FAIL: POST command failed to download image payload, status code %s returned" % response.status_code)
164
- logging.error(post_command_response_output)
165
- sys.exit(0)
166
- available_entry = post_command_response_output['Id']
167
- logging.info("- INFO, AVAILABLE entry created for download image \"%s\" is \"%s\"" % (filename, available_entry))
168
-
169
- def install_image_payload():
170
- global job_id
171
- url = 'https://%s/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate' % (idrac_ip)
172
- if args["reboot"]:
173
- payload = {"ImageURI":"%s/%s" % (http_push_uri, available_entry),"@Redfish.OperationApplyTime": "Immediate"}
174
- else:
175
- payload = {"ImageURI":"%s/%s" % (http_push_uri, available_entry),"@Redfish.OperationApplyTime": "OnReset"}
176
- if args["x"]:
177
- headers = {'content-type': 'application/json', 'X-Auth-Token': args["x"]}
178
- response = requests.post(url, data=json.dumps(payload), headers=headers, verify=verify_cert)
179
- else:
180
- headers = {'content-type': 'application/json'}
181
- response = requests.post(url, data=json.dumps(payload), headers=headers, verify=verify_cert,auth=(idrac_username,idrac_password))
182
- if response.status_code == 202 or response.status_code == 200:
183
- logging.info("- PASS, POST command passed for SimpleUpdate action, status code %s returned" % response.status_code)
184
- else:
185
- logging.error("\n- FAIL, Command failed to check job status, return code is %s" % response.status_code)
186
- loging.error("Extended Info Message: {0}".format(response.json()))
187
- sys.exit(0)
188
- try:
189
- job_id = response.headers['Location'].split("/")[-1]
190
- except:
191
- logging.error("- FAIL, unable to locate job ID in header")
192
- sys.exit(0)
193
- logging.info("- PASS, update job ID %s successfully created, script will now loop polling the job status\n" % job_id)
194
-
195
- def check_job_status():
196
- retry_count = 1
197
- schedule_job_status_count = 1
198
- while True:
199
- check_idrac_connection()
200
- if retry_count == 20:
201
- logging.warning("- WARNING, GET command retry count of 20 has been reached, script will exit")
202
- sys.exit(0)
203
- try:
204
- if args["x"]:
205
- response = requests.get('https://%s/redfish/v1/TaskService/Tasks/%s' % (idrac_ip, job_id), verify=verify_cert, headers={'X-Auth-Token': args["x"]})
206
- else:
207
- response = requests.get('https://%s/redfish/v1/TaskService/Tasks/%s' % (idrac_ip, job_id), verify=verify_cert, auth=(idrac_username, idrac_password))
208
- except requests.ConnectionError as error_message:
209
- logging.info("- INFO, GET request failed due to connection error, retry")
210
- time.sleep(10)
211
- retry_count += 1
212
- continue
213
- data = response.json()
214
- current_time = str(datetime.now()-start_time)[0:7]
215
- message_string = data["Messages"]
216
- if response.status_code == 200 or response.status_code == 202:
217
- time.sleep(1)
218
- else:
219
- logging.error("\n- ERROR, GET request failed to get job ID details, status code %s returned, error: \n%s" % (response.status_code, data))
220
- sys.exit(0)
221
- if data["TaskState"] == "Completed" and data["Oem"]["Dell"]["JobState"]:
222
- logging.info("\n- INFO, job completed, detailed final job status results\n")
223
- for i in data['Oem']['Dell'].items():
224
- pprint(i)
225
- logging.info("\n- JOB ID %s completed in %s" % (job_id, current_time))
226
- sys.exit(0)
227
- if data["TaskState"] == "UserIntervention" and data["PercentComplete"] == 100:
228
- logging.info("\n- JOB ID %s completed in %s but user intervention is needed, final job message: %s" % (job_id, current_time, message_string[0]["Message"].rstrip(".")))
229
- if args["reboot"]:
230
- if "reboot" in message_string[0]["Message"].lower():
231
- logging.info("- INFO, rebooting server for the new firmware installed to become effective")
232
- reboot_server()
233
- if "virtual" in message_string[0]["Message"].lower():
234
- logging.info("- INFO, server virtual a/c cycle is needed for the new firmware installed to become effective")
235
- sys.exit(0)
236
- if data["TaskState"] == "Completed":
237
- logging.info("\n- PASS, job ID successfuly marked completed, detailed final job status results\n")
238
- for i in data['Oem']['Dell'].items():
239
- pprint(i)
240
- logging.info("\n- JOB ID %s completed in %s" % (job_id, current_time))
241
- sys.exit(0)
242
- if str(current_time)[0:7] >= "0:30:00":
243
- logging.error("\n- FAIL: Timeout of 30 minutes has been hit, update job should of already been marked completed. Check the iDRAC job queue and LC logs to debug the issue\n")
244
- sys.exit(0)
245
- elif "failed" in data['Oem']['Dell']['Message'] or "completed with errors" in data['Oem']['Dell']['Message'] or "Failed" in data['Oem']['Dell']['Message']:
246
- logging.error("- FAIL: Job failed, current message: %s" % data["Messages"])
247
- sys.exit(0)
248
- elif "scheduled" in data['Oem']['Dell']['Message']:
249
- if schedule_job_status_count == 1:
250
- time.sleep(15)
251
- schedule_job_status_count += 1
252
- continue
253
- else:
254
- print("- PASS, job ID %s successfully marked as scheduled" % data["Id"])
255
- if not args["reboot"]:
256
- logging.warning("- WARNING, missing argument --reboot for rebooting the server. Job is still scheduled and will be applied on next manual server reboot")
257
- sys.exit(0)
258
- else:
259
- break
260
- else:
261
- logging.info("- INFO: %s, execution time: %s" % (message_string[0]["Message"].rstrip("."), current_time))
262
- time.sleep(1)
263
- continue
264
-
265
- def loop_check_final_job_status():
266
- retry_count = 1
267
- while True:
268
- if retry_count == 20:
269
- logging.warning("- WARNING, GET command retry count of 20 has been reached, script will exit")
270
- sys.exit(0)
271
- check_idrac_connection()
272
- try:
273
- if args["x"]:
274
- response = requests.get('https://%s/redfish/v1/Managers/iDRAC.Embedded.1/Jobs/%s' % (idrac_ip, job_id), verify=verify_cert, headers={'X-Auth-Token': args["x"]})
275
- else:
276
- response = requests.get('https://%s/redfish/v1/Managers/iDRAC.Embedded.1/Jobs/%s' % (idrac_ip, job_id), verify=verify_cert,auth=(idrac_username, idrac_password))
277
- except requests.ConnectionError as error_message:
278
- logging.info("- INFO, GET request failed due to connection error, retry")
279
- time.sleep(10)
280
- retry_count += 1
281
- continue
282
- current_time = str((datetime.now()-start_time))[0:7]
283
- if response.status_code != 200:
284
- logging.error("\n- FAIL, GET command failed to check job status, return code %s" % response.status_code)
285
- logging.error("Extended Info Message: {0}".format(response.json()))
286
- sys.exit(0)
287
- data = response.json()
288
- if str(current_time)[0:7] >= "0:50:00":
289
- logging.error("\n- FAIL: Timeout of 50 minutes has been hit, script stopped\n")
290
- sys.exit(0)
291
- elif "Fail" in data['Message'] or "fail" in data['Message'] or "fail" in data['JobState'] or "Fail" in data['JobState']:
292
- logging.error("- FAIL: job ID %s failed" % job_id)
293
- sys.exit(0)
294
- elif "success" in data['Message'].lower():
295
- logging.info("\n- PASS, job ID %s successfully marked completed" % job_id)
296
- logging.info("\n- Final detailed job results -\n")
297
- for i in data.items():
298
- pprint(i)
299
- logging.info("\n- JOB ID %s completed in %s" % (job_id, current_time))
300
- break
301
- else:
302
- logging.info("- INFO, %s, execution time: %s" % (data['Message'].rstrip("."), current_time))
303
- time.sleep(10)
304
-
305
- def reboot_server():
306
- if args["x"]:
307
- response = requests.get('https://%s/redfish/v1/Systems/System.Embedded.1' % idrac_ip, verify=verify_cert, headers={'X-Auth-Token': args["x"]})
308
- else:
309
- response = requests.get('https://%s/redfish/v1/Systems/System.Embedded.1' % idrac_ip, verify=verify_cert,auth=(idrac_username, idrac_password))
310
- data = response.json()
311
- logging.info("- INFO, Current server power state is: %s" % data['PowerState'])
312
- if data['PowerState'] == "On":
313
- url = 'https://%s/redfish/v1/Systems/System.Embedded.1/Actions/ComputerSystem.Reset' % idrac_ip
314
- payload = {'ResetType': 'GracefulShutdown'}
315
- if args["x"]:
316
- headers = {'content-type': 'application/json', 'X-Auth-Token': args["x"]}
317
- response = requests.post(url, data=json.dumps(payload), headers=headers, verify=verify_cert)
318
- else:
319
- headers = {'content-type': 'application/json'}
320
- response = requests.post(url, data=json.dumps(payload), headers=headers, verify=verify_cert,auth=(idrac_username,idrac_password))
321
- if response.status_code == 204:
322
- logging.info("- PASS, POST command passed to gracefully power OFF server")
323
- logging.info("- INFO, script will now verify the server was able to perform a graceful shutdown. If the server was unable to perform a graceful shutdown, forced shutdown will be invoked in 5 minutes")
324
- time.sleep(15)
325
- start_time = datetime.now()
326
- else:
327
- logging.error("\n- FAIL, Command failed to gracefully power OFF server, status code is: %s\n" % response.status_code)
328
- logging.error("Extended Info Message: {0}".format(response.json()))
329
- sys.exit(0)
330
- while True:
331
- if args["x"]:
332
- response = requests.get('https://%s/redfish/v1/Systems/System.Embedded.1' % idrac_ip, verify=verify_cert, headers={'X-Auth-Token': args["x"]})
333
- else:
334
- response = requests.get('https://%s/redfish/v1/Systems/System.Embedded.1' % idrac_ip, verify=verify_cert,auth=(idrac_username, idrac_password))
335
- data = response.json()
336
- current_time = str(datetime.now() - start_time)[0:7]
337
- if data['PowerState'] == "Off":
338
- logging.info("- PASS, GET command passed to verify graceful shutdown was successful and server is in OFF state")
339
- break
340
- elif current_time >= "0:05:00":
341
- logging.info("- INFO, unable to perform graceful shutdown, server will now perform forced shutdown")
342
- payload = {'ResetType': 'ForceOff'}
343
- if args["x"]:
344
- headers = {'content-type': 'application/json', 'X-Auth-Token': args["x"]}
345
- response = requests.post(url, data=json.dumps(payload), headers=headers, verify=verify_cert)
346
- else:
347
- headers = {'content-type': 'application/json'}
348
- response = requests.post(url, data=json.dumps(payload), headers=headers, verify=verify_cert,auth=(idrac_username,idrac_password))
349
- if response.status_code == 204:
350
- logging.info("- PASS, POST command passed to perform forced shutdown")
351
- time.sleep(15)
352
- if args["x"]:
353
- response = requests.get('https://%s/redfish/v1/Systems/System.Embedded.1' % idrac_ip, verify=verify_cert, headers={'X-Auth-Token': args["x"]})
354
- else:
355
- response = requests.get('https://%s/redfish/v1/Systems/System.Embedded.1' % idrac_ip, verify=verify_cert,auth=(idrac_username, idrac_password))
356
- data = response.json()
357
- if data['PowerState'] == "Off":
358
- logging.info("- PASS, GET command passed to verify forced shutdown was successful and server is in OFF state")
359
- break
360
- else:
361
- logging.error("- FAIL, server not in OFF state, current power status is %s" % data['PowerState'])
362
- sys.exit(0)
363
- else:
364
- continue
365
- payload = {'ResetType': 'On'}
366
- if args["x"]:
367
- headers = {'content-type': 'application/json', 'X-Auth-Token': args["x"]}
368
- response = requests.post(url, data=json.dumps(payload), headers=headers, verify=verify_cert)
369
- else:
370
- headers = {'content-type': 'application/json'}
371
- response = requests.post(url, data=json.dumps(payload), headers=headers, verify=verify_cert,auth=(idrac_username,idrac_password))
372
- if response.status_code == 204:
373
- logging.info("- PASS, POST command passed to power ON server")
374
- else:
375
- logging.error("\n- FAIL, Command failed to power ON server, status code is: %s\n" % response.status_code)
376
- logging.error("Extended Info Message: {0}".format(response.json()))
377
- sys.exit(0)
378
- elif data['PowerState'] == "Off":
379
- url = 'https://%s/redfish/v1/Systems/System.Embedded.1/Actions/ComputerSystem.Reset' % idrac_ip
380
- payload = {'ResetType': 'On'}
381
- if args["x"]:
382
- headers = {'content-type': 'application/json', 'X-Auth-Token': args["x"]}
383
- response = requests.post(url, data=json.dumps(payload), headers=headers, verify=verify_cert)
384
- else:
385
- headers = {'content-type': 'application/json'}
386
- response = requests.post(url, data=json.dumps(payload), headers=headers, verify=verify_cert,auth=(idrac_username,idrac_password))
387
- if response.status_code == 204:
388
- logging.info("- PASS, Command passed to power ON server, code return is %s" % response.status_code)
389
- else:
390
- logging.error("\n- FAIL, Command failed to power ON server, status code is: %s\n" % response.status_code)
391
- logging.error("Extended Info Message: {0}".format(response.json()))
392
- sys.exit(0)
393
- else:
394
- logging.error("- FAIL, unable to get current server power state to perform either reboot or power on")
395
- sys.exit(0)
396
-
397
- def check_idrac_connection():
398
- run_network_connection_function = ""
399
- if platform.system().lower() == "windows":
400
- ping_command = "ping -n 3 %s" % idrac_ip
401
- elif platform.system().lower() == "linux":
402
- ping_command = "ping -c 3 %s" % idrac_ip
403
- else:
404
- logging.error("- FAIL, unable to determine OS type, check iDRAC connection function will not execute")
405
- run_network_connection_function = "fail"
406
- execute_command = subprocess.call(ping_command, stdout=subprocess.PIPE, shell=True)
407
- if execute_command != 0:
408
- ping_status = "lost"
409
- else:
410
- ping_status = "good"
411
- pass
412
- if ping_status == "lost":
413
- logging.info("- INFO, iDRAC network connection lost due to slow network response, waiting 30 seconds to access iDRAC again")
414
- time.sleep(30)
415
- while True:
416
- if run_network_connection_function == "fail":
417
- break
418
- execute_command=subprocess.call(ping_command, stdout=subprocess.PIPE)
419
- if execute_command != 0:
420
- ping_status = "lost"
421
- else:
422
- ping_status = "good"
423
- if ping_status == "lost":
424
- logging.info("- INFO, unable to ping iDRAC IP, script will wait 30 seconds and try again")
425
- time.sleep(30)
426
- continue
427
- else:
428
- break
429
- while True:
430
- try:
431
- if args["x"]:
432
- response = requests.get('https://%s/redfish/v1/TaskService/Tasks/%s' % (idrac_ip, job_id), verify=verify_cert, headers={'X-Auth-Token': args["x"]})
433
- else:
434
- response = requests.get('https://%s/redfish/v1/TaskService/Tasks/%s' % (idrac_ip, job_id), verify=verify_cert, auth=(idrac_username, idrac_password))
435
- except requests.ConnectionError as error_message:
436
- logging.info("- INFO, GET request failed due to connection error, retry")
437
- time.sleep(10)
438
- continue
439
- break
440
-
441
- def shutdown_server():
442
- logging.info("- INFO, argument -S detected to shutdown the server after firmware update completes")
443
- url = 'https://%s/redfish/v1/Systems/System.Embedded.1/Actions/ComputerSystem.Reset' % idrac_ip
444
- payload = {'ResetType': 'ForceOff'}
445
- if args["x"]:
446
- headers = {'content-type': 'application/json', 'X-Auth-Token': args["x"]}
447
- response = requests.post(url, data=json.dumps(payload), headers=headers, verify=verify_cert)
448
- else:
449
- headers = {'content-type': 'application/json'}
450
- response = requests.post(url, data=json.dumps(payload), headers=headers, verify=verify_cert,auth=(idrac_username,idrac_password))
451
- if response.status_code == 204:
452
- logging.info("- PASS, POST action passed to power OFF server")
453
- else:
454
- logging.error("\n- FAIL, POST action failed to power OFF server, status code: %s\n" % statusCode)
455
- logging.error("Extended Info Message: {0}".format(response.json()))
456
- sys.exit(0)
457
-
458
- if __name__ == "__main__":
459
- if args["script_examples"]:
460
- script_examples()
461
- if args["ip"] or args["ssl"] or args["u"] or args["p"] or args["x"]:
462
- idrac_ip = args["ip"]
463
- idrac_username = args["u"]
464
- if args["p"]:
465
- idrac_password = args["p"]
466
- if not args["p"] and not args["x"] and args["u"]:
467
- idrac_password = getpass.getpass("\n- Argument -p not detected, pass in iDRAC user %s password: " % args["u"])
468
- if args["ssl"]:
469
- if args["ssl"].lower() == "true":
470
- verify_cert = True
471
- elif args["ssl"].lower() == "false":
472
- verify_cert = False
473
- else:
474
- verify_cert = False
475
- else:
476
- verify_cert = False
477
- get_server_generation()
478
- check_supported_idrac_version()
479
- else:
480
- logging.error("\n- FAIL, invalid argument values or not all required parameters passed in. See help text or argument --script-examples for more details.")
481
- sys.exit(0)
482
- if args["get"]:
483
- get_FW_inventory()
484
- elif args["location"] and args["image"]:
485
- get_idrac_version()
486
- download_image_payload()
487
- install_image_payload()
488
- check_job_status()
489
- sys.exit()
490
- if args["reboot"]:
491
- if int(idrac_fw_version[0]) >= 5:
492
- loop_check_final_job_status()
493
- else:
494
- print("- INFO, older iDRAC version detected, execute action ComputerSystem.Reset to reboot the server")
495
- reboot_server()
496
- loop_check_final_job_status()
497
- if args["final_shutdown"]:
498
- shutdown_server()
499
- else:
500
- logging.error("\n- FAIL, invalid argument values or not all required parameters passed in. See help text or argument --script-examples for more details.")
data/sig/idrac.rbs DELETED
@@ -1,4 +0,0 @@
1
- module Idrac
2
- VERSION: String
3
- # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
- end
@@ -1,68 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'lib/idrac'
4
- require 'colorize'
5
-
6
- # Create a client
7
- client = IDRAC::Client.new(
8
- host: '127.0.0.1',
9
- username: 'root',
10
- password: 'calvin',
11
- verify_ssl: false
12
- )
13
-
14
- begin
15
- # Login to iDRAC
16
- puts "Logging in to iDRAC...".light_cyan
17
- client.login
18
- puts "Logged in successfully".green
19
-
20
- # Create a firmware instance
21
- firmware = IDRAC::Firmware.new(client)
22
-
23
- # Get system inventory
24
- puts "Getting system inventory...".light_cyan
25
- inventory = firmware.get_system_inventory
26
-
27
- puts "System Information:".green.bold
28
- puts " Model: #{inventory[:system][:model]}".light_cyan
29
- puts " Manufacturer: #{inventory[:system][:manufacturer]}".light_cyan
30
- puts " Service Tag: #{inventory[:system][:service_tag]}".light_cyan
31
- puts " BIOS Version: #{inventory[:system][:bios_version]}".light_cyan
32
-
33
- puts "\nInstalled Firmware:".green.bold
34
- inventory[:firmware].each do |fw|
35
- puts " #{fw[:name]}: #{fw[:version]} (#{fw[:updateable] ? 'Updateable'.light_green : 'Not Updateable'.light_red})".light_cyan
36
- end
37
-
38
- # Check for updates
39
- catalog_path = File.expand_path("~/.idrac/Catalog.xml")
40
- if File.exist?(catalog_path)
41
- puts "\nChecking for updates using catalog: #{catalog_path}".light_cyan
42
- updates = firmware.check_updates(catalog_path)
43
-
44
- if updates.any?
45
- puts "\nAvailable Updates:".green.bold
46
- updates.each_with_index do |update, index|
47
- puts "#{index + 1}. #{update[:name]}: #{update[:current_version]} -> #{update[:available_version]}".light_cyan
48
- end
49
-
50
- # Interactive update for the first update
51
- puts "\nSelected update: #{updates.first[:name]}".light_yellow
52
- puts "Starting interactive update for selected component...".light_cyan.bold
53
-
54
- firmware.interactive_update(catalog_path, [updates.first])
55
- else
56
- puts "No updates available for your system.".yellow
57
- end
58
- else
59
- puts "\nCatalog not found at #{catalog_path}. Run 'idrac firmware:catalog' to download it.".yellow
60
- end
61
-
62
- rescue IDRAC::Error => e
63
- puts "Error: #{e.message}".red.bold
64
- ensure
65
- # Logout
66
- client.logout if client
67
- puts "Logged out".light_cyan
68
- end