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:
parent
8abbd9091e
commit
e665ced5b4
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 = ''
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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():
|
||||
|
@ -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():
|
||||
|
@ -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():
|
||||
|
@ -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):
|
||||
|
||||
|
@ -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():
|
||||
|
@ -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):
|
||||
|
@ -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']])
|
||||
|
@ -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:
|
||||
|
@ -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]
|
||||
|
@ -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']])
|
||||
|
Loading…
x
Reference in New Issue
Block a user