#!/usr/bin/env python # Copyright 2017 Hewlett-Packard Enterprise Development Company, L.P. # # 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. __author__ = 'HPE' import os from pysnmp import hlapi from pysnmp.smi import builder from pysnmp.smi import view from proliantutils import exception from proliantutils import log LOG = log.get_logger(__name__) cpq_mibs_path = os.path.dirname(os.path.abspath(__file__)) cpq_mibs_path = os.path.join(cpq_mibs_path, "cpqdisk_mibs") mBuilder = builder.MibBuilder() mBuilder.addMibSources(builder.DirMibSource(cpq_mibs_path)) mibBuilder = mBuilder.loadModules('CPQIDA-MIB', 'CPQSCSI-MIB') mibViewController = view.MibViewController(mibBuilder) # A dictionary of supported mapped snmp attributes MAPPED_SNMP_ATTRIBUTES = { 'authProtocol': { 'SHA': hlapi.usmHMACSHAAuthProtocol, 'MD5': hlapi.usmHMACMD5AuthProtocol, }, 'privProtocol': { 'AES': hlapi.usmAesCfb128Protocol, 'DES': hlapi.usmDESPrivProtocol, }, } def _create_usm_user_obj(snmp_cred): """Creates the UsmUserData obj for the given credentials. This method creates an instance for the method hlapi.UsmUserData. The UsmUserData() allows the 'auth_protocol' and 'priv_protocol' to be undefined by user if their pass phrases are provided. :param snmp_cred: Dictionary of SNMP credentials. auth_user: SNMP user auth_protocol: Auth Protocol auth_prot_pp: Pass phrase value for AuthProtocol. priv_protocol:Privacy Protocol. auth_priv_pp: Pass phrase value for Privacy Protocol. :returns UsmUserData object as per given credentials. """ auth_protocol = snmp_cred.get('auth_protocol') priv_protocol = snmp_cred.get('priv_protocol') auth_user = snmp_cred.get('auth_user') auth_prot_pp = snmp_cred.get('auth_prot_pp') auth_priv_pp = snmp_cred.get('auth_priv_pp') if ((not auth_protocol) and priv_protocol): priv_protocol = ( MAPPED_SNMP_ATTRIBUTES['privProtocol'][priv_protocol]) usm_user_obj = hlapi.UsmUserData(auth_user, auth_prot_pp, auth_priv_pp, privProtocol=priv_protocol) elif ((not priv_protocol) and auth_protocol): auth_protocol = ( MAPPED_SNMP_ATTRIBUTES['authProtocol'][auth_protocol]) usm_user_obj = hlapi.UsmUserData(auth_user, auth_prot_pp, auth_priv_pp, authProtocol=auth_protocol) elif not all([priv_protocol and auth_protocol]): usm_user_obj = hlapi.UsmUserData(auth_user, auth_prot_pp, auth_priv_pp) else: auth_protocol = ( MAPPED_SNMP_ATTRIBUTES['authProtocol'][auth_protocol]) priv_protocol = ( MAPPED_SNMP_ATTRIBUTES['privProtocol'][priv_protocol]) usm_user_obj = hlapi.UsmUserData(auth_user, auth_prot_pp, auth_priv_pp, authProtocol=auth_protocol, privProtocol=priv_protocol) return usm_user_obj def _parse_mibs(iLOIP, snmp_credentials): """Parses the MIBs. :param iLOIP: IP address of the server on which SNMP discovery has to be executed. :param snmp_credentials: a Dictionary of SNMP credentials. auth_user: SNMP user auth_protocol: Auth Protocol auth_prot_pp: Pass phrase value for AuthProtocol. priv_protocol:Privacy Protocol. auth_priv_pp: Pass phrase value for Privacy Protocol. :returns the dictionary of parsed MIBs. :raises exception.InvalidInputError if pysnmp is unable to get SNMP data due to wrong inputs provided. :raises exception.IloError if pysnmp raises any exception. """ result = {} usm_user_obj = _create_usm_user_obj(snmp_credentials) try: for(errorIndication, errorStatus, errorIndex, varBinds) in hlapi.nextCmd( hlapi.SnmpEngine(), usm_user_obj, hlapi.UdpTransportTarget((iLOIP, 161), timeout=3, retries=3), hlapi.ContextData(), # cpqida cpqDaPhyDrvTable Drive Array Physical Drive Table hlapi.ObjectType( hlapi.ObjectIdentity('1.3.6.1.4.1.232.3.2.5.1')), # cpqscsi SCSI Physical Drive Table hlapi.ObjectType( hlapi.ObjectIdentity('1.3.6.1.4.1.232.5.2.4.1')), # cpqscsi SAS Physical Drive Table hlapi.ObjectType( hlapi.ObjectIdentity('1.3.6.1.4.1.232.5.5.2.1')), lexicographicMode=False, ignoreNonIncreasingOid=True): if errorIndication: LOG.error(errorIndication) msg = "SNMP failed to traverse MIBs %s", errorIndication raise exception.IloSNMPInvalidInputFailure(msg) else: if errorStatus: msg = ('Parsing MIBs failed. %s at %s' % ( errorStatus.prettyPrint(), errorIndex and varBinds[-1][int(errorIndex)-1] or '?' ) ) LOG.error(msg) raise exception.IloSNMPInvalidInputFailure(msg) else: for varBindTableRow in varBinds: name, val = tuple(varBindTableRow) oid, label, suffix = ( mibViewController.getNodeName(name)) key = name.prettyPrint() # Don't traverse outside the tables we requested if not (key.find("SNMPv2-SMI::enterprises.232.3") >= 0 or (key.find( "SNMPv2-SMI::enterprises.232.5") >= 0)): break if key not in result: result[key] = {} result[key][label[-1]] = {} result[key][label[-1]][suffix] = val except Exception as e: msg = "SNMP library failed with error %s", e LOG.error(msg) raise exception.IloSNMPExceptionFailure(msg) return result def _get_disksize_MiB(iLOIP, cred): """Reads the dictionary of parsed MIBs and gets the disk size. :param iLOIP: IP address of the server on which SNMP discovery has to be executed. :param snmp_credentials in a dictionary having following mandatory keys. auth_user: SNMP user auth_protocol: Auth Protocol auth_prot_pp: Pass phrase value for AuthProtocol. priv_protocol:Privacy Protocol. auth_priv_pp: Pass phrase value for Privacy Protocol. :returns the dictionary of disk sizes of all physical drives. """ # '1.3.6.1.4.1.232.5.5.1.1', # cpqscsi SAS HBA Table # '1.3.6.1.4.1.232.3.2.3.1', # cpqida Drive Array Logical Drive Table result = _parse_mibs(iLOIP, cred) disksize = {} for uuid in sorted(result): for key in result[uuid]: # We only track the Physical Disk Size if key.find('PhyDrvSize') >= 0: disksize[uuid] = dict() for suffix in sorted(result[uuid][key]): size = result[uuid][key][suffix] disksize[uuid][key] = str(size) return disksize def get_local_gb(iLOIP, snmp_credentials): """Gets the maximum disk size among all disks. :param iLOIP: IP address of the server on which SNMP discovery has to be executed. :param snmp_credentials in a dictionary having following mandatory keys. auth_user: SNMP user auth_protocol: Auth Protocol auth_prot_pp: Pass phrase value for AuthProtocol. priv_protocol:Privacy Protocol. auth_priv_pp: Pass phrase value for Privacy Protocol. """ disk_sizes = _get_disksize_MiB(iLOIP, snmp_credentials) max_size = 0 for uuid in disk_sizes: for key in disk_sizes[uuid]: if int(disk_sizes[uuid][key]) > max_size: max_size = int(disk_sizes[uuid][key]) max_size_gb = max_size/1024 return max_size_gb