1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
|
# Copyright 2017 FUJITSU LIMITED
#
# 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 functools
import itertools
from pyghmi import exceptions as ipmi_exception
from pyghmi.ipmi import command as ipmi_command
# F1 1A - Get the number of specific PCI devices on baremetal
GET_PCI = '0x2E 0xF1 0x80 0x28 0x00 0x1A %s 0x00'
# F5 81 - GET TPM STATUS
GET_TPM_STATUS = '0x2E 0xF5 0x80 0x28 0x00 0x81 0xC0'
class IPMIFailure(Exception):
"""IPMI Failure
This exception is used when IPMI operation failed.
"""
def __init__(self, message):
super(IPMIFailure, self).__init__(message)
class InvalidParameterValue(IPMIFailure):
"""Invalid Parameter Value Failure
This exception is used when invalid parameter values are passed to
the APIs exposed by this module.
"""
def __init__(self, message):
super(InvalidParameterValue, self).__init__(message)
def _parse_raw_bytes(raw_bytes):
"""Convert a string of hexadecimal values to decimal values parameters
Example: '0x2E 0xF1 0x80 0x28 0x00 0x1A 0x01 0x00' is converted to:
46, 241, [128, 40, 0, 26, 1, 0]
:param raw_bytes: string of hexadecimal values
:returns: 3 decimal values
"""
bytes_list = [int(x, base=16) for x in raw_bytes.split()]
return bytes_list[0], bytes_list[1], bytes_list[2:]
def _send_raw_command(ipmicmd, raw_bytes):
"""Use IPMI command object to send raw ipmi command to BMC
:param ipmicmd: IPMI command object
:param raw_bytes: string of hexadecimal values. This is commonly used
for certain vendor specific commands.
:returns: dict -- The response from IPMI device
"""
netfn, command, data = _parse_raw_bytes(raw_bytes)
response = ipmicmd.raw_command(netfn, command, data=data)
return response
def get_tpm_status(d_info):
"""Get the TPM support status.
Get the TPM support status of the node.
:param d_info: the list of ipmitool parameters for accessing a node.
:returns: TPM support status
"""
# note:
# Get TPM support status : ipmi cmd '0xF5', valid flags '0xC0'
#
# $ ipmitool raw 0x2E 0xF5 0x80 0x28 0x00 0x81 0xC0
#
# Raw response:
# 80 28 00 C0 C0: True
# 80 28 00 -- --: False (other values than 'C0 C0')
ipmicmd = ipmi_command.Command(
bmc=d_info['irmc_address'],
userid=d_info['irmc_username'].encode('utf-8'),
password=d_info['irmc_password'].encode('utf-8'))
try:
response = _send_raw_command(ipmicmd, GET_TPM_STATUS)
if response['code'] != 0:
raise IPMIFailure(
"IPMI operation '%(operation)s' failed: %(error)s" %
{'operation': "GET TMP status",
'error': response.get('error')})
out = ' '.join('{:02X}'.format(x) for x in response['data'])
return out is not None and out[-5:] == 'C0 C0'
except ipmi_exception.IpmiException as e:
raise IPMIFailure(
"IPMI operation '%(operation)s' failed: %(error)s" %
{'operation': "GET TMP status", 'error': e})
def _pci_seq(ipmicmd):
"""Get output of ipmiraw command and the ordinal numbers.
:param ipmicmd: IPMI command object.
:returns: List of tuple contain ordinal number and output of ipmiraw
command.
"""
for i in range(1, 0xff + 1):
try:
res = _send_raw_command(ipmicmd, GET_PCI % hex(i))
yield i, res
except ipmi_exception.IpmiException as e:
raise IPMIFailure(
"IPMI operation '%(operation)s' failed: %(error)s" %
{'operation': "GET PCI device quantity", 'error': e})
def get_pci_device(d_info, pci_device_ids):
"""Get quantity of PCI devices.
Get quantity of PCI devices of the node.
:param d_info: the list of ipmitool parameters for accessing a node.
:param pci_device_ids: the list contains pairs of <vendorID>/<deviceID> for
PCI devices.
:returns: the number of PCI devices.
"""
# note:
# Get quantity of PCI devices:
# ipmi cmd '0xF1'
#
# $ ipmitool raw 0x2E 0xF1 0x80 0x28 0x00 0x1A 0x01 0x00
#
# Raw response:
# 80 28 00 00 00 05 data1 data2 34 17 76 11 00 04
# 01
# data1: 2 octet of VendorID
# data2: 2 octet of DeviceID
ipmicmd = ipmi_command.Command(
bmc=d_info['irmc_address'],
userid=d_info['irmc_username'].encode('utf-8'),
password=d_info['irmc_password'].encode('utf-8'))
response = itertools.takewhile(
lambda y: (y[1]['code'] != 0xC9 and y[1].get('error') is None),
_pci_seq(ipmicmd))
def _pci_count(accm, v):
out = v[1]['data']
# if system returns value, record id will be increased.
pci_id = "0x{:02x}{:02x}/0x{:02x}{:02x}".format(
out[7], out[6], out[9], out[8])
return accm + 1 if pci_id in pci_device_ids else accm
device_count = functools.reduce(_pci_count, response, 0)
return device_count
|