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 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 not accinfo:
419
- raise Exception("Unable to find indicated uid")
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='PATCH', etag=etag)
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):
@@ -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._do_web_request('/redfish/v1/UpdateService', cache=False)
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
- finally:
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
- '/redfish/v1/UpdateService',
1158
- {'HttpPushUriTargetsBusy': False}, method='PATCH')
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
- currval = int(currval)
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.', '')] = changeset[key]
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 form
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
- self._upbuffer = io.BytesIO(get_upload_form(
341
- filename, data, formname, otherfields, boundary))
342
- ulhdrs['Content-Type'] = b'multipart/form-data; boundary=' + boundary
343
- ulhdrs['Content-Length'] = len(uploadforms[filename])
344
- self.ulsize = len(uploadforms[filename])
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):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pyghmi
3
- Version: 1.6.3
3
+ Version: 1.6.4
4
4
  Summary: Python General Hardware Management Initiative (IPMI and others)
5
5
  Home-page: http://github.com/openstack/pyghmi/
6
6
  Author: Jarrod Johnson
@@ -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=0mLgsynfiyfi_i4wtL3ZqPR6CeeHajj-azqTW7EUE3I,61278
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=OvkQV3-p6aoY-oeVNSpfChpAuh1iDOV8OXdWuz7tW9Q,56747
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=W3PKHpFNj5Ujql-neWTH3UgYGDZXQlBvC1aRX97GV8A,5982
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=Uu6VjvUNZgNkAW5slEGckFR55htALbrxvVUjkIy-1g8,55678
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=Sw-XQI0udlD22pdCMOBPvv42KMtLV4a3noYY9v_Muzw,15472
67
- pyghmi-1.6.3.dist-info/AUTHORS,sha256=yv4aQom_PII-SNqbeeKrfH-spcG85PRPsZ71Iqjl_fU,2083
68
- pyghmi-1.6.3.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
69
- pyghmi-1.6.3.dist-info/METADATA,sha256=nYZYXWlA0oLwsa438e0NOFvPrd_XMrR7-ZURkEK7D3E,1136
70
- pyghmi-1.6.3.dist-info/WHEEL,sha256=iAkIy5fosb7FzIOwONchHf19Qu7_1wCWyFNR5gu9nU0,91
71
- pyghmi-1.6.3.dist-info/entry_points.txt,sha256=-OpJliDzATxmuPXK0VR3Ma-Yk_i4ZhfIIB-12A26dSI,168
72
- pyghmi-1.6.3.dist-info/pbr.json,sha256=vB_8gvy6-F0qrwot79vigX7I5YKQFLwLkZqGWdkJErA,46
73
- pyghmi-1.6.3.dist-info/top_level.txt,sha256=aDtt6S9eVu6-tNdaUs4Pz9PbdUd69bziZZMhNvk9Ulc,7
74
- pyghmi-1.6.3.dist-info/RECORD,,
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}
@@ -1 +0,0 @@
1
- {"git_version": "58cf3ce", "is_release": true}
File without changes