2
0
mirror of https://opendev.org/x/pyghmi synced 2025-01-27 19:37:44 +00:00

Prepare to switch to flake8 - 04

Fourth wave of changes to prepare to migrate to flake8 tests.

Change-Id: I92b56e3f6c64acd05fc4e7a65789e836c47f4000
This commit is contained in:
Riccardo Pittau 2019-12-17 12:16:13 +01:00
parent 8abbd9091e
commit e665ced5b4
17 changed files with 413 additions and 380 deletions

View File

@ -1,5 +1,3 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2013 IBM Corporation
# Copyright 2015-2017 Lenovo
#
@ -14,15 +12,21 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# This represents the low layer message framing portion of IPMI
"""This represents the low layer message framing portion of IPMI"""
from itertools import chain
import socket
import struct
import threading
import pyghmi.constants as const
import pyghmi.exceptions as exc
import pyghmi.ipmi.events as sel
import pyghmi.ipmi.fru as fru
from pyghmi.ipmi.oem.lookup import get_oem_handler
import pyghmi.ipmi.private.util as pygutil
from pyghmi.ipmi import sdr
try:
from pyghmi.ipmi.private import session
@ -32,11 +36,6 @@ try:
from pyghmi.ipmi.private import localsession
except ImportError:
localsession = None
import pyghmi.ipmi.private.util as pygutil
import pyghmi.ipmi.sdr as sdr
import socket
import struct
import threading
try:
range = xrange
@ -96,6 +95,7 @@ def _mask_to_cidr(mask):
def _cidr_to_mask(prefix):
return struct.pack('>I', 2 ** prefix - 1 << (32 - prefix))
class Housekeeper(threading.Thread):
"""A Maintenance thread for housekeeping
@ -106,6 +106,7 @@ class Housekeeper(threading.Thread):
tasks automatically as needed. This is an alternative to calling
wait_for_rsp or eventloop in a thread of the callers design.
"""
def run(self):
Command.eventloop()
@ -130,10 +131,11 @@ class Command(object):
:param onlogon: function to run when logon completes in an asynchronous
fashion. This will result in a greenthread behavior.
:param kg: Optional parameter to use if BMC has a particular Kg configured
:param verifycallback: For OEM extensions that use HTTPS, this function
will be used to evaluate the certificate.
:param keepalive: If False, then an idle connection will logout rather than keepalive
unless held open by console or ongoing activity.
:param verifycallback: For OEM extensions that use HTTPS, this function
will be used to evaluate the certificate.
:param keepalive: If False, then an idle connection will logout rather
than keepalive unless held open by console or ongoing
activity.
"""
def __init__(self, bmc=None, userid=None, password=None, port=623,
@ -338,7 +340,7 @@ class Command(object):
if not isinstance(wait, bool):
waitattempts = wait
if (wait and
newpowerstate in ('on', 'off', 'shutdown', 'softoff')):
newpowerstate in ('on', 'off', 'shutdown', 'softoff')):
if newpowerstate in ('softoff', 'shutdown'):
waitpowerstate = 'off'
else:
@ -368,8 +370,8 @@ class Command(object):
return self._oem.get_video_launchdata()
def reset_bmc(self):
"""Do a cold reset in BMC
"""
"""Do a cold reset in BMC"""
response = self.raw_command(netfn=6, command=2)
if 'error' in response:
raise exc.IpmiException(response['error'])
@ -626,8 +628,8 @@ class Command(object):
for fruid in self._sdr.fru:
if self._sdr.fru[fruid].fru_name == component:
return self._oem.process_fru(fru.FRU(
ipmicmd=self, fruid=fruid, sdr=self._sdr.fru[fruid]).info,
component)
ipmicmd=self, fruid=fruid,
sdr=self._sdr.fru[fruid]).info, component)
return self._oem.get_inventory_of_component(component)
def _get_zero_fru(self):
@ -1913,8 +1915,8 @@ class Command(object):
return True
def get_firmware(self, components=()):
"""Retrieve OEM Firmware information
"""
"""Retrieve OEM Firmware information"""
self.oem_init()
mcinfo = self.xraw_command(netfn=6, command=1)
major, minor = struct.unpack('BB', mcinfo['data'][2:4])
@ -1938,14 +1940,14 @@ class Command(object):
return self._oem.set_oem_capping_enabled(enable)
def get_remote_kvm_available(self):
"""Get remote KVM availability
"""
"""Get remote KVM availability"""
self.oem_init()
return self._oem.get_oem_remote_kvm_available()
def get_domain_name(self):
"""Get Domain name
"""
"""Get Domain name"""
self.oem_init()
return self._oem.get_oem_domain_name()
@ -1962,20 +1964,21 @@ class Command(object):
self.oem_init()
return self._oem.get_graphical_console()
def update_firmware(self, file, data=None, progress=None, bank=None):
def update_firmware(self, filename, data=None, progress=None, bank=None):
"""Send file to BMC to perform firmware update
:param filename: The filename to upload to the target BMC
:param data: The payload of the firmware. Default is to read from
specified filename.
:param progress: A callback that will be given a dict describing
update process. Provide if
:param filename: The filename to upload to the target BMC
:param data: The payload of the firmware. Default is to read from
specified filename.
:param progress: A callback that will be given a dict describing
update process. Provide if
:param bank: Indicate a target 'bank' of firmware if supported
"""
self.oem_init()
if progress is None:
progress = lambda x: True
return self._oem.update_firmware(file, data, progress, bank)
return self._oem.update_firmware(filename, data, progress, bank)
def attach_remote_media(self, url, username=None, password=None):
"""Attach remote media by url

View File

@ -1,5 +1,3 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2014 IBM Corporation
# Copyright 2015-2019 Lenovo
#
@ -15,12 +13,12 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
# This represents the low layer message framing portion of IPMI
"""This represents the low layer message framing portion of IPMI"""
import pyghmi.exceptions as exc
import struct
import threading
import pyghmi.exceptions as exc
from pyghmi.ipmi.private import constants
from pyghmi.ipmi.private import session
from pyghmi.ipmi.private.util import _monotonic_time
@ -75,8 +73,8 @@ class Console(object):
self.callgotsession = None
def _got_session(self, response):
"""Private function to navigate SOL payload activation
"""
"""Private function to navigate SOL payload activation"""
if 'error' in response:
self._print_error(response['error'])
return
@ -190,15 +188,15 @@ class Console(object):
self.pendingoutput[-1] += data
def _got_cons_input(self, handle):
"""Callback for handle events detected by ipmi session
"""
"""Callback for handle events detected by ipmi session"""
self._addpendingdata(handle.read())
if not self.awaitingack:
self._sendpendingoutput()
def close(self):
"""Shut down an SOL session,
"""
"""Shut down an SOL session"""
if self.ipmi_session:
self.ipmi_session.unregister_keepalive(self.keepaliveid)
if self.activated:
@ -331,8 +329,8 @@ class Console(object):
self.out_handler(data)
def _got_sol_payload(self, payload):
"""SOL payload callback
"""
"""SOL payload callback"""
# TODO(jbjohnso) test cases to throw some likely scenarios at functions
# for example, retry with new data, retry with no new data
# retry with unexpected sequence number
@ -457,8 +455,8 @@ class ServerConsole(Console):
session.Session.wait_for_rsp(0)
def _got_sol_payload(self, payload):
"""SOL payload callback
"""
"""SOL payload callback"""
# TODO(jbjohnso) test cases to throw some likely scenarios at functions
# for example, retry with new data, retry with no new data
# retry with unexpected sequence number
@ -540,6 +538,6 @@ class ServerConsole(Console):
needskeepalive=needskeepalive)
def close(self):
"""Shut down an SOL session,
"""
"""Shut down an SOL session"""
self.activated = False

View File

@ -1,5 +1,3 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2016 Lenovo
#
# Licensed under the Apache License, Version 2.0 (the "License");
@ -14,13 +12,12 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# __author__ = 'jjohnson2@lenovo.com'
import struct
import time
import pyghmi.constants as pygconst
import pyghmi.exceptions as pygexc
import pyghmi.ipmi.private.constants as ipmiconst
import struct
import time
try:
range = xrange

