pyghmi 1.5.71__py3-none-any.whl → 1.5.75__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,85 @@
1
+ # Copyright 2025 Lenovo Corporation
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ import pyghmi.redfish.oem.generic as generic
16
+ import pyghmi.constants as pygconst
17
+
18
+ healthlookup = {
19
+ 'ok': pygconst.Health.Ok,
20
+ 'critical': pygconst.Health.Critical
21
+ }
22
+
23
+ def _baytonumber(bay):
24
+ try:
25
+ return int(bay)
26
+ except ValueError:
27
+ if len(bay) == 2:
28
+ # Treat a hexadecimal system as a leading decimal digit and letter compile
29
+ # 1a == slot 1, 1b == slot 2, 2a == slot 1, etc..
30
+ try:
31
+ tmp = int(bay, 16)
32
+ return (2 * (tmp >> 4) - 1) + ((tmp & 15) % 10)
33
+ except ValueError:
34
+ return None
35
+ return None
36
+
37
+
38
+ def _baytolabel(bay):
39
+ try:
40
+ baynum = int(bay)
41
+ # need to convert to 1a, 1b, etc...
42
+ vertidx = ((baynum - 1) // 2 + 1) << 4
43
+ horizidx = (baynum - 1) % 2 + 10
44
+ bayid = vertidx | horizidx
45
+ return '{:02x}'.format(bayid)
46
+ except ValueError:
47
+ return bay
48
+ return None
49
+
50
+ class OEMHandler(generic.OEMHandler):
51
+ def get_health(self, fishclient, verbose=True):
52
+ rsp = self._do_web_request('/redfish/v1/Chassis/chassis1')
53
+ health = rsp.get('Status', {}).get('Health', 'Unknown').lower()
54
+ health = healthlookup.get(health, pygconst.Health.Critical)
55
+ return {'health': health}
56
+
57
+ def get_system_configuration(self, hideadvanced=True, fishclient=None):
58
+ return {}
59
+
60
+ def _get_node_info(self):
61
+ nodeinfo = self._varsysinfo
62
+ if not nodeinfo:
63
+ overview = self._do_web_request('/redfish/v1/')
64
+ chassismembs = overview.get('Chassis', {}).get('@odata.id', None)
65
+ if not chassismembs:
66
+ return nodeinfo
67
+ chassislist = self._do_web_request(chassismembs)
68
+ chassismembs = chassislist.get('Members', [])
69
+ if len(chassismembs) == 1:
70
+ chassisurl = chassismembs[0]['@odata.id']
71
+ nodeinfo = self._do_web_request(chassisurl)
72
+ nodeinfo['SKU'] = nodeinfo['Model']
73
+ nodeinfo['Model'] = 'N1380 Enclosure'
74
+ return nodeinfo
75
+
76
+ def reseat_bay(self, bay):
77
+ bayid = _baytolabel(bay)
78
+ url = '/redfish/v1/Chassis/chassis1/Oem/Lenovo/Nodes/{}/Actions/Node.Reseat'.format(bayid)
79
+ rsp = self._do_web_request(url, method='POST')
80
+
81
+ def get_event_log(self, clear=False, fishclient=None):
82
+ return super().get_event_log(clear, fishclient, extraurls=[{'@odata.id':'/redfish/v1/Chassis/chassis1/LogServices/EventLog'}])
83
+
84
+ def get_description(self, fishclient):
85
+ return {'height': 13, 'slot': 0, 'slots': [8, 2]}
@@ -579,7 +579,7 @@ class OEMHandler(generic.OEMHandler):
579
579
  summary['badreadings'] = fallbackdata
580
580
  return summary
581
581
 
582
- def get_description(self):
582
+ def get_description(self, fishclient):
583
583
  description = self._do_web_request('/DeviceDescription.json')
584
584
  if description:
585
585
  description = description[0]
@@ -674,7 +674,7 @@ class OEMHandler(generic.OEMHandler):
674
674
  for diskent in adp.get('aimDisks', ()):
675
675
  yield self._get_disk_firmware_single(diskent)
676
676
 
677
- def get_firmware_inventory(self, components):
677
+ def get_firmware_inventory(self, components, fishclient):
678
678
  sysinf = self.wc.grab_json_response('/api/dataset/sys_info')
679
679
  for item in sysinf.get('items', {}):
680
680
  for firm in item.get('firmware', []):
@@ -0,0 +1,395 @@
1
+ # Copyright 2025 Lenovo Corporation
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ import copy
15
+ import json
16
+ import pyghmi.redfish.oem.generic as generic
17
+ import pyghmi.exceptions as pygexc
18
+ import pyghmi.util.webclient as webclient
19
+ import zipfile
20
+ import time
21
+ import os.path
22
+
23
+ class OEMHandler(generic.OEMHandler):
24
+
25
+ def supports_expand(self, url):
26
+ return True
27
+
28
+ def get_diagnostic_data(self, savefile, progress=None, autosuffix=False):
29
+ tsk = self._do_web_request(
30
+ '/redfish/v1/Systems/1/LogServices/DiagnosticLog/Actions/LogService.CollectDiagnosticData',
31
+ {"DiagnosticDataType": "Manager", "SelectDataTypes": []})
32
+ taskrunning = True
33
+ taskurl = tsk.get('TaskMonitor', None)
34
+ pct = 0 if taskurl else 100
35
+ durl = None
36
+ while pct < 100 and taskrunning:
37
+ status = self._do_web_request(taskurl)
38
+ durl = status.get('AdditionalDataURI', '')
39
+ pct = status.get('PercentComplete', 0)
40
+ taskrunning = status.get('TaskState', 'Complete') == 'Running'
41
+ if progress:
42
+ progress({'phase': 'initializing', 'progress': float(pct)})
43
+ if taskrunning:
44
+ time.sleep(3)
45
+ if not durl:
46
+ raise Exception("Failed getting service data url")
47
+ fname = os.path.basename(durl)
48
+ if autosuffix and not savefile.endswith('.tar.zst'):
49
+ savefile += '-{0}'.format(fname)
50
+ fd = webclient.FileDownloader(self.webclient, durl, savefile)
51
+ fd.start()
52
+ while fd.isAlive():
53
+ fd.join(1)
54
+ if progress and self.webclient.get_download_progress():
55
+ progress({'phase': 'download',
56
+ 'progress': 100 * self.webclient.get_download_progress()})
57
+ if fd.exc:
58
+ raise fd.exc
59
+ if progress:
60
+ progress({'phase': 'complete'})
61
+ return savefile
62
+
63
+ def get_system_power_watts(self, fishclient):
64
+ powerinfo = fishclient._do_web_request('/redfish/v1/Chassis/1/Sensors/power_Sys_Power')
65
+ return powerinfo['Reading']
66
+
67
+ def _get_cpu_temps(self, fishclient):
68
+ cputemps = []
69
+ for reading in super()._get_cpu_temps(fishclient):
70
+ if 'Margin' in reading['Name']:
71
+ continue
72
+ cputemps.append(reading)
73
+ return cputemps
74
+
75
+ def get_system_configuration(self, hideadvanced=True, fishclient=None):
76
+ stgs = self._getsyscfg(fishclient)[0]
77
+ outstgs = {}
78
+ for stg in stgs:
79
+ outstgs[f'UEFI.{stg}'] = stgs[stg]
80
+ return outstgs
81
+
82
+ def set_system_configuration(self, changeset, fishclient):
83
+ bmchangeset = {}
84
+ vpdchangeset = {}
85
+ for stg in list(changeset):
86
+ if stg.startswith('BMC.'):
87
+ bmchangeset[stg.replace('BMC.', '')] = changeset[stg]
88
+ del changeset[stg]
89
+ if stg.startswith('UEFI.'):
90
+ changeset[stg.replace('UEFI.', '')] = changeset[stg]
91
+ del changeset[stg]
92
+ if stg.startswith('VPD.'):
93
+ vpdchangeset[stg.replace('VPD.', '')] = changeset[stg]
94
+ del changeset[stg]
95
+ if changeset:
96
+ super().set_system_configuration(changeset, fishclient)
97
+ if bmchangeset:
98
+ self._set_xcc3_settings(bmchangeset, fishclient)
99
+ if vpdchangeset:
100
+ self._set_xcc3_vpd(vpdchangeset, fishclient)
101
+
102
+ def _set_xcc3_vpd(self, changeset, fishclient):
103
+ newvpd = {'Attributes': changeset}
104
+ fishclient._do_web_request(
105
+ '/redfish/v1/Chassis/1/Oem/Lenovo/SysvpdSettings/Actions/LenovoSysVpdSettings.SetVpdSettings',
106
+ newvpd)
107
+
108
+
109
+ def _set_xcc3_settings(self, changeset, fishclient):
110
+ currsettings, reginfo = self._get_lnv_bmcstgs(fishclient)
111
+ rawsettings = fishclient._do_web_request('/redfish/v1/Managers/1/Oem/Lenovo/BMCSettings',
112
+ cache=False)
113
+ rawsettings = rawsettings.get('Attributes', {})
114
+ pendingsettings = {}
115
+ ret = self._set_redfish_settings(
116
+ changeset, fishclient, currsettings, rawsettings,
117
+ pendingsettings, self.lenovobmcattrdeps, reginfo,
118
+ '/redfish/v1/Managers/1/Oem/Lenovo/BMCSettings')
119
+ fishclient._do_web_request('/redfish/v1/Managers/1/Oem/Lenovo/BMCSettings', cache=False)
120
+ return ret
121
+
122
+ oemacctmap = {
123
+ 'password_reuse_count': 'MinimumPasswordReuseCycle',
124
+ 'password_change_interval': 'MinimumPasswordChangeIntervalHours',
125
+ 'password_expiration': 'PasswordExpirationPeriodDays',
126
+ 'password_complexity': 'ComplexPassword',
127
+ }
128
+
129
+ acctmap = {
130
+ 'password_login_failures': 'AccountLockoutThreshold',
131
+ 'password_min_length': 'MinPasswordLength',
132
+ 'password_lockout_period': 'AccountLockoutDuration',
133
+ }
134
+
135
+ def update_firmware(self, filename, data=None, progress=None, bank=None, otherfields=()):
136
+ if not otherfields and bank == 'backup':
137
+ uxzcount = 0
138
+ otherfields = {'UpdateParameters': {"Targets": ["/redfish/v1/UpdateService/FirmwareInventory/BMC-Backup"]}}
139
+ needseek = False
140
+ if data and hasattr(data, 'read'):
141
+ if zipfile.is_zipfile(data):
142
+ needseek = True
143
+ z = zipfile.ZipFile(data)
144
+ else:
145
+ data.seek(0)
146
+ elif data is None and zipfile.is_zipfile(filename):
147
+ z = zipfile.ZipFile(filename)
148
+ if z:
149
+ for tmpname in z.namelist():
150
+ if tmpname.startswith('payloads/'):
151
+ uxzcount += 1
152
+ if tmpname.endswith('.uxz'):
153
+ wrappedfilename = tmpname
154
+ if uxzcount == 1 and wrappedfilename:
155
+ filename = os.path.basename(wrappedfilename)
156
+ data = z.open(wrappedfilename)
157
+ elif needseek:
158
+ data.seek(0)
159
+ super().update_firmware(filename, data=data, progress=progress, bank=bank, otherfields=otherfields)
160
+
161
+ def get_bmc_configuration(self):
162
+ settings = {}
163
+ acctsrv = self._do_web_request('/redfish/v1/AccountService')
164
+ for oemstg in self.oemacctmap:
165
+ settings[oemstg] = {
166
+ 'value': acctsrv['Oem']['Lenovo'][self.oemacctmap[oemstg]]}
167
+ for stg in self.acctmap:
168
+ settings[stg] = {
169
+ 'value': acctsrv[self.acctmap[stg]]}
170
+ bmcstgs = self._do_web_request('/redfish/v1/Managers/1/Oem/Lenovo/BMCSettings')
171
+ bmcattrs = bmcstgs['Attributes']
172
+ self.ethoverusb = True if 'EthOverUSBEnabled' in bmcattrs else False
173
+ usbcfg = bmcattrs.get('NetMgrUsb0Enabled', bmcattrs.get('EthOverUSBEnabled', 'False'))
174
+ usbeth = 'Enable' if usbcfg == 'True' else 'Disable'
175
+ settings['usb_ethernet'] = {
176
+ 'value': usbeth
177
+ }
178
+ usbcfg = bmcattrs.get('NetMgrUsb0PortForwardingEnabled', bmcattrs.get('EthOverUSBPortForwardingEnabled', 'False'))
179
+ fwd = 'Enable' if usbcfg == 'True' else 'Disable'
180
+ settings['usb_ethernet_port_forwarding'] = fwd
181
+ mappings = []
182
+ for idx in range(1, 11):
183
+ keyname = 'NetMgrUsb0PortForwardingPortMapping.{}'.format(idx)
184
+ keyaltname = 'EthOverUSBPortForwardingPortMapping_{}'.format(idx)
185
+ currval = bmcattrs.get(keyname, bmcattrs.get(keyaltname, '0,0'))
186
+ if currval == '0,0':
187
+ continue
188
+ src, dst = currval.split(',')
189
+ mappings.append('{}:{}'.format(src,dst))
190
+ settings['usb_forwarded_ports'] = {'value': ','.join(mappings)}
191
+ return settings
192
+
193
+ def set_bmc_configuration(self, changeset):
194
+ acctattribs = {}
195
+ usbsettings = {}
196
+ for key in changeset:
197
+ if isinstance(changeset[key], str):
198
+ changeset[key] = {'value': changeset[key]}
199
+ currval = changeset[key].get('value', None)
200
+ if key == 'password_complexity':
201
+ if currval.lower() in ("false", 0):
202
+ currval = False
203
+ elif currval.lower() in ('true', 1):
204
+ currval = True
205
+ elif key.lower().startswith('usb_'):
206
+ if 'forwarded_ports' not in key.lower():
207
+ currval = currval.lower()
208
+ if currval and 'disabled'.startswith(currval):
209
+ currval = 'False'
210
+ elif currval and 'enabled'.startswith(currval):
211
+ currval = 'True'
212
+ else:
213
+ currval = int(currval)
214
+ if key.lower() in self.oemacctmap:
215
+ if 'Oem' not in acctattribs:
216
+ acctattribs['Oem'] = {'Lenovo': {}}
217
+ acctattribs['Oem']['Lenovo'][
218
+ self.oemacctmap[key.lower()]] = currval
219
+ if key.lower() == 'password_expiration':
220
+ warntime = str(int(int(currval) * 0.08))
221
+ acctattribs['Oem']['Lenovo'][
222
+ 'PasswordExpirationWarningPeriod'] = warntime
223
+ elif key.lower() in self.acctmap:
224
+ acctattribs[self.acctmap[key.lower()]] = currval
225
+ elif key.lower() in (
226
+ 'usb_ethernet', 'usb_ethernet_port_forwarding',
227
+ 'usb_forwarded_ports'):
228
+ usbsettings[key] = currval
229
+ else:
230
+ raise pygexc.InvalidParameterValue(
231
+ '{0} not a known setting'.format(key))
232
+ if acctattribs:
233
+ self._do_web_request(
234
+ '/redfish/v1/AccountService', acctattribs, method='PATCH')
235
+ self._do_web_request('/redfish/v1/AccountService', cache=False)
236
+ if usbsettings:
237
+ self.apply_usb_configuration(usbsettings)
238
+
239
+ def apply_usb_configuration(self, usbsettings):
240
+ bmcattribs = {}
241
+ if not hasattr(self, 'ethoverusb'):
242
+ self.get_bmc_configuration()
243
+
244
+ if 'usb_forwarded_ports' in usbsettings:
245
+ pairs = usbsettings['usb_forwarded_ports'].split(',')
246
+ idx = 1
247
+ for pair in pairs:
248
+ if self.ethoverusb:
249
+ keyname = 'EthOverUSBPortForwardingPortMapping_{}'.format(idx)
250
+ else:
251
+ keyname = 'NetMgrUsb0PortForwardingPortMapping.{}'.format(idx)
252
+ pair = pair.replace(':', ',')
253
+ bmcattribs[keyname] = pair
254
+ idx += 1
255
+ while idx < 11:
256
+ if self.ethoverusb:
257
+ keyname = 'EthOverUSBPortForwardingPortMapping_{}'.format(idx)
258
+ else:
259
+ keyname = 'NetMgrUsb0PortForwardingPortMapping.{}'.format(idx)
260
+ bmcattribs[keyname] = '0,0'
261
+ idx += 1
262
+ if 'usb_ethernet' in usbsettings:
263
+ keyname = 'EthOverUSBEnabled' if self.ethoverusb else 'NetMgrUsb0Enabled'
264
+ bmcattribs[keyname] = usbsettings['usb_ethernet']
265
+ if 'usb_ethernet_port_forwarding' in usbsettings:
266
+ keyname = 'EthOverUSBPortForwardingEnabled' if self.ethoverusb else 'NetMgrUsb0PortForwardingEnabled'
267
+ bmcattribs[keyname] = usbsettings[
268
+ 'usb_ethernet_port_forwarding']
269
+ self._do_web_request(
270
+ '/redfish/v1/Managers/1/Oem/Lenovo/BMCSettings',
271
+ {'Attributes': bmcattribs}, method='PATCH')
272
+ self._do_web_request(
273
+ '/redfish/v1/Managers/1/Oem/Lenovo/BMCSettings', cache=False)
274
+
275
+ def get_extended_bmc_configuration(self, fishclient, hideadvanced=True):
276
+ cfgin = self._get_lnv_bmcstgs(fishclient)[0]
277
+ cfgout = {}
278
+ for stgname in cfgin:
279
+ cfgout[f'BMC.{stgname}'] = cfgin[stgname]
280
+ vpdin = self._get_lnv_vpd(fishclient)[0]
281
+ for stgname in vpdin:
282
+ cfgout[f'VPD.{stgname}'] = vpdin[stgname]
283
+ return cfgout
284
+
285
+ def _get_lnv_vpd(self, fishclient):
286
+ currsettings, reginfo = self._get_lnv_stgs(
287
+ fishclient, '/redfish/v1/Chassis/1/Oem/Lenovo/SysvpdSettings')
288
+ self.lenovobmcattrdeps = reginfo[3]
289
+ return currsettings, reginfo
290
+
291
+ def _get_lnv_bmcstgs(self, fishclient):
292
+ currsettings, reginfo = self._get_lnv_stgs(
293
+ fishclient, '/redfish/v1/Managers/1/Oem/Lenovo/BMCSettings')
294
+ self.lenovobmcattrdeps = reginfo[3]
295
+ return currsettings, reginfo
296
+
297
+ def _get_lnv_stgs(self, fishclient, url):
298
+ bmcstgs = fishclient._do_web_request(url)
299
+ bmcreg = bmcstgs.get('AttributeRegistry', None)
300
+ extrainfo = {}
301
+ valtodisplay = {}
302
+ currsettings = {}
303
+ reginfo = {}, {}, {}, {}
304
+ if bmcreg:
305
+ reginfo = self._get_attrib_registry(fishclient, bmcreg)
306
+ if reginfo:
307
+ extrainfo, valtodisplay, _, _ = reginfo
308
+ for setting in bmcstgs.get('Attributes', {}):
309
+ val = bmcstgs['Attributes'][setting]
310
+ currval = val
311
+ val = valtodisplay.get(setting, {}).get(val, val)
312
+ val = {'value': val}
313
+ val.update(**extrainfo.get(setting, {}))
314
+ currsettings[setting] = val
315
+ return currsettings, reginfo
316
+
317
+ def get_description(self, fishclient):
318
+ rsp = self._get_expanded_data('/redfish/v1/Chassis')
319
+ for chassis in rsp['Members']:
320
+ if (chassis['@odata.id'] == '/redfish/v1/Chassis/1'
321
+ and chassis['ChassisType'] != 'Blade'):
322
+ hmm = chassis.get('HeightMm', None)
323
+ if hmm:
324
+ return {'height': hmm/44.45}
325
+ if (chassis['@odata.id'] == '/redfish/v1/Chassis/Enclosure'
326
+ and chassis.get('ChassisType', None) == 'Enclosure'):
327
+ try:
328
+ slot = chassis['Location']['PartLocation']['LocationOrdinalValue']
329
+ slotnum = (2 * (slot >> 4) - 1) + ((slot & 15) % 10)
330
+ slotcoord = [slot >> 4, (slot & 15) - 9]
331
+ return {'slot': slotnum, 'slotlabel': '{:02x}'.format(slot), 'slotcoord': slotcoord}
332
+ except KeyError:
333
+ continue
334
+ return {}
335
+
336
+ def upload_media(self, filename, progress=None, data=None):
337
+ wc = self.webclient
338
+ uploadthread = webclient.FileUploader(
339
+ wc, '/rdoc_upload', filename, data,
340
+ formname='file',
341
+ formwrap=True)
342
+ uploadthread.start()
343
+ while uploadthread.isAlive():
344
+ uploadthread.join(3)
345
+ if progress:
346
+ progress({'phase': 'upload',
347
+ 'progress': 100 * wc.get_upload_progress()})
348
+ rsp = json.loads(uploadthread.rsp)
349
+ if rsp['return'] != 0:
350
+ raise Exception('Issue uploading file')
351
+ remfilename = rsp['upload_filename']
352
+ if progress:
353
+ progress({'phase': 'upload',
354
+ 'progress': 100.0})
355
+ self._do_web_request(
356
+ '/redfish/v1/Systems/1/VirtualMedia/RDOC1',
357
+ {'Image':'file:///gpx/rdocupload/' + remfilename,
358
+ 'WriteProtected': False}, method='PATCH')
359
+ if progress:
360
+ progress({'phase': 'complete'})
361
+
362
+ def get_firmware_inventory(self, components, fishclient):
363
+ fwlist = fishclient._do_web_request(fishclient._fwinventory + '?$expand=.')
364
+ fwlist = copy.deepcopy(fwlist.get('Members', []))
365
+ self._fwnamemap = {}
366
+ for redres in fwlist:
367
+ fwurl = redres['@odata.id']
368
+ res = (redres, fwurl)
369
+ if fwurl.startswith('/redfish/v1/UpdateService/FirmwareInventory/Bundle.'):
370
+ continue # skip Bundle information for now
371
+ if redres.get('Name', '').startswith('Firmware:'):
372
+ redres['Name'] = redres['Name'].replace('Firmware:', '')
373
+ if redres['Name'].startswith('Firmware-PSoC') and 'Drive_Backplane' in redres["@odata.id"]:
374
+ redres['Name'] = 'Drive Backplane'
375
+ if redres['Name'].startswith('DEVICE-'):
376
+ redres['Name'] = redres['Name'].replace('DEVICE-', '')
377
+ if redres['Name'].startswith('POWER-PSU'):
378
+ redres['Name'] = redres['Name'].replace('POWER-', '')
379
+ swid = redres.get('SoftwareId', '')
380
+ buildid = ''
381
+ version = redres.get('Version', None)
382
+ if swid.startswith('FPGA-') or swid.startswith('UEFI-') or swid.startswith('BMC-'):
383
+ buildid = swid.split('-')[1] + version.split('-')[0]
384
+ version = '-'.join(version.split('-')[1:])
385
+ if version:
386
+ redres['Version'] = version
387
+ cres = fishclient._extract_fwinfo(res)
388
+ if cres[0] is None:
389
+ continue
390
+ if buildid:
391
+ cres[1]['build'] = buildid
392
+ yield cres
393
+ raise pygexc.BypassGenericBehavior()
394
+
395
+
pyghmi/util/webclient.py CHANGED
@@ -97,8 +97,9 @@ class FileDownloader(threading.Thread):
97
97
 
98
98
 
99
99
  def get_upload_form(filename, data, formname, otherfields):
100
+ ffilename = filename.split('/')[-1]
100
101
  if not formname:
101
- formname = filename
102
+ formname = ffilename
102
103
  try:
103
104
  return uploadforms[filename]
104
105
  except KeyError:
@@ -106,16 +107,22 @@ def get_upload_form(filename, data, formname, otherfields):
106
107
  data = data.read()
107
108
  except AttributeError:
108
109
  pass
109
- form = (b'--' + BND
110
+ form = b''
111
+ for ofield in otherfields:
112
+ tfield = otherfields[ofield]
113
+ xtra=''
114
+ if isinstance(tfield, dict):
115
+ tfield = json.dumps(tfield)
116
+ xtra = '\r\nContent-Type: application/json'
117
+ form += (b'--' + BND
118
+ + '\r\nContent-Disposition: form-data; '
119
+ 'name="{0}"{1}\r\n\r\n{2}\r\n'.format(
120
+ ofield, xtra, tfield).encode('utf-8'))
121
+ form += (b'--' + BND
110
122
  + '\r\nContent-Disposition: form-data; '
111
123
  'name="{0}"; filename="{1}"\r\n'.format(
112
- formname, filename).encode('utf-8'))
124
+ formname, ffilename).encode('utf-8'))
113
125
  form += b'Content-Type: application/octet-stream\r\n\r\n' + data
