pyghmi 1.6.3__py3-none-any.whl → 1.6.4__py3-none-any.whl
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.
- pyghmi/redfish/command.py +6 -3
- pyghmi/redfish/oem/generic.py +37 -21
- pyghmi/redfish/oem/lenovo/smm3.py +32 -0
- pyghmi/redfish/oem/lenovo/xcc3.py +7 -2
- pyghmi/util/webclient.py +14 -8
- {pyghmi-1.6.3.dist-info → pyghmi-1.6.4.dist-info}/METADATA +1 -1
- {pyghmi-1.6.3.dist-info → pyghmi-1.6.4.dist-info}/RECORD +13 -13
- pyghmi-1.6.4.dist-info/pbr.json +1 -0
- pyghmi-1.6.3.dist-info/pbr.json +0 -1
- {pyghmi-1.6.3.dist-info → pyghmi-1.6.4.dist-info}/AUTHORS +0 -0
- {pyghmi-1.6.3.dist-info → pyghmi-1.6.4.dist-info}/LICENSE +0 -0
- {pyghmi-1.6.3.dist-info → pyghmi-1.6.4.dist-info}/WHEEL +0 -0
- {pyghmi-1.6.3.dist-info → pyghmi-1.6.4.dist-info}/entry_points.txt +0 -0
- {pyghmi-1.6.3.dist-info → pyghmi-1.6.4.dist-info}/top_level.txt +0 -0
pyghmi/redfish/command.py
CHANGED
@@ -415,8 +415,11 @@ class Command(object):
|
|
415
415
|
Operator, and ReadOnly
|
416
416
|
"""
|
417
417
|
accinfo = self._account_url_info_by_id(uid)
|
418
|
-
if
|
419
|
-
|
418
|
+
if accinfo:
|
419
|
+
method = 'PATCH'
|
420
|
+
else:
|
421
|
+
accinfo = (self._accountserviceurl + '/Accounts', {})
|
422
|
+
method = 'POST'
|
420
423
|
if privilege_level.startswith('custom.'):
|
421
424
|
privilege_level = privilege_level.replace('custom.', '')
|
422
425
|
for role in self._validroles:
|
@@ -429,7 +432,7 @@ class Command(object):
|
|
429
432
|
"Password": password,
|
430
433
|
"RoleId": privilege_level,
|
431
434
|
}
|
432
|
-
self._do_web_request(accinfo[0], userinfo, method=
|
435
|
+
self._do_web_request(accinfo[0], userinfo, method=method, etag=etag)
|
433
436
|
return True
|
434
437
|
|
435
438
|
def get_screenshot(self, outfile):
|
pyghmi/redfish/oem/generic.py
CHANGED
@@ -21,6 +21,7 @@ import re
|
|
21
21
|
from datetime import datetime
|
22
22
|
from datetime import timedelta
|
23
23
|
from dateutil import tz
|
24
|
+
import socket
|
24
25
|
import time
|
25
26
|
|
26
27
|
import pyghmi.constants as const
|
@@ -1065,22 +1066,7 @@ class OEMHandler(object):
|
|
1065
1066
|
|
1066
1067
|
def update_firmware(self, filename, data=None, progress=None, bank=None, otherfields=()):
|
1067
1068
|
# disable cache to make sure we trigger the token renewal logic if needed
|
1068
|
-
usd = self.
|
1069
|
-
upurl = usd.get('MultipartHttpPushUri', None)
|
1070
|
-
ismultipart = True
|
1071
|
-
if not upurl:
|
1072
|
-
ismultipart = False
|
1073
|
-
if usd.get('HttpPushUriTargetsBusy', False):
|
1074
|
-
raise exc.TemporaryError('Cannot run multtiple updates to '
|
1075
|
-
'same target concurrently')
|
1076
|
-
try:
|
1077
|
-
upurl = usd['HttpPushUri']
|
1078
|
-
except KeyError:
|
1079
|
-
raise exc.UnsupportedFunctionality('Redfish firmware update only supported for implementations with push update support')
|
1080
|
-
if 'HttpPushUriTargetsBusy' in usd:
|
1081
|
-
self._do_web_request(
|
1082
|
-
'/redfish/v1/UpdateService',
|
1083
|
-
{'HttpPushUriTargetsBusy': True}, method='PATCH')
|
1069
|
+
usd, upurl, ismultipart = self.retrieve_firmware_upload_url()
|
1084
1070
|
try:
|
1085
1071
|
uploadthread = webclient.FileUploader(
|
1086
1072
|
self.webclient, upurl, filename, data, formwrap=ismultipart,
|
@@ -1105,8 +1091,19 @@ class OEMHandler(object):
|
|
1105
1091
|
except Exception:
|
1106
1092
|
raise Exception(uploadthread.rsp)
|
1107
1093
|
raise Exception(errmsg)
|
1094
|
+
return self.continue_update(uploadthread, progress)
|
1095
|
+
finally:
|
1096
|
+
if 'HttpPushUriTargetsBusy' in usd:
|
1097
|
+
self._do_web_request(
|
1098
|
+
'/redfish/v1/UpdateService',
|
1099
|
+
{'HttpPushUriTargetsBusy': False}, method='PATCH')
|
1100
|
+
|
1101
|
+
def continue_update(self, uploadthread, progress):
|
1108
1102
|
rsp = json.loads(uploadthread.rsp)
|
1109
1103
|
monitorurl = rsp['@odata.id']
|
1104
|
+
return self.monitor_update_progress(monitorurl, progress)
|
1105
|
+
|
1106
|
+
def monitor_update_progress(self, monitorurl, progress):
|
1110
1107
|
complete = False
|
1111
1108
|
phase = "apply"
|
1112
1109
|
statetype = 'TaskState'
|
@@ -1151,11 +1148,26 @@ class OEMHandler(object):
|
|
1151
1148
|
if not retry:
|
1152
1149
|
raise Exception('Falied to monitor update progress due to excessive timeouts')
|
1153
1150
|
return 'pending'
|
1154
|
-
|
1151
|
+
|
1152
|
+
|
1153
|
+
def retrieve_firmware_upload_url(self):
|
1154
|
+
usd = self._do_web_request('/redfish/v1/UpdateService', cache=False)
|
1155
|
+
upurl = usd.get('MultipartHttpPushUri', None)
|
1156
|
+
ismultipart = True
|
1157
|
+
if not upurl:
|
1158
|
+
ismultipart = False
|
1159
|
+
if usd.get('HttpPushUriTargetsBusy', False):
|
1160
|
+
raise exc.TemporaryError('Cannot run multtiple updates to '
|
1161
|
+
'same target concurrently')
|
1162
|
+
try:
|
1163
|
+
upurl = usd['HttpPushUri']
|
1164
|
+
except KeyError:
|
1165
|
+
raise exc.UnsupportedFunctionality('Redfish firmware update only supported for implementations with push update support')
|
1155
1166
|
if 'HttpPushUriTargetsBusy' in usd:
|
1156
|
-
self._do_web_request(
|
1157
|
-
'
|
1158
|
-
|
1167
|
+
self._do_web_request('/redfish/v1/UpdateService',
|
1168
|
+
{'HttpPushUriTargetsBusy': True}, method='PATCH')
|
1169
|
+
|
1170
|
+
return usd,upurl,ismultipart
|
1159
1171
|
|
1160
1172
|
|
1161
1173
|
def _do_bulk_requests(self, urls, cache=True):
|
@@ -1191,17 +1203,21 @@ class OEMHandler(object):
|
|
1191
1203
|
wc.stdheaders['X-Auth-Token'] = self.xauthtoken
|
1192
1204
|
self.webclient.stdheaders['X-Auth-Token'] = self.xauthtoken
|
1193
1205
|
|
1194
|
-
def _do_web_request(self, url, payload=None, method=None, cache=True):
|
1206
|
+
def _do_web_request(self, url, payload=None, method=None, cache=True, etag=None):
|
1195
1207
|
res = None
|
1196
1208
|
if cache and payload is None and method is None:
|
1197
1209
|
res = self._get_cache(url)
|
1198
1210
|
if res:
|
1199
1211
|
return res
|
1200
1212
|
wc = self.webclient.dupe()
|
1213
|
+
if etag:
|
1214
|
+
wc.stdheaders['If-Match'] = etag
|
1201
1215
|
res = wc.grab_json_response_with_status(url, payload, method=method)
|
1202
1216
|
if res[1] == 401 and 'X-Auth-Token' in self.webclient.stdheaders:
|
1203
1217
|
wc.set_basic_credentials(self.username, self.password)
|
1204
1218
|
self._get_session_token(wc)
|
1219
|
+
if etag:
|
1220
|
+
wc.stdheaders['If-Match'] = etag
|
1205
1221
|
res = wc.grab_json_response_with_status(url, payload,
|
1206
1222
|
method=method)
|
1207
1223
|
if res[1] < 200 or res[1] >= 300:
|
@@ -19,6 +19,7 @@ import pyghmi.constants as pygconst
|
|
19
19
|
import pyghmi.util.webclient as webclient
|
20
20
|
import pyghmi.exceptions as exc
|
21
21
|
import time
|
22
|
+
import socket
|
22
23
|
|
23
24
|
healthlookup = {
|
24
25
|
'ok': pygconst.Health.Ok,
|
@@ -78,6 +79,37 @@ class OEMHandler(generic.OEMHandler):
|
|
78
79
|
def get_system_configuration(self, hideadvanced=True, fishclient=None):
|
79
80
|
return {}
|
80
81
|
|
82
|
+
def retrieve_firmware_upload_url(self):
|
83
|
+
# SMMv3 needs to do the non-multipart upload
|
84
|
+
usd = self._do_web_request('/redfish/v1/UpdateService', cache=False)
|
85
|
+
if usd.get('HttpPushUriTargetsBusy', False):
|
86
|
+
raise exc.TemporaryError('Cannot run multtiple updates to '
|
87
|
+
'same target concurrently')
|
88
|
+
try:
|
89
|
+
upurl = usd['HttpPushUri']
|
90
|
+
except KeyError:
|
91
|
+
raise exc.UnsupportedFunctionality('Redfish firmware update only supported for implementations with push update support')
|
92
|
+
if 'HttpPushUriTargetsBusy' in usd:
|
93
|
+
self._do_web_request(
|
94
|
+
'/redfish/v1/UpdateService',
|
95
|
+
{'HttpPushUriTargetsBusy': True}, method='PATCH')
|
96
|
+
return usd,upurl,False
|
97
|
+
|
98
|
+
def continue_update(self, uploadthread, progress):
|
99
|
+
# SMMv3 does not provide a response, must hardcode the continuation
|
100
|
+
# /redfish/v1/UpdateService/FirmwareInventory/fwuimage
|
101
|
+
rsp = self._do_web_request('/redfish/v1/UpdateService/FirmwareInventory/fwuimage')
|
102
|
+
for ri in rsp.get('RelatedItem', []):
|
103
|
+
targ = ri.get('@odata.id', None)
|
104
|
+
parms = {'Oem': {'Lenovo': {'SecureRollBack': False}}}
|
105
|
+
rsp = self._do_web_request('/redfish/v1/UpdateService', parms, method='PATCH')
|
106
|
+
targspec = {'target': targ}
|
107
|
+
rsp = self._do_web_request('/redfish/v1/UpdateService/Actions/UpdateService.StartUpdate', targspec)
|
108
|
+
monitorurl = rsp.get('@odata.id', None)
|
109
|
+
return self.monitor_update_progress(monitorurl, progress)
|
110
|
+
|
111
|
+
|
112
|
+
|
81
113
|
def get_diagnostic_data(self, savefile, progress=None, autosuffix=False):
|
82
114
|
tsk = self._do_web_request(
|
83
115
|
'/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.CollectDiagnosticData',
|
@@ -950,8 +950,10 @@ class OEMHandler(generic.OEMHandler):
|
|
950
950
|
acctattribs = {}
|
951
951
|
usbsettings = {}
|
952
952
|
bmchangeset = {}
|
953
|
+
rawchangeset = {}
|
953
954
|
for key in changeset:
|
954
955
|
if isinstance(changeset[key], str):
|
956
|
+
rawchangeset[key] = changeset[key]
|
955
957
|
changeset[key] = {'value': changeset[key]}
|
956
958
|
currval = changeset[key].get('value', None)
|
957
959
|
if key == 'password_complexity':
|
@@ -967,7 +969,10 @@ class OEMHandler(generic.OEMHandler):
|
|
967
969
|
elif currval and 'enabled'.startswith(currval):
|
968
970
|
currval = 'True'
|
969
971
|
else:
|
970
|
-
|
972
|
+
try:
|
973
|
+
currval = int(currval)
|
974
|
+
except ValueError:
|
975
|
+
pass
|
971
976
|
if key.lower() in self.oemacctmap:
|
972
977
|
if 'Oem' not in acctattribs:
|
973
978
|
acctattribs['Oem'] = {'Lenovo': {}}
|
@@ -984,7 +989,7 @@ class OEMHandler(generic.OEMHandler):
|
|
984
989
|
'usb_forwarded_ports'):
|
985
990
|
usbsettings[key] = currval
|
986
991
|
else:
|
987
|
-
bmchangeset[key.replace('bmc.', '')] =
|
992
|
+
bmchangeset[key.replace('bmc.', '')] = rawchangeset[key]
|
988
993
|
if acctattribs:
|
989
994
|
self._do_web_request(
|
990
995
|
'/redfish/v1/AccountService', acctattribs, method='PATCH')
|
pyghmi/util/webclient.py
CHANGED
@@ -24,6 +24,7 @@ import json
|
|
24
24
|
import socket
|
25
25
|
import ssl
|
26
26
|
import threading
|
27
|
+
import os
|
27
28
|
|
28
29
|
import six
|
29
30
|
|
@@ -97,6 +98,8 @@ class FileDownloader(threading.Thread):
|
|
97
98
|
|
98
99
|
|
99
100
|
def get_upload_form(filename, data, formname, otherfields, boundary=BND):
|
101
|
+
if not boundary:
|
102
|
+
boundary = base64.b64encode(os.urandom(54))[:70]
|
100
103
|
ffilename = filename.split('/')[-1]
|
101
104
|
if not formname:
|
102
105
|
formname = ffilename
|
@@ -124,8 +127,8 @@ def get_upload_form(filename, data, formname, otherfields, boundary=BND):
|
|
124
127
|
formname, ffilename).encode('utf-8'))
|
125
128
|
form += b'Content-Type: application/octet-stream\r\n\r\n' + data
|
126
129
|
form += b'\r\n--' + boundary + b'--\r\n'
|
127
|
-
uploadforms[filename] = form
|
128
|
-
return
|
130
|
+
uploadforms[filename] = form, boundary
|
131
|
+
return uploadforms[filename]
|
129
132
|
|
130
133
|
|
131
134
|
class SecureHTTPConnection(httplib.HTTPConnection, object):
|
@@ -142,6 +145,7 @@ class SecureHTTPConnection(httplib.HTTPConnection, object):
|
|
142
145
|
self.broken = False
|
143
146
|
self.thehost = host
|
144
147
|
self.theport = port
|
148
|
+
self._upbuffer = None
|
145
149
|
try:
|
146
150
|
httplib.HTTPConnection.__init__(self, host, port, strict=strict,
|
147
151
|
**kwargs)
|
@@ -332,16 +336,16 @@ class SecureHTTPConnection(httplib.HTTPConnection, object):
|
|
332
336
|
the file.
|
333
337
|
:return:
|
334
338
|
"""
|
335
|
-
boundary = base64.b64encode(os.urandom(54))[:70]
|
336
339
|
if data is None:
|
337
340
|
data = open(filename, 'rb')
|
338
341
|
ulhdrs = self.stdheaders.copy()
|
339
342
|
if formwrap:
|
340
|
-
|
341
|
-
filename, data, formname, otherfields, boundary)
|
342
|
-
|
343
|
-
ulhdrs['Content-
|
344
|
-
|
343
|
+
guf = get_upload_form(
|
344
|
+
filename, data, formname, otherfields, boundary=None)
|
345
|
+
self._upbuffer = io.BytesIO(guf[0])
|
346
|
+
ulhdrs['Content-Type'] = b'multipart/form-data; boundary=' + guf[1]
|
347
|
+
ulhdrs['Content-Length'] = len(uploadforms[filename][0])
|
348
|
+
self.ulsize = len(uploadforms[filename][0])
|
345
349
|
else:
|
346
350
|
canseek = True
|
347
351
|
try:
|
@@ -384,6 +388,8 @@ class SecureHTTPConnection(httplib.HTTPConnection, object):
|
|
384
388
|
return body
|
385
389
|
|
386
390
|
def get_upload_progress(self):
|
391
|
+
if self._upbuffer is None:
|
392
|
+
return 0.0
|
387
393
|
return float(self._upbuffer.tell()) / float(self.ulsize)
|
388
394
|
|
389
395
|
def request(self, method, url, body=None, headers=None, referer=None):
|
@@ -43,19 +43,19 @@ pyghmi/ipmi/private/simplesession.py,sha256=cNGaoT0uWIKDut6gUG9kAOX_b_qTzdB26R6I
|
|
43
43
|
pyghmi/ipmi/private/spd.py,sha256=oEPSXm19X2eNXDiyW_6fVjBFqhuuMAtBI9quRJgclH4,27094
|
44
44
|
pyghmi/ipmi/private/util.py,sha256=ayYodiSydlrrt0_pQppoRB1T6n-KNOiHZSfAlCMcpG0,3847
|
45
45
|
pyghmi/redfish/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
46
|
-
pyghmi/redfish/command.py,sha256=
|
46
|
+
pyghmi/redfish/command.py,sha256=_HLICBri_ON1GqSqqPNWoNKnGz7YBrqHo_l6tjGRiDc,61350
|
47
47
|
pyghmi/redfish/oem/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
48
|
-
pyghmi/redfish/oem/generic.py,sha256=
|
48
|
+
pyghmi/redfish/oem/generic.py,sha256=fX6ADqGURX9cQr-Q8cyncQtxLM1oz5CMv57IQ8ijxoY,57313
|
49
49
|
pyghmi/redfish/oem/lookup.py,sha256=pfJW5xSkUY61OirMeYy0b1SbjBFz6IDfN5ZOYog_Yq4,1530
|
50
50
|
pyghmi/redfish/oem/dell/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
51
51
|
pyghmi/redfish/oem/dell/idrac.py,sha256=pNnmqdV1sOP3ABw0xq0wF1QEO2L8onT7Osc_-sDO8EU,2146
|
52
52
|
pyghmi/redfish/oem/dell/main.py,sha256=g8773SShUpbYxXB9zVx2pD5z1xP04wB_sXAxcAs6_xY,793
|
53
53
|
pyghmi/redfish/oem/lenovo/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
54
54
|
pyghmi/redfish/oem/lenovo/main.py,sha256=bnx8LuC_C4_OluNR8JSHIxtSlM4_jdBb4cUzJM6mazE,2597
|
55
|
-
pyghmi/redfish/oem/lenovo/smm3.py,sha256=
|
55
|
+
pyghmi/redfish/oem/lenovo/smm3.py,sha256=QHasf5QofFuYqtHPeqcwCEJUbd0PV5_C6u-Y8FVdqCk,7598
|
56
56
|
pyghmi/redfish/oem/lenovo/tsma.py,sha256=6GELCuriumARj_kv7fgqtUpo9ekiWHpQcM9v_mnGILI,34645
|
57
57
|
pyghmi/redfish/oem/lenovo/xcc.py,sha256=78ksNj2-0jquj61lmAZldy3DdcR5KndqbLQ2Y4ZSFOM,84234
|
58
|
-
pyghmi/redfish/oem/lenovo/xcc3.py,sha256=
|
58
|
+
pyghmi/redfish/oem/lenovo/xcc3.py,sha256=8LxWzqXCkNmQ9PT-bu2ZSvgziTar3u1J37x8IRBshx8,55843
|
59
59
|
pyghmi/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
60
60
|
pyghmi/tests/unit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
61
61
|
pyghmi/tests/unit/base.py,sha256=xWImA7zPRgfrEe2xAdRZ6w_dLwExGRBJ5CBybssUQGg,744
|
@@ -63,12 +63,12 @@ pyghmi/tests/unit/ipmi/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3
|
|
63
63
|
pyghmi/tests/unit/ipmi/test_sdr.py,sha256=vb3iLY0cnHJ2K_m4xgYUjEcbPd_ZYhYx-uBowByplXw,824
|
64
64
|
pyghmi/util/__init__.py,sha256=GZLBWJiun2Plb_VE9dDSh4_PQMCha3gA7QLUqx3oSYI,25
|
65
65
|
pyghmi/util/parse.py,sha256=6VlyBCEcE8gy8PJWmEDdtCyWATaKwPaTswCdioPCWOE,2120
|
66
|
-
pyghmi/util/webclient.py,sha256=
|
67
|
-
pyghmi-1.6.
|
68
|
-
pyghmi-1.6.
|
69
|
-
pyghmi-1.6.
|
70
|
-
pyghmi-1.6.
|
71
|
-
pyghmi-1.6.
|
72
|
-
pyghmi-1.6.
|
73
|
-
pyghmi-1.6.
|
74
|
-
pyghmi-1.6.
|
66
|
+
pyghmi/util/webclient.py,sha256=i1rJ7NBlPQFTRv7kgzbTaOHsWuPeXcMAjRXm_i8CI0A,15652
|
67
|
+
pyghmi-1.6.4.dist-info/AUTHORS,sha256=yv4aQom_PII-SNqbeeKrfH-spcG85PRPsZ71Iqjl_fU,2083
|
68
|
+
pyghmi-1.6.4.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
|
69
|
+
pyghmi-1.6.4.dist-info/METADATA,sha256=iunjBkI12heq3smej-gMbCPO3KdWK4Y60I6yuxqmwd0,1136
|
70
|
+
pyghmi-1.6.4.dist-info/WHEEL,sha256=iAkIy5fosb7FzIOwONchHf19Qu7_1wCWyFNR5gu9nU0,91
|
71
|
+
pyghmi-1.6.4.dist-info/entry_points.txt,sha256=-OpJliDzATxmuPXK0VR3Ma-Yk_i4ZhfIIB-12A26dSI,168
|
72
|
+
pyghmi-1.6.4.dist-info/pbr.json,sha256=G84aunNCSzzeuUMkVxkxXAfI8E9qATe2tf_kPWkiFWs,46
|
73
|
+
pyghmi-1.6.4.dist-info/top_level.txt,sha256=aDtt6S9eVu6-tNdaUs4Pz9PbdUd69bziZZMhNvk9Ulc,7
|
74
|
+
pyghmi-1.6.4.dist-info/RECORD,,
|
@@ -0,0 +1 @@
|
|
1
|
+
{"git_version": "99af22b", "is_release": true}
|
pyghmi-1.6.3.dist-info/pbr.json
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
{"git_version": "58cf3ce", "is_release": true}
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|