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.
- checksums.yaml +4 -4
- data/README.md +48 -101
- data/bin/idrac +128 -12
- data/idrac.gemspec +9 -8
- data/lib/idrac/version.rb +1 -1
- data/lib/idrac.rb +1 -0
- metadata +3 -36
- data/.rspec +0 -3
- data/Rakefile +0 -17
- data/dell_firmware_downloads/Catalog.etag +0 -1
- data/dell_firmware_downloads/Catalog.xml +0 -0
- data/idrac-0.1.6/.rspec +0 -3
- data/idrac-0.1.6/README.md +0 -103
- data/idrac-0.1.6/Rakefile +0 -17
- data/idrac-0.1.6/bin/console +0 -11
- data/idrac-0.1.6/bin/idrac +0 -179
- data/idrac-0.1.6/bin/setup +0 -8
- data/idrac-0.1.6/idrac.gemspec +0 -51
- data/idrac-0.1.6/lib/idrac/client.rb +0 -109
- data/idrac-0.1.6/lib/idrac/firmware.rb +0 -366
- data/idrac-0.1.6/lib/idrac/version.rb +0 -5
- data/idrac-0.1.6/lib/idrac.rb +0 -30
- data/idrac-0.1.6/sig/idrac.rbs +0 -4
- data/idrac-0.1.7/.rspec +0 -3
- data/idrac-0.1.7/README.md +0 -103
- data/idrac-0.1.7/Rakefile +0 -17
- data/idrac-0.1.7/bin/console +0 -11
- data/idrac-0.1.7/bin/idrac +0 -179
- data/idrac-0.1.7/bin/setup +0 -8
- data/idrac-0.1.7/idrac.gemspec +0 -51
- data/idrac-0.1.7/lib/idrac/client.rb +0 -109
- data/idrac-0.1.7/lib/idrac/firmware.rb +0 -366
- data/idrac-0.1.7/lib/idrac/screenshot.rb +0 -49
- data/idrac-0.1.7/lib/idrac/version.rb +0 -5
- data/idrac-0.1.7/lib/idrac.rb +0 -30
- data/idrac-0.1.7/sig/idrac.rbs +0 -4
- data/idrac.py +0 -500
- data/sig/idrac.rbs +0 -4
- data/test_firmware_update.rb +0 -68
- data/updater.rb +0 -729
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
data/test_firmware_update.rb
DELETED
@@ -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
|