114
- for ofield in otherfields:
115
- form += (b'\r\n--' + BND
116
- + '\r\nContent-Disposition: form-data; '
117
- 'name="{0}"\r\n\r\n{1}'.format(
118
- ofield, otherfields[ofield]).encode('utf-8'))
119
126
  form += b'\r\n--' + BND + b'--\r\n'
120
127
  uploadforms[filename] = form
121
128
  return form
@@ -272,6 +279,22 @@ class SecureHTTPConnection(httplib.HTTPConnection, object):
272
279
  return json.loads(body) if body else {}, rsp.status
273
280
  return body, rsp.status
274
281
 
282
+ def grab_rsp(self, url, data=None, referer=None, headers=None, method=None):
283
+ webclient = self.dupe()
284
+ if isinstance(data, dict):
285
+ data = json.dumps(data)
286
+ if data:
287
+ if not method:
288
+ method = 'POST'
289
+ webclient.request(method, url, data, referer=referer,
290
+ headers=headers)
291
+ else:
292
+ if not method:
293
+ method = 'GET'
294
+ webclient.request(method, url, referer=referer, headers=headers)
295
+ rsp = webclient.getresponse()
296
+ return rsp
297
+
275
298
  def download(self, url, file):
276
299
  """Download a file to filename or file object
277
300
 
@@ -390,3 +413,4 @@ class SecureHTTPConnection(httplib.HTTPConnection, object):
390
413
  except httplib.CannotSendRequest:
391
414
  self.broken = True
392
415
  raise
416
+
@@ -1,12 +1,11 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pyghmi
3
- Version: 1.5.71
3
+ Version: 1.5.75
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
7
7
  Author-email: jjohnson2@lenovo.com
8
8
  License: Apache License, Version 2.0
9
- Platform: UNKNOWN
10
9
  Classifier: Intended Audience :: Information Technology
11
10
  Classifier: Intended Audience :: System Administrators
12
11
  Classifier: License :: OSI Approved :: Apache Software License
@@ -18,14 +17,14 @@ Classifier: Programming Language :: Python :: 3
18
17
  Classifier: Programming Language :: Python :: 3.6
19
18
  Classifier: Programming Language :: Python :: 3.7
20
19
  Classifier: Programming Language :: Python :: 3.8
21
- Requires-Dist: cryptography (>=2.1)
22
- Requires-Dist: python-dateutil (>=2.8.1)
23
- Requires-Dist: six (>=1.10.0)
20
+ License-File: LICENSE
21
+ License-File: AUTHORS
22
+ Requires-Dist: cryptography >=2.1
23
+ Requires-Dist: python-dateutil >=2.8.1
24
+ Requires-Dist: six >=1.10.0
24
25
 
25
26
  This is a pure python implementation of IPMI protocol.
26
27
 
27
28
  pyghmicons and pyghmiutil are example scripts to show how one may incorporate
28
29
  this library into python code
29
30
 
30
-
31
-