View File

@ -1,6 +1,3 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# coding=utf8
# Copyright 2015 Lenovo
#
# Licensed under the Apache License, Version 2.0 (the "License");
@ -15,27 +12,31 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# This module provides access to SDR offered by a BMC
# This data is common between 'sensors' and 'inventory' modules since SDR
# is both used to enumerate sensors for sensor commands and FRU ids for FRU
# commands
"""This module provides access to SDR offered by a BMC
# For now, we will not offer persistent SDR caching as we do in xCAT's IPMI
# code. Will see if it is adequate to advocate for high object reuse in a
# persistent process for the moment.
This data is common between 'sensors' and 'inventory' modules since SDR
is both used to enumerate sensors for sensor commands and FRU ids for FRU
commands
# Focus is at least initially on the aspects that make the most sense for a
# remote client to care about. For example, smbus information is being
# skipped for now
For now, we will not offer persistent SDR caching as we do in xCAT's IPMI
code. Will see if it is adequate to advocate for high object reuse in a
persistent process for the moment.
# This file handles parsing of fru format records as presented by IPMI
# devices. This format is documented in the 'Platform Management FRU
# Information Storage Definition (Document Revision 1.2)
Focus is at least initially on the aspects that make the most sense for a
remote client to care about. For example, smbus information is being
skipped for now
This file handles parsing of fru format records as presented by IPMI
devices. This format is documented in the 'Platform Management FRU
Information Storage Definition (Document Revision 1.2)
"""
import struct
import time
import pyghmi.exceptions as iexc
import pyghmi.ipmi.private.spd as spd
import struct
import time
fruepoch = 820454400 # 1/1/1996, 0:00
@ -242,7 +243,7 @@ class FRU(object):
# removing trailing spaces and nulls like makes sense for text
# and rely on vendors to workaround deviations in their OEM
# module
#retinfo = retinfo.rstrip(b'\x00 ')
# retinfo = retinfo.rstrip(b'\x00 ')
return retinfo, newoffset
elif currtype == 1: # BCD 'plus'
retdata = ''

View File

@ -1,5 +1,3 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2015 Lenovo Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
@ -190,8 +188,8 @@ class OEMHandler(object):
return fru
def get_oem_firmware(self, bmcver, components):
"""Get Firmware information.
"""
"""Get Firmware information."""
# Here the bmc version is passed into the OEM handler, to allow
# the handler to enrich the data. For the generic case, just
# provide the generic BMC version, which is all that is possible
@ -201,7 +199,7 @@ class OEMHandler(object):
# code to know whether it cares or not. The main purpose of the
# components argument is to indicate when certain performance
# optimizations can be performed.
yield ('BMC Version', {'version': bmcver})
yield 'BMC Version', {'version': bmcver}
def get_oem_capping_enabled(self):
"""Get PSU based power capping status
@ -218,13 +216,11 @@ class OEMHandler(object):
return ()
def get_oem_remote_kvm_available(self):
"""Get remote KVM availability
"""
"""Get remote KVM availability"""
return False
def get_oem_domain_name(self):
"""Get Domain name
"""
"""Get Domain name"""
return ()
def set_oem_domain_name(self, name):
@ -309,15 +305,11 @@ class OEMHandler(object):
return []
def set_hostname(self, hostname):
"""OEM specific hook to specify name information
"""
"""OEM specific hook to specify name information"""
raise exc.UnsupportedFunctionality()
def get_hostname(self):
"""OEM specific hook to specify name information
"""
"""OEM specific hook to specify name information"""
raise exc.UnsupportedFunctionality()
def set_user_access(self, uid, channel, callback, link_auth, ipmi_msg,
@ -343,7 +335,8 @@ class OEMHandler(object):
return {}
def set_bmc_configuration(self, changeset):
raise exc.UnsupportedFunctionality('Platform does not support setting bmc attributes')
raise exc.UnsupportedFunctionality(
'Platform does not support setting bmc attributes')
def get_system_configuration(self, hideadvanced):
"""Retrieve system configuration

View File

@ -1,4 +1,15 @@
# -*- coding: utf-8 -*-
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import struct
try:
@ -6,7 +17,8 @@ try:
except NameError:
pass
class BitArray:
class BitArray(object):
def __init__(self, data):
self._Data = bytearray(data)

View File

@ -1,5 +1,3 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2017-2019 Lenovo
#
# Licensed under the Apache License, Version 2.0 (the "License");
@ -14,21 +12,22 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# from Matthew Garret's 'firmware_config' project.
"""from Matthew Garret's 'firmware_config' project.
# This contains functions to manage the firmware configuration of Lenovo
# servers
This contains functions to manage the firmware configuration of Lenovo servers
"""
import ast
import struct
import random
import pyghmi.exceptions as pygexc
import struct
import pyghmi.exceptions as pygexc
from pyghmi.ipmi.oem.lenovo import EfiDecompressor
import six
try:
from lxml import etree
import EfiCompressor
from lxml import etree
except ImportError:
etree = None
EfiCompressor = None
@ -168,7 +167,7 @@ class LenovoFirmwareConfig(object):
data.append(0)
while retries:
retries = retries-1
retries = retries - 1
response = run_command_with_retry(self.connection, data=data)
try:
if response['code'] == 0 or retries == 0:
@ -207,7 +206,7 @@ class LenovoFirmwareConfig(object):
amount = remaining
else:
amount = blocksize
data.extend(inputdata[offset:offset+amount])
data.extend(inputdata[offset:offset + amount])
remaining -= blocksize
offset += blocksize
run_command_with_retry(self.connection, data=data)
@ -378,24 +377,25 @@ class LenovoFirmwareConfig(object):
instidx = 1
for inst in current:
optname = '{0}.{1}'.format(optionname, instidx)
options[optname] = dict(current=inst,
default=default,
possible=possible,
pending=None,
new_value=None,
help=help,
is_list=is_list,
lenovo_value=lenovo_value,
lenovo_id=lenovo_id,
lenovo_group=lenovo_group,
lenovo_setting=lenovo_setting,
lenovo_reboot=reset,
lenovo_protect=protect,
lenovo_instance=instidx,
readonly_expression=readonly,
hide_expression=hide,
sortid=sortid,
alias=alias)
options[optname] = dict(
current=inst,
default=default,
possible=possible,
pending=None,
new_value=None,
help=help,
is_list=is_list,
lenovo_value=lenovo_value,
lenovo_id=lenovo_id,
lenovo_group=lenovo_group,
lenovo_setting=lenovo_setting,
lenovo_reboot=reset,
lenovo_protect=protect,
lenovo_instance=instidx,
readonly_expression=readonly,
hide_expression=hide,
sortid=sortid,
alias=alias)
sortid += 1
instidx += 1
continue
@ -405,24 +405,25 @@ class LenovoFirmwareConfig(object):
for currid in sorted(instancetochoicemap):
optname = '{0}.{1}'.format(optionname, currid)
current = instancetochoicemap[currid]
options[optname] = dict(current=current,
default=default,
possible=possible,
pending=None,
new_value=None,
help=help,
is_list=is_list,
lenovo_value=lenovo_value,
lenovo_id=lenovo_id,
lenovo_group=lenovo_group,
lenovo_setting=lenovo_setting,
lenovo_reboot=reset,
lenovo_protect=protect,
lenovo_instance=currid,
readonly_expression=readonly,
hide_expression=hide,
sortid=sortid,
alias=alias)
options[optname] = dict(
current=current,
default=default,
possible=possible,
pending=None,
new_value=None,
help=help,
is_list=is_list,
lenovo_value=lenovo_value,
lenovo_id=lenovo_id,
lenovo_group=lenovo_group,
lenovo_setting=lenovo_setting,
lenovo_reboot=reset,
lenovo_protect=protect,
lenovo_instance=currid,
readonly_expression=readonly,
hide_expression=hide,
sortid=sortid,
alias=alias)
sortid += 1
continue
lenovoinstance = ""
@ -481,8 +482,7 @@ class LenovoFirmwareConfig(object):
','.join(sorted(options[option]['readonly_why'])))
errstr += ea
raise pygexc.InvalidParameterValue(errstr)
if (isinstance(options[option]['new_value'], str) or
isinstance(options[option]['new_value'], unicode)):
if isinstance(options[option]['new_value'], six.string_types):
# Coerce a simple string parameter to the expected list format
options[option]['new_value'] = [options[option]['new_value']]
options[option]['pending'] = options[option]['new_value']
@ -495,7 +495,8 @@ class LenovoFirmwareConfig(object):
setting = etree.Element('setting',
ID=options[option]['lenovo_setting'])
if options[option]['lenovo_group'] is not None:
group = etree.Element('group', ID=options[option]['lenovo_group'])
group = etree.Element('group',
ID=options[option]['lenovo_group'])
config.append(group)
group.append(setting)
else:

View File

@ -1,5 +1,3 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2015 Lenovo
#
# Licensed under the Apache License, Version 2.0 (the "License");
@ -14,24 +12,23 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from pyghmi.ipmi.oem.lenovo.inventory import EntryField, \
parse_inventory_category_entry
from pyghmi.ipmi.oem.lenovo import inventory
cpu_fields = (
EntryField("index", "B"),
EntryField("Cores", "B"),
EntryField("Threads", "B"),
EntryField("Manufacturer", "13s"),
EntryField("Family", "30s"),
EntryField("Model", "30s"),
EntryField("Stepping", "3s"),
EntryField("Maximum Frequency", "<I",
valuefunc=lambda v: str(v) + " MHz"),
EntryField("Reserved", "h", include=False))
inventory.EntryField("index", "B"),
inventory.EntryField("Cores", "B"),
inventory.EntryField("Threads", "B"),
inventory.EntryField("Manufacturer", "13s"),
inventory.EntryField("Family", "30s"),
inventory.EntryField("Model", "30s"),
inventory.EntryField("Stepping", "3s"),
inventory.EntryField("Maximum Frequency", "<I",
valuefunc=lambda v: str(v) + " MHz"),
inventory.EntryField("Reserved", "h", include=False))
def parse_cpu_info(raw):
return parse_inventory_category_entry(raw, cpu_fields)
return inventory.parse_inventory_category_entry(raw, cpu_fields)
def get_categories():

View File

@ -1,5 +1,3 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2015 Lenovo
#
# Licensed under the Apache License, Version 2.0 (the "License");
@ -14,29 +12,29 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from pyghmi.ipmi.oem.lenovo.inventory import EntryField, \
parse_inventory_category_entry
from pyghmi.ipmi.oem.lenovo import inventory
dimm_fields = (
EntryField("index", "B"),
EntryField("manufacture_location", "B"),
EntryField("channel_number", "B"),
EntryField("module_type", "10s"),
EntryField("ddr_voltage", "10s"),
EntryField("speed", "<h",
valuefunc=lambda v: str(v) + " MHz"),
EntryField("capacity_mb", "<h",
valuefunc=lambda v: v*1024),
EntryField("manufacturer", "30s"),
EntryField("serial", ">I",
valuefunc=lambda v: hex(v)[2:]),
EntryField("model", "21s"),
EntryField("reserved", "h", include=False)
inventory.EntryField("index", "B"),
inventory.EntryField("manufacture_location", "B"),
inventory.EntryField("channel_number", "B"),
inventory.EntryField("module_type", "10s"),
inventory.EntryField("ddr_voltage", "10s"),
inventory.EntryField("speed", "<h",
valuefunc=lambda v: str(v) + " MHz"),
inventory.EntryField("capacity_mb", "<h",
valuefunc=lambda v: v * 1024),
inventory.EntryField("manufacturer", "30s"),
inventory.EntryField("serial", ">I",
valuefunc=lambda v: hex(v)[2:]),
inventory.EntryField("model", "21s"),
inventory.EntryField("reserved", "h", include=False)
)
def parse_dimm_info(raw):
return parse_inventory_category_entry(raw, dimm_fields)
return inventory.parse_inventory_category_entry(raw, dimm_fields)
def get_categories():

View File

@ -1,5 +1,3 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2015 Lenovo
#
# Licensed under the Apache License, Version 2.0 (the "License");
@ -14,49 +12,48 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from pyghmi.ipmi.oem.lenovo.inventory import EntryField, \
parse_inventory_category_entry
from pyghmi.ipmi.oem.lenovo import inventory
drive_fields = (
EntryField("index", "B"),
EntryField("VendorID", "64s"),
EntryField("Size", "I",
valuefunc=lambda v: str(v) + " MB"),
EntryField("MediaType", "B", mapper={
inventory.EntryField("index", "B"),
inventory.EntryField("VendorID", "64s"),
inventory.EntryField("Size", "I",
valuefunc=lambda v: str(v) + " MB"),
inventory.EntryField("MediaType", "B", mapper={
0x00: "HDD",
0x01: "SSD"
}),
EntryField("InterfaceType", "B", mapper={
inventory.EntryField("InterfaceType", "B", mapper={
0x00: "Unknown",
0x01: "ParallelSCSI",
0x02: "SAS",
0x03: "SATA",
0x04: "FC"
}),
EntryField("FormFactor", "B", mapper={
inventory.EntryField("FormFactor", "B", mapper={
0x00: "Unknown",
0x01: "2.5in",
0x02: "3.5in"
}),
EntryField("LinkSpeed", "B", mapper={
inventory.EntryField("LinkSpeed", "B", mapper={
0x00: "Unknown",
0x01: "1.5 Gb/s",
0x02: "3.0 Gb/s",
0x03: "6.0 Gb/s",
0x04: "12.0 Gb/s"
}),
EntryField("SlotNumber", "B"),
EntryField("DeviceState", "B", mapper={
inventory.EntryField("SlotNumber", "B"),
inventory.EntryField("DeviceState", "B", mapper={
0x00: "active",
0x01: "stopped",
0xff: "transitioning"
}),
# There seems to be an undocumented byte at the end
EntryField("Reserved", "B", include=False))
inventory.EntryField("Reserved", "B", include=False))
def parse_drive_info(raw):
return parse_inventory_category_entry(raw, drive_fields)
return inventory.parse_inventory_category_entry(raw, drive_fields)
def get_categories():

View File

@ -1,5 +1,3 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2017 Lenovo
#
# Licensed under the Apache License, Version 2.0 (the "License");
@ -14,9 +12,10 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import pyghmi.exceptions as pygexc
import struct
import pyghmi.exceptions as pygexc
class EnergyManager(object):

View File

@ -1,5 +1,3 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2015 Lenovo
#
# Licensed under the Apache License, Version 2.0 (the "License");
@ -14,33 +12,34 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from pyghmi.ipmi.oem.lenovo.inventory import EntryField, \
parse_inventory_category_entry
from pyghmi.ipmi.oem.lenovo import inventory
firmware_fields = (
EntryField("Revision", "B"),
EntryField("Bios", "16s"),
EntryField("Operational ME", "10s"),
EntryField("Recovery ME", "10s"),
EntryField("RAID 1", "16s"),
EntryField("RAID 2", "16s"),
EntryField("Mezz 1", "16s"),
EntryField("Mezz 2", "16s"),
EntryField("BMC", "16s"),
EntryField("LEPT", "16s"),
EntryField("PSU 1", "16s"),
EntryField("PSU 2", "16s"),
EntryField("CPLD", "16s"),
EntryField("LIND", "16s"),
EntryField("WIND", "16s"),
EntryField("DIAG", "16s"))
inventory.EntryField("Revision", "B"),
inventory.EntryField("Bios", "16s"),
inventory.EntryField("Operational ME", "10s"),
inventory.EntryField("Recovery ME", "10s"),
inventory.EntryField("RAID 1", "16s"),
inventory.EntryField("RAID 2", "16s"),
inventory.EntryField("Mezz 1", "16s"),
inventory.EntryField("Mezz 2", "16s"),
inventory.EntryField("BMC", "16s"),
inventory.EntryField("LEPT", "16s"),
inventory.EntryField("PSU 1", "16s"),
inventory.EntryField("PSU 2", "16s"),
inventory.EntryField("CPLD", "16s"),
inventory.EntryField("LIND", "16s"),
inventory.EntryField("WIND", "16s"),
inventory.EntryField("DIAG", "16s"))
def parse_firmware_info(raw):
bytes_read, data = parse_inventory_category_entry(raw, firmware_fields)
bytes_read, data = inventory.parse_inventory_category_entry(
raw, firmware_fields)
del data['Revision']
for key in data:
yield(key, {'version': data[key]})
yield key, {'version': data[key]}
def get_categories():

View File

@ -1,5 +1,3 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2015-2017 Lenovo
#
# Licensed under the Apache License, Version 2.0 (the "License");
@ -16,22 +14,17 @@
import base64
import binascii
import socket
import struct
import traceback
try:
from urllib import urlencode
except ImportError:
from urllib.parse import urlencode
import weakref
import pyghmi.constants as pygconst
import pyghmi.exceptions as pygexc
import pyghmi.ipmi.oem.generic as generic
import pyghmi.ipmi.private.constants as ipmiconst
import pyghmi.ipmi.private.util as util
from pyghmi.ipmi.oem.lenovo import cpu
from pyghmi.ipmi.oem.lenovo import dimm
from pyghmi.ipmi.oem.lenovo import drive
from pyghmi.ipmi.oem.lenovo import firmware
from pyghmi.ipmi.oem.lenovo import imm
from pyghmi.ipmi.oem.lenovo import inventory
@ -40,15 +33,17 @@ from pyghmi.ipmi.oem.lenovo import pci
from pyghmi.ipmi.oem.lenovo import psu
from pyghmi.ipmi.oem.lenovo import raid_controller
from pyghmi.ipmi.oem.lenovo import raid_drive
from pyghmi.redfish.oem.lenovo import tsma
import pyghmi.ipmi.private.constants as ipmiconst
import pyghmi.ipmi.private.util as util
import pyghmi.redfish.command as redfishcmd
from pyghmi.redfish.oem.lenovo import tsma
import pyghmi.util.webclient as wc
import socket
import struct
import weakref
try:
from urllib import urlencode
except ImportError:
from urllib.parse import urlencode
try:
range = xrange
except NameError:
@ -162,10 +157,11 @@ class OEMHandler(generic.OEMHandler):
elif self.is_fpc:
self.smmhandler = nextscale.SMMClient(ipmicmd)
elif self.has_tsma:
conn = wc.SecureHTTPConnection(ipmicmd.bmc, 443,
conn = wc.SecureHTTPConnection(
ipmicmd.bmc, 443,
verifycallback=self.ipmicmd.certverify)
#sysinfo, sysurl, webclient, cache=None):
self.tsmahandler = tsma.TsmHandler(None, None, conn, fish=redfishcmd)
self.tsmahandler = tsma.TsmHandler(None, None, conn,
fish=redfishcmd)
self.tsmahandler.set_credentials(
ipmicmd.ipmi_session.userid.decode('utf-8'),
ipmicmd.ipmi_session.password.decode('utf-8'))
@ -254,12 +250,12 @@ class OEMHandler(generic.OEMHandler):
event['severity'] = pygconst.Health.Ok
event['component'] = 'User Privilege'
event['component_type'] = ipmiconst.sensor_type_codes[6]
event['event_data'] = \
'User {0} on channel {1} had privilege changed ' \
event['event_data'] = (
'User {0} on channel {1} had privilege changed '
'from {2} to {3}'.format(
oemdata[2], oemdata[1], oemdata[3] & 0b1111,
(oemdata[3] & 0b11110000) >> 4
)
(oemdata[3] & 0b11110000) >> 4)
)
else:
event['event'] = 'OEM event: {0}'.format(
' '.join(format(x, '02x') for x in event['oemdata']))
@ -342,13 +338,13 @@ class OEMHandler(generic.OEMHandler):
def set_user_access(self, uid, channel, callback, link_auth, ipmi_msg,
privilege_level):
if self.is_fpc and self._fpc_variant == 2:
if self.is_fpc and self._fpc_variant == 2:
self.smmhandler.set_user_priv(uid, privilege_level)
@property
def is_fpc(self):
"""True if the target is a Lenovo nextscale fan power controller
"""
"""True if the target is a Lenovo nextscale fan power controller"""
if self.has_imm or self.has_xcc:
return None
if self._fpc_variant is not None:
@ -378,8 +374,8 @@ class OEMHandler(generic.OEMHandler):
@property
def has_tsm(self):
"""True if this particular server have a TSM based service processor
"""
"""True if this particular server have a TSM based service processor"""
if (self.oemid['manufacturer_id'] == 19046 and
self.oemid['device_id'] == 32):
try:
@ -559,7 +555,7 @@ class OEMHandler(generic.OEMHandler):
endidx = len(macs) - 5
macprefix = None
while idx < endidx:
currmac = macs[idx:idx+6]
currmac = macs[idx:idx + 6]
if not isinstance(currmac, bytearray):
# invalid vpd format, abort attempts to extract
# mac in this way
@ -638,16 +634,20 @@ class OEMHandler(generic.OEMHandler):
return nextscale.get_fpc_firmware(bmcver, self.ipmicmd,
self._fpc_variant)
elif self.has_tsma:
return self.tsmahandler.get_firmware_inventory(components, raisebypass=False)
return self.tsmahandler.get_firmware_inventory(components,
raisebypass=False)
return super(OEMHandler, self).get_oem_firmware(bmcver, components)
def get_diagnostic_data(self, savefile, progress, autosuffix=False):
if self.has_xcc:
return self.immhandler.get_diagnostic_data(savefile, progress, autosuffix)
return self.immhandler.get_diagnostic_data(savefile, progress,
autosuffix)
if self.is_fpc:
return self.smmhandler.get_diagnostic_data(savefile, progress, autosuffix)
return self.smmhandler.get_diagnostic_data(savefile, progress,
autosuffix)
if self.has_tsma:
return self.tsmahandler.get_diagnostic_data(savefile, progress, autosuffix)
return self.tsmahandler.get_diagnostic_data(savefile, progress,
autosuffix)
def get_oem_capping_enabled(self):
if self.has_tsm:
@ -706,9 +706,9 @@ class OEMHandler(generic.OEMHandler):
# set the domain name content
name = name.ljust(256, "\x00")
for i in range(0, 4):
data = [4, i+1]
offset = i*64
data.extend([ord(x) for x in name[offset:offset+64]])
data = [4, i + 1]
offset = i * 64
data.extend([ord(x) for x in name[offset:offset + 64]])
self.ipmicmd.xraw_command(netfn=0x32, command=0x6c, data=data)
self._restart_dns()
@ -799,7 +799,7 @@ class OEMHandler(generic.OEMHandler):
else:
# fall back to a dumber, but more universal formatter
ipv6str = binascii.b2a_hex(ipv6_addr)
ipv6str = ':'.join([ipv6str[x:x+4] for x in range(0, 32, 4)])
ipv6str = ':'.join([ipv6str[x:x + 4] for x in range(0, 32, 4)])
netdata['ipv6_addresses'] = [
'{0}/{1}'.format(ipv6str, ipv6_prefix)]
@ -858,7 +858,7 @@ class OEMHandler(generic.OEMHandler):
data=(1, selector, 0, 1))
# now do the set
for x in range(0, 256, 64):
currdata = padded[x:x+64]
currdata = padded[x:x + 64]
currchunk = x // 64 + 1
cmddata = [1, selector, currchunk] + currdata
self.ipmicmd.xraw_command(netfn=0x32, command=0x9f, data=cmddata)
@ -872,7 +872,7 @@ class OEMHandler(generic.OEMHandler):
imgnames = rsp['data'][1:]
shortnames = []
for idx in range(0, len(imgnames), 22):
shortnames.append(imgnames[idx+2:idx+22].rstrip('\0'))
shortnames.append(imgnames[idx + 2:idx + 22].rstrip('\0'))
return shortnames
def _megarac_media_waitforready(self, imagename):

View File

@ -1,6 +1,3 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# coding=utf8
# Copyright 2016-2019 Lenovo
#
# Licensed under the Apache License, Version 2.0 (the "License");
@ -23,25 +20,28 @@ import fnmatch
import json
import math
import os.path
import random
import re
import socket
import struct
import weakref
import pyghmi.constants as pygconst
import pyghmi.exceptions as pygexc
import pyghmi.ipmi.oem.lenovo.config as config
import pyghmi.ipmi.oem.lenovo.energy as energy
import pyghmi.ipmi.private.session as ipmisession
import pyghmi.ipmi.private.util as util
import pyghmi.ipmi.sdr as sdr
from pyghmi.ipmi import sdr
import pyghmi.media as media
import pyghmi.storage as storage
import pyghmi.util.webclient as webclient
import random
import re
import socket
import struct
import six
try:
from urllib import urlencode
except ImportError:
from urllib.parse import urlencode
import weakref
numregex = re.compile('([0-9]+)')
@ -55,10 +55,11 @@ funtypes = {
12: 'Fabric Controller',
}
def naturalize_string(key):
"""Analyzes string in a human way to enable natural sort
:param nodename: The node name to analyze
:param key: string for the split
:returns: A structure that can be consumed by 'sorted'
"""
return [int(text) if text.isdigit() else text.lower()
@ -185,7 +186,8 @@ class IMMClient(object):
try:
self.fwo = self.fwc.get_fw_options()
except Exception:
raise Exception(self.bmcname + ' failed to retrieve UEFI configuration')
raise Exception(self.bmcname +
' failed to retrieve UEFI configuration')
self.fwovintage = util._monotonic_time()
retcfg = {}
for opt in self.fwo:
@ -229,8 +231,7 @@ class IMMClient(object):
raise pygexc.InvalidParameterValue(
'{0} not a known setting'.format(key))
for key in changeset:
if (isinstance(changeset[key], str) or
isinstance(changeset[key], unicode)):
if isinstance(changeset[key], six.string_types):
changeset[key] = {'value': changeset[key]}
newvalue = changeset[key]['value']
if self.fwo[key]['is_list'] and not isinstance(newvalue, list):
@ -244,12 +245,12 @@ class IMMClient(object):
newvalues = [newvalue]
newnewvalues = []
for newvalue in newvalues:
newv = re.sub('\s+', ' ', newvalue)
newv = re.sub(r'\s+', ' ', newvalue)
if (self.fwo[key]['possible'] and
newvalue not in self.fwo[key]['possible']):
candlist = []
for candidate in self.fwo[key]['possible']:
candid = re.sub('\s+', ' ', candidate)
candid = re.sub(r'\s+', ' ', candidate)
if newv.lower().startswith(candid.lower()):
newvalue = candidate
break
@ -277,7 +278,8 @@ class IMMClient(object):
raise
def clear_bmc_configuration(self):
self.ipmicmd.xraw_command(0x2e, 0xcc, data=(0x5e, 0x2b, 0, 0xa, 1, 0xff, 0, 0, 0))
self.ipmicmd.xraw_command(0x2e, 0xcc,
data=(0x5e, 0x2b, 0, 0xa, 1, 0xff, 0, 0, 0))
def set_property(self, propname, value):
if not isinstance(value, int) or value > 255:
@ -285,7 +287,7 @@ class IMMClient(object):
propname = propname.encode('utf-8')
proplen = len(propname) | 0b10000000
valuelen = 0x11 # The value is always one byte, for now
cmdlen = len(propname) + 4 # the flags byte, two tlv bytes, and value
cmdlen = len(propname) + 4 # the flags byte, two tlv bytes, and value
cdata = bytearray([3, 0, cmdlen, 1, proplen]) + propname
cdata += bytearray([valuelen, value])
rsp = self.ipmicmd.xraw_command(netfn=0x3a, command=0xc4, data=cdata)
@ -324,8 +326,7 @@ class IMMClient(object):
return None
adata = urlencode({'user': self.username,
'password': self.password,
'SessionTimeout': 60
})
'SessionTimeout': 60})
headers = {'Connection': 'keep-alive',
'Referer': 'https://{0}/designs/imm/index.php'.format(
self.imm),
@ -369,7 +370,6 @@ class IMMClient(object):
if returnit:
return retdata
def grab_cacheable_json(self, url, age=30):
data = self.get_cached_data(url, age)
if not data:
@ -427,7 +427,7 @@ class IMMClient(object):
progress({'phase': 'complete'})
def attach_remote_media(self, url, user, password):
url = url.replace(':', '\:')
url = url.replace(':', '\\:')
params = urlencode({
'RP_VmAllocateMountUrl({0},{1},1,,)'.format(
self.username, url): ''
@ -466,7 +466,7 @@ class IMMClient(object):
'/data/set', 'RP_RemoveFile({0}, 0)'.format(
uload['slotId']))
for url in removeurls:
url = url.replace(':', '\:')
url = url.replace(':', '\\:')
params = urlencode({
'RP_VmAllocateUnMountUrl({0},{1},0,)'.format(
self.username, url): ''})
@ -496,8 +496,8 @@ class IMMClient(object):
adapterdata = self.wc.grab_json_response(
self.ADP_URL, referer=self.adp_referer)
if self.ADP_FU_URL:
fwu = self.wc.grab_json_response(self.ADP_FU_URL,
referer=self.adp_referer)
fwu = self.wc.grab_json_response(
self.ADP_FU_URL, referer=self.adp_referer)
else:
fwu = {}
if adapterdata:
@ -549,7 +549,7 @@ class IMMClient(object):
self.weblogout()
def disk_inventory(self, mode=0):
if mode==1:
if mode == 1:
# Bypass IMM hardware inventory for now
return
storagedata = self.get_cached_data('lenovo_cached_storage')
@ -647,7 +647,7 @@ class IMMClient(object):
'Model': fixup_str(model),
'Serial': fixup_str(serial),
}
for disk in self.disk_inventory(mode=1): # hardware mode
for disk in self.disk_inventory(mode=1): # hardware mode
hwmap[disk[0]] = disk[1]
adapterdata = self.get_cached_data('lenovo_cached_adapters')
if not adapterdata:
@ -716,7 +716,7 @@ class IMMClient(object):
for lp in portinfo['logicalPorts']:
ma = lp['networkAddr']
ma = ':'.join(
[ma[i:i+2] for i in range(
[ma[i:i + 2] for i in range(
0, len(ma), 2)]).lower()
bdata['MAC Address {0}'.format(
portinfo['portIndex'])] = ma
@ -827,13 +827,20 @@ class XCCClient(IMMClient):
settings = {}
passrules = self.wc.grab_json_response('/api/dataset/imm_users_global')
passrules = passrules.get('items', [{}])[0]
settings['password_reuse_count'] = {'value': passrules.get('pass_min_resuse')}
settings['password_change_interval'] = {'value': passrules.get('pass_change_interval')}
settings['password_expiration'] = {'value': passrules.get('pass_expire_days')}
settings['password_login_failures'] = {'value': passrules.get('max_login_failures')}
settings['password_complexity'] = {'value': passrules.get('pass_complex_required')}
settings['password_min_length'] = {'value': passrules.get('pass_min_length')}
settings['password_lockout_period'] = {'value': passrules.get('lockout_period')}
settings['password_reuse_count'] = {
'value': passrules.get('pass_min_resuse')}
settings['password_change_interval'] = {
'value': passrules.get('pass_change_interval')}
settings['password_expiration'] = {
'value': passrules.get('pass_expire_days')}
settings['password_login_failures'] = {
'value': passrules.get('max_login_failures')}
settings['password_complexity'] = {
'value': passrules.get('pass_complex_required')}
settings['password_min_length'] = {
'value': passrules.get('pass_min_length')}
settings['password_lockout_period'] = {
'value': passrules.get('lockout_period')}
try:
enclosureinfo = self.ipmicmd.xraw_command(0x3a, 0xf1, data=[0])
except pygexc.IpmiException:
@ -841,7 +848,8 @@ class XCCClient(IMMClient):
settings['smm'] = {
'default': 'Disable',
'possible': ['Enable', 'Disable'],
'help': 'Enables or disables the network of the D2 enclosure manager.',
'help': 'Enables or disables the network of the D2 '
'enclosure manager.',
}
if bytearray(enclosureinfo['data'])[0] == 2:
settings['smm']['value'] = 'Disable'
@ -864,8 +872,7 @@ class XCCClient(IMMClient):
def set_bmc_configuration(self, changeset):
ruleset = {}
for key in changeset:
if (isinstance(changeset[key], str) or
isinstance(changeset[key], unicode)):
if isinstance(changeset[key], six.string_types):
changeset[key] = {'value': changeset[key]}
currval = changeset[key].get('value', None)
if 'smm'.startswith(key.lower()):
@ -880,17 +887,21 @@ class XCCClient(IMMClient):
ruleset['USER_GlobalPassExpWarningPeriod'] = warntime
else:
raise pygexc.InvalidParameterValue(
'{0} not a known setting'.format(key))
'{0} not a known setting'.format(key))
if ruleset:
rsp = self.wc.grab_json_response('/api/dataset', ruleset)
self.wc.grab_json_response('/api/dataset', ruleset)
def clear_system_configuration(self):
res = self.wc.grab_json_response_with_status(
'/redfish/v1/Systems/1/Bios/Actions/Bios.ResetBios',
{'Action': 'Bios.ResetBios'},
headers={'Authorization': 'Basic ' + base64.b64encode(
self.username + ':' + self.password),
'Content-Type': 'application/json'})
'/redfish/v1/Systems/1/Bios/Actions/Bios.ResetBios',
{'Action': 'Bios.ResetBios'},
headers={
'Authorization': 'Basic ' +
base64.b64encode(
self.username + ':' + self.password),
'Content-Type': 'application/json'
}
)
if res[1] < 200 or res[1] >= 300:
raise Exception(
'Unexpected response to clear configuration: {0}'.format(
@ -995,21 +1006,21 @@ class XCCClient(IMMClient):
if storagedata and 'items' in storagedata:
for adp in storagedata['items']:
for diskent in adp.get('disks', ()):
if mode==0:
if mode == 0:
yield self.get_disk_firmware(diskent)
elif mode==1:
elif mode == 1:
yield self.get_disk_hardware(diskent)
for diskent in adp.get('aimDisks', ()):
if mode==0:
if mode == 0:
yield self.get_disk_firmware(diskent)
elif mode==1:
elif mode == 1:
yield self.get_disk_hardware(diskent)
if mode == 1:
bdata = {'Description': 'Unmanaged Disk'}
if adp.get('m2Type', -1) == 2:
yield ('M.2 Disk', bdata)
yield 'M.2 Disk', bdata
for umd in adp.get('unmanagedDisks', []):
yield ('Disk {0}'.format(umd['slotNo']), bdata)
yield 'Disk {0}'.format(umd['slotNo']), bdata
def get_disk_hardware(self, diskent, prefix=''):
bdata = {}
@ -1084,7 +1095,8 @@ class XCCClient(IMMClient):
'perspan': drivesperspan,
}
else:
pass # TODO: adding new volume to existing array would be here
# TODO(): adding new volume to existing array would be here
pass
def _make_jbod(self, disk, realcfg):
currstatus = self._get_status(disk, realcfg)
@ -1252,7 +1264,8 @@ class XCCClient(IMMClient):
def get_oem_sensor_names(self, ipmicmd):
oemsensornames = super(XCCClient, self).get_oem_sensor_names(ipmicmd)
therminfo = self.grab_cacheable_json('/api/dataset/pwrmgmt?params=GetThermalRealTimeData', 1)
therminfo = self.grab_cacheable_json(
'/api/dataset/pwrmgmt?params=GetThermalRealTimeData', 1)
if therminfo:
for name in sorted(therminfo['items'][0]):
if 'DIMM' in name and 'Temp' in name:
@ -1260,9 +1273,10 @@ class XCCClient(IMMClient):
return oemsensornames
def get_oem_sensor_descriptions(self, ipmicmd):
oemdesc = [{'name': x, 'type': 'Energy'
} for x in super(XCCClient, self).get_oem_sensor_names(ipmicmd)]
therminfo = self.grab_cacheable_json('/api/dataset/pwrmgmt?params=GetThermalRealTimeData', 1)
oemdesc = [{'name': x, 'type': 'Energy'} for x in super(
XCCClient, self).get_oem_sensor_names(ipmicmd)]
therminfo = self.grab_cacheable_json(
'/api/dataset/pwrmgmt?params=GetThermalRealTimeData', 1)
if therminfo:
for name in sorted(therminfo['items'][0]):
if 'DIMM' in name and 'Temp' in name:
@ -1272,7 +1286,8 @@ class XCCClient(IMMClient):
def get_oem_sensor_reading(self, name, ipmicmd):
if 'Energy' in name:
return super(XCCClient, self).get_oem_sensor_reading(name, ipmicmd)
therminfo = self.grab_cacheable_json('/api/dataset/pwrmgmt?params=GetThermalRealTimeData', 1)
therminfo = self.grab_cacheable_json(
'/api/dataset/pwrmgmt?params=GetThermalRealTimeData', 1)
temp = therminfo.get('items', [{}])[0].get(name, None)
if temp is None:
raise pygexc.UnsupportedFunctionality('No sunch sensor ' + name)
@ -1387,10 +1402,8 @@ class XCCClient(IMMClient):
return
for psu in psudata.get('items', ()):
yield ('PSU {0}'.format(psu['slot']),
{
'model': psu['model'],
'version': psu['version'],
})
{'model': psu['model'],
'version': psu['version']})
def get_firmware_inventory(self, bmcver, components):
# First we fetch the system firmware found in imm properties
@ -1432,47 +1445,48 @@ class XCCClient(IMMClient):
'version': '/v2/ibmc/dm/fw/imm3/primary_pending_build_version',
'date': '/v2/ibmc/dm/fw/imm3/primary_pending_build_date'})
if bdata:
yield ('{0} Pending Update'.format(self.bmcname), bdata)
if (not components or set(('core', 'uefi', 'bios')) & components):
yield '{0} Pending Update'.format(self.bmcname), bdata
if not components or set(('core', 'uefi', 'bios')) & components:
bdata = self.fetch_grouped_properties({
'build': '/v2/bios/build_id',
'version': '/v2/bios/build_version',
'date': '/v2/bios/build_date'})
if bdata:
yield ('UEFI', bdata)
yield 'UEFI', bdata
# Note that the next pending could be pending for either primary
# or backup, so can't promise where it will go
bdata = self.fetch_grouped_properties({
'build': '/v2/bios/pending_build_id'})
if bdata:
yield ('UEFI Pending Update', bdata)
yield 'UEFI Pending Update', bdata
if not components or set(('lxpm', 'core')) & components:
bdata = self.fetch_grouped_properties({
'build': '/v2/tdm/build_id',
'version': '/v2/tdm/build_version',
'date': '/v2/tdm/build_date'})
if bdata:
yield ('LXPM', bdata)
yield 'LXPM', bdata
bdata = self.fetch_grouped_properties({
'build': '/v2/drvwn/build_id',
'version': '/v2/drvwn/build_version',
'date': '/v2/drvwn/build_date',
})
if bdata:
yield ('LXPM Windows Driver Bundle', bdata)
yield 'LXPM Windows Driver Bundle', bdata
bdata = self.fetch_grouped_properties({
'build': '/v2/drvln/build_id',
'version': '/v2/drvln/build_version',
'date': '/v2/drvln/build_date',
})
if bdata:
yield ('LXPM Linux Driver Bundle', bdata)
yield 'LXPM Linux Driver Bundle', bdata
if not components or set(('core', 'fpga')) in components:
try:
fpga = self.ipmicmd.xraw_command(netfn=0x3a, command=0x6b,
data=(0,))
fpga = '{0}.{1}.{2}'.format(*struct.unpack('BBB', fpga['data']))
yield ('FPGA', {'version': fpga})
fpga = '{0}.{1}.{2}'.format(
*struct.unpack('BBB', fpga['data']))
yield 'FPGA', {'version': fpga}
except pygexc.IpmiException as ie:
if ie.ipmicode != 193:
raise
@ -1633,7 +1647,8 @@ class XCCClient(IMMClient):
progress({'phase': 'upload',
'progress': 100.0 * rsp['received'] / rsp['size']})
elif rsp['state'] != 'done':
if rsp.get('status', None) == 413 or uploadthread.rspstatus == 413:
if (rsp.get('status', None) == 413 or
uploadthread.rspstatus == 413):
raise Exception('File is larger than supported')
raise Exception('Unexpected result:' + repr(rsp))
uploadstate = rsp['state']
@ -1669,7 +1684,8 @@ class XCCClient(IMMClient):
elif rsp.get('return', -1) == 108:
raise Exception('Temporary error validating update, try again')
elif rsp.get('return', -1) == 109:
raise Exception('Invalid update file or component does not support remote update')
raise Exception('Invalid update file or component does '
'not support remote update')
elif rsp.get('return', -1) != 0:
errmsg = repr(rsp) if rsp else self.wc.lastjsonerror
raise Exception('Unexpected return to verify: ' + errmsg)
@ -1680,12 +1696,13 @@ class XCCClient(IMMClient):
rsp, status = self.wc.grab_json_response_with_status(
'/api/providers/fwupdate',
json.dumps({'UPD_WebVerifyUploadFileStatus': 1}))
if not rsp or status != 200 or rsp.get('return', -1) == 2:
if not rsp or status != 200 or rsp.get('return', -1) == 2:
# The XCC firmware predates the FileStatus api
verifyuploadfilersp = rsp
break
if rsp.get('return', -1) == 109:
raise Exception('Invalid update file or component does not support remote update')
raise Exception('Invalid update file or component does '
'not support remote update')
if rsp.get('return', -1) != 0:
errmsg = repr(rsp) if rsp else self.wc.lastjsonerror
raise Exception(
@ -1714,7 +1731,7 @@ class XCCClient(IMMClient):
'TDM', 'WINDOWS DRIV', 'LINUX DRIVER', 'UEFI', 'IMM'):
# adapter firmware
webid = rsp['items'][0]['webfile_build_id']
locations = webid[webid.find('[')+1:webid.find(']')]
locations = webid[webid.find('[') + 1:webid.find(']')]
locations = locations.split(':')
validselectors = set([])
for loc in locations:
@ -1801,7 +1818,8 @@ class XCCClient(IMMClient):
def augment_psu_info(self, info, psuname):
psud = self.get_cached_data('lenovo_cached_psuhwinfo')
if not psud:
psud = self.wc.grab_json_response('/api/dataset/imm_power_supplies')
psud = self.wc.grab_json_response(
'/api/dataset/imm_power_supplies')
if not psud:
return
self.datacache['lenovo_cached_psuhwinfo'] = (
@ -1818,7 +1836,7 @@ class XCCClient(IMMClient):
except (socket.timeout, socket.error) as e:
wc = None
if not wc:
summary['health'] = pygconst.Health.Critical;
summary['health'] = pygconst.Health.Critical
summary['badreadings'].append(
sdr.SensorReading({'name': 'HTTPS Service',
'states': ['Unreachable'],
@ -1848,7 +1866,8 @@ class XCCClient(IMMClient):
# while usually the ipmi interrogation shall explain things,
# just in case there is a gap, make sure at least the
# health field is accurately updated
itemseverity = hmap.get(item.get('severity', 'E'), pygconst.Health.Critical)
itemseverity = hmap.get(item.get('severity', 'E'),
pygconst.Health.Critical)
if (summary['health'] < itemseverity):
summary['health'] = itemseverity
if item['cmnid'] == 'FQXSPPW0104J':
@ -1896,7 +1915,8 @@ class XCCClient(IMMClient):
if lic['status'] == 0:
yield {'name': lic['feature'], 'state': 'Active'}
elif lic['status'] == 10:
yield {'name': lic['feature'], 'state': 'Missing required license'}
yield {'name': lic['feature'],
'state': 'Missing required license'}
def save_licenses(self, directory):
licdata = self.wc.grab_json_response('/api/providers/imm_fod')
@ -1938,8 +1958,8 @@ class XCCClient(IMMClient):
rsp = json.loads(uploadthread.rsp)
licpath = rsp.get('items', [{}])[0].get('path', None)
if licpath:
rsp = self.wc.grab_json_response('/api/providers/imm_fod',
{'FOD_LicenseKeyInstall': licpath})
rsp = self.wc.grab_json_response(
'/api/providers/imm_fod', {'FOD_LicenseKeyInstall': licpath})
if rsp.get('return', 0) in license_errors:
raise pygexc.InvalidParameterValue(
license_errors[rsp['return']])

View File

@ -17,7 +17,7 @@
import pyghmi.constants as pygconst
import pyghmi.exceptions as pygexc
import pyghmi.ipmi.private.session as ipmisession
import pyghmi.ipmi.sdr as sdr
from pyghmi.ipmi import sdr
import pyghmi.util.webclient as webclient
import struct
try:

View File

@ -1,6 +1,3 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# coding=utf8
# Copyright 2014 IBM Corporation
# Copyright 2015 Lenovo
#
@ -16,28 +13,35 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# This module provides access to SDR offered by a BMC
# This data is common between 'sensors' and 'inventory' modules since SDR
# is both used to enumerate sensors for sensor commands and FRU ids for FRU
# commands
"""This module provides access to SDR offered by a BMC
# For now, we will not offer persistent SDR caching as we do in xCAT's IPMI
# code. Will see if it is adequate to advocate for high object reuse in a
# persistent process for the moment.
This data is common between 'sensors' and 'inventory' modules since SDR
is both used to enumerate sensors for sensor commands and FRU ids for FRU
commands
# Focus is at least initially on the aspects that make the most sense for a
# remote client to care about. For example, smbus information is being
# skipped for now
For now, we will not offer persistent SDR caching as we do in xCAT's IPMI
code. Will see if it is adequate to advocate for high object reuse in a
persistent process for the moment.
Focus is at least initially on the aspects that make the most sense for a
remote client to care about. For example, smbus information is being
skipped for now
"""
import math
import os
import pyghmi.constants as const
import pyghmi.exceptions as exc
import pyghmi.ipmi.private.constants as ipmiconst
import random
import string
import struct
import sys
import weakref
import pyghmi.constants as const
import pyghmi.exceptions as exc
import pyghmi.ipmi.command as ipmicmd
import pyghmi.ipmi.private.constants as ipmiconst
import six
try:
import cPickle as pickle
except ImportError:
@ -49,6 +53,7 @@ TYPE_FRU = 2
shared_sdrs = {}
def ones_complement(value, bits):
# utility function to help with the large amount of 2s
# complement prevalent in ipmi spec
@ -553,18 +558,15 @@ class SDREntry(object):
elif linearization == 10:
return math.sqrt(decoded)
elif linearization == 11:
return decoded ** (1.0/3)
return decoded ** (1.0 / 3)
else:
raise NotImplementedError
def decode_formula(self, entry):
self.m = \
twos_complement(entry[0] + ((entry[1] & 0b11000000) << 2), 10)
self.m = twos_complement(entry[0] + ((entry[1] & 0b11000000) << 2), 10)
self.tolerance = entry[1] & 0b111111
self.b = \
twos_complement(entry[2] + ((entry[3] & 0b11000000) << 2), 10)
self.accuracy = (entry[3] & 0b111111) + \
(entry[4] & 0b11110000) << 2
self.b = twos_complement(entry[2] + ((entry[3] & 0b11000000) << 2), 10)
self.accuracy = (entry[3] & 0b111111) + (entry[4] & 0b11110000) << 2
self.accuracyexp = (entry[4] & 0b1100) >> 2
self.direction = entry[4] & 0b11
# 0 = n/a, 1 = input, 2 = output
@ -580,7 +582,8 @@ class SDREntry(object):
return ""
if ipmitype == 0: # Unicode per 43.15 in ipmi 2.0 spec
# the spec is not specific about encoding, assuming utf8
return unicode(struct.pack("%dB" % len(data), *data), "utf_8")
return six.text_type(struct.pack("%dB" % len(data), *data),
"utf_8")
elif ipmitype == 1: # BCD '+'
tmpl = "%02X" * len(data)
tstr = tmpl % tuple(data)
@ -811,10 +814,8 @@ class SDR(object):
# decode information
return "".join(hex(x) for x in auxdata)
if __name__ == "__main__": # test code
import os
import pyghmi.ipmi.command as ipmicmd
import sys
password = os.environ['IPMIPASSWORD']
bmc = sys.argv[1]
user = sys.argv[2]

View File

@ -12,19 +12,21 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import pyghmi.redfish.oem.generic as generic
from pyghmi.util.parse import parse_time
import errno
import json
import math
import os
import random
import socket
import time
import pyghmi.ipmi.private.util as util
import pyghmi.exceptions as pygexc
import pyghmi.ipmi.private.util as util
import pyghmi.redfish.oem.generic as generic
import pyghmi.storage as storage
from pyghmi.util.parse import parse_time
import pyghmi.util.webclient as webclient
import random
class OEMHandler(generic.OEMHandler):
@ -50,7 +52,8 @@ class OEMHandler(generic.OEMHandler):
return {'height': u_height, 'slot': slot}
def _get_agentless_firmware(self, components):
adata = self.wc.grab_json_response('/api/dataset/imm_adapters?params=pci_GetAdapters')
adata = self.wc.grab_json_response(
'/api/dataset/imm_adapters?params=pci_GetAdapters')
anames = set()
for adata in adata.get('items', []):
baseaname = adata['adapterName']
@ -93,6 +96,7 @@ class OEMHandler(generic.OEMHandler):
'productName'].rstrip()
bdata['version'] = diskent['fwVersion']
return (diskname, bdata)
def _get_disk_firmware(self, coponents):
storagedata = storagedata = self.wc.grab_json_response(
'/api/function/raid_alldevices?params=storage_GetAllDisks')
@ -300,7 +304,9 @@ class OEMHandler(generic.OEMHandler):
'perspan': drivesperspan,
}
else:
pass # TODO: adding new volume to existing array would be here
# TODO(Jarrod Johnson): adding new volume to
# existing array would be here
pass
def _create_array(self, pool):
params = self._parse_array_spec(pool)
@ -435,7 +441,8 @@ class OEMHandler(generic.OEMHandler):
vminfo = self._do_web_request(vmurl, cache=False)
if vminfo['ConnectedVia'] != 'NotConnected':
continue
self._do_web_request(vmurl, {'Image': url, 'Inserted': True}, 'PATCH')
self._do_web_request(vmurl, {'Image': url, 'Inserted': True},
'PATCH')
raise pygexc.BypassGenericBehavior()
break
else:
@ -485,7 +492,6 @@ class OEMHandler(generic.OEMHandler):
raise Exception('Unrecognized return: ' + errmsg)
if progress:
progress({'phase': 'complete'})
#self.weblogout()
def update_firmware(self, filename, data=None, progress=None, bank=None):
result = None
@ -501,15 +507,12 @@ class OEMHandler(generic.OEMHandler):
self._refresh_token()
self.wc.grab_json_response('/api/providers/fwupdate', json.dumps(
{'UPD_WebCancel': 1}))
#self.weblogout()
raise
self.updating = False
#self.weblogout()
return result
def update_firmware_backend(self, filename, data=None, progress=None,
bank=None):
#self.weblogout()
self._refresh_token()
rsv = self.wc.grab_json_response('/api/providers/fwupdate', json.dumps(
{'UPD_WebReserve': 1}))
@ -530,7 +533,8 @@ class OEMHandler(generic.OEMHandler):
progress({'phase': 'upload',
'progress': 100.0 * rsp['received'] / rsp['size']})
elif rsp['state'] != 'done':
if rsp.get('status', None) == 413 or uploadthread.rspstatus == 413:
if (rsp.get('status', None) == 413 or
uploadthread.rspstatus == 413):
raise Exception('File is larger than supported')
raise Exception('Unexpected result:' + repr(rsp))
uploadstate = rsp['state']
@ -566,7 +570,8 @@ class OEMHandler(generic.OEMHandler):
elif rsp.get('return', -1) == 108:
raise Exception('Temporary error validating update, try again')
elif rsp.get('return', -1) == 109:
raise Exception('Invalid update file or component does not support remote update')
raise Exception('Invalid update file or component '
'does not support remote update')
elif rsp.get('return', -1) != 0:
errmsg = repr(rsp) if rsp else self.wc.lastjsonerror
raise Exception('Unexpected return to verify: ' + errmsg)
@ -577,12 +582,13 @@ class OEMHandler(generic.OEMHandler):
rsp, status = self.wc.grab_json_response_with_status(
'/api/providers/fwupdate',
json.dumps({'UPD_WebVerifyUploadFileStatus': 1}))
if not rsp or status != 200 or rsp.get('return', -1) == 2:
if not rsp or status != 200 or rsp.get('return', -1) == 2:
# The XCC firmware predates the FileStatus api
verifyuploadfilersp = rsp
break
if rsp.get('return', -1) == 109:
raise Exception('Invalid update file or component does not support remote update')
raise Exception('Invalid update file or component '
'does not support remote update')
if rsp.get('return', -1) != 0:
errmsg = repr(rsp) if rsp else self.wc.lastjsonerror
raise Exception(
@ -611,7 +617,7 @@ class OEMHandler(generic.OEMHandler):
'TDM', 'WINDOWS DRIV', 'LINUX DRIVER', 'UEFI', 'IMM'):
# adapter firmware
webid = rsp['items'][0]['webfile_build_id']
locations = webid[webid.find('[')+1:webid.find(']')]
locations = webid[webid.find('[') + 1:webid.find(']')]
locations = locations.split(':')
validselectors = set([])
for loc in locations:
@ -721,7 +727,10 @@ class OEMHandler(generic.OEMHandler):
if lic['status'] == 0:
yield {'name': lic['feature'], 'state': 'Active'}
if lic['status'] == 10:
yield {'name': lic['feature'], 'state': 'Missing required license'}
yield {
'name': lic['feature'],
'state': 'Missing required license'
}
def delete_license(self, name):
licdata = self.wc.grab_json_response('/api/providers/imm_fod')
@ -729,7 +738,11 @@ class OEMHandler(generic.OEMHandler):
if lic.get('feature', None) == name:
licid = ','.join((str(lic['type']), str(lic['id'])))
self.wc.grab_json_response(
'/api/providers/imm_fod', {'FOD_LicenseKeyDelete': licid})
'/api/providers/imm_fod',
{
'FOD_LicenseKeyDelete': licid
}
)
break
def save_licenses(self, directory):
@ -763,8 +776,12 @@ class OEMHandler(generic.OEMHandler):
rsp = json.loads(uploadthread.rsp)
licpath = rsp.get('items', [{}])[0].get('path', None)
if licpath:
rsp = self.wc.grab_json_response('/api/providers/imm_fod',
{'FOD_LicenseKeyInstall': licpath})
rsp = self.wc.grab_json_response(
'/api/providers/imm_fod',
{
'FOD_LicenseKeyInstall': licpath
}
)
if rsp.get('return', 0) in license_errors:
raise pygexc.InvalidParameterValue(
license_errors[rsp['return']])