00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 """
00018 This module intends to provide independent methods related to lsm.Volume and
00019 CIM_StorageVolume.
00020 """
00021
00022 import re
00023 import sys
00024
00025 from lsm import md5, Volume, LsmError, ErrorNumber
00026 from lsm.plugin.smispy.utils import (
00027 merge_list, cim_path_to_path_str, path_str_to_cim_path)
00028 from lsm.plugin.smispy import dmtf
00029
00030
00031 def cim_vol_id_pros():
00032 """
00033 Return the property of CIM_StorageVolume required to generate
00034 lsm.Volume.id
00035 """
00036 return ['SystemName', 'DeviceID']
00037
00038
00039 def vol_id_of_cim_vol(cim_vol):
00040 """
00041 Get lsm.Volume.id from CIM_StorageVolume['DeviceID'] and ['SystemName']
00042 """
00043 if 'SystemName' not in cim_vol or 'DeviceID' not in cim_vol:
00044 raise LsmError(
00045 ErrorNumber.PLUGIN_BUG,
00046 "vol_id_of_cim_vol(): Got cim_vol with no "
00047 "SystemName or DeviceID property: %s, %s" %
00048 (cim_vol.path, cim_vol.items()))
00049
00050 return md5("%s%s" % (cim_vol['SystemName'], cim_vol['DeviceID']))
00051
00052
00053 def cim_vol_pros():
00054 """
00055 Return the PropertyList required for creating new lsm.Volume.
00056 """
00057 props = ['ElementName', 'NameFormat',
00058 'NameNamespace', 'BlockSize', 'NumberOfBlocks', 'Name',
00059 'OtherIdentifyingInfo', 'IdentifyingDescriptions', 'Usage',
00060 'OtherNameFormat', 'OtherNameNamespace']
00061 props.extend(cim_vol_id_pros())
00062 return props
00063
00064
00065 def cim_vol_of_cim_pool_path(smis_common, cim_pool_path, property_list=None):
00066 """
00067 Use this association to get a list of CIM_StorageVolume:
00068 CIM_StoragePool
00069 |
00070 | CIM_AllocatedFromStoragePool
00071 |
00072 v
00073 CIM_StorageVolume
00074 CIM_StorageVolume['Usage'] == dmtf.VOL_USAGE_SYS_RESERVED will be filtered
00075 out.
00076 Return a list of CIM_StorageVolume.
00077 """
00078 if property_list is None:
00079 property_list = ['Usage']
00080 else:
00081 property_list = merge_list(property_list, ['Usage'])
00082
00083 cim_vols = smis_common.Associators(
00084 cim_pool_path,
00085 AssocClass='CIM_AllocatedFromStoragePool',
00086 ResultClass='CIM_StorageVolume',
00087 PropertyList=property_list)
00088
00089 needed_cim_vols = []
00090 for cim_vol in cim_vols:
00091 if 'Usage' not in cim_vol or \
00092 cim_vol['Usage'] != dmtf.VOL_USAGE_SYS_RESERVED:
00093 needed_cim_vols.append(cim_vol)
00094 return needed_cim_vols
00095
00096
00097 def _vpd83_in_cim_vol_name(cim_vol):
00098 """
00099 We require NAA Type 3 VPD83 address:
00100 Only this is allowed when storing VPD83 in cim_vol["Name"]:
00101 * NameFormat = NAA(9), NameNamespace = VPD83Type3(2)
00102 """
00103 if not ('NameFormat' in cim_vol and
00104 'NameNamespace' in cim_vol and
00105 'Name' in cim_vol):
00106 return None
00107 name_format = cim_vol['NameFormat']
00108 name_space = cim_vol['NameNamespace']
00109 name = cim_vol['Name']
00110 if not (name_format and name_space and name):
00111 return None
00112
00113 if name_format == dmtf.VOL_NAME_FORMAT_NNA and \
00114 name_space == dmtf.VOL_NAME_SPACE_VPD83_TYPE3:
00115 return name
00116
00117
00118 def _vpd83_in_cim_vol_otherinfo(cim_vol):
00119 """
00120 IdentifyingDescriptions[] shall contain "NAA;VPD83Type3".
00121 Will return the vpd_83 value if found
00122 """
00123 if not ("IdentifyingDescriptions" in cim_vol and
00124 "OtherIdentifyingInfo" in cim_vol):
00125 return None
00126
00127 id_des = cim_vol["IdentifyingDescriptions"]
00128 other_info = cim_vol["OtherIdentifyingInfo"]
00129 if not (isinstance(cim_vol["IdentifyingDescriptions"], list) and
00130 isinstance(cim_vol["OtherIdentifyingInfo"], list)):
00131 return None
00132
00133 index = 0
00134 len_id_des = len(id_des)
00135 len_other_info = len(other_info)
00136 while index < min(len_id_des, len_other_info):
00137 if dmtf.VOL_OTHER_INFO_NAA_VPD83_TYPE3H == id_des[index]:
00138 return other_info[index]
00139 index += 1
00140 return None
00141
00142
00143 def _vpd83_netapp(cim_vol):
00144 """
00145 Workaround for NetApp, they use OtherNameNamespace and
00146 OtherNameFormat.
00147 """
00148 if 'OtherNameFormat' in cim_vol and \
00149 cim_vol['OtherNameFormat'] == 'NAA' and \
00150 'OtherNameNamespace' in cim_vol and \
00151 cim_vol['OtherNameNamespace'] == 'VPD83Type3' and \
00152 'OtherIdentifyingInfo' in cim_vol and \
00153 isinstance(cim_vol["OtherIdentifyingInfo"], list) and \
00154 len(cim_vol['OtherIdentifyingInfo']) == 1:
00155 return cim_vol['OtherIdentifyingInfo'][0]
00156
00157
00158 def _vpd83_of_cim_vol(cim_vol):
00159 """
00160 Extract VPD83 NAA string from CIMInstanceName and convert to LSM format.
00161 """
00162 vpd_83 = _vpd83_in_cim_vol_name(cim_vol)
00163 if vpd_83 is None:
00164 vpd_83 = _vpd83_in_cim_vol_otherinfo(cim_vol)
00165 if vpd_83 is None:
00166 vpd_83 = _vpd83_netapp(cim_vol)
00167
00168 if vpd_83:
00169 vpd_83 = vpd_83.lower()
00170
00171 if vpd_83 and Volume.vpd83_verify(vpd_83):
00172 return vpd_83
00173 else:
00174 return ''
00175
00176
00177 def cim_vol_to_lsm_vol(cim_vol, pool_id, sys_id):
00178 """
00179 Takes a CIMInstance that represents a volume and returns a lsm Volume
00180 """
00181
00182
00183 if 'ElementName' in cim_vol:
00184 user_name = cim_vol["ElementName"]
00185 else:
00186
00187 user_name = cim_vol['DeviceID']
00188
00189 vpd_83 = _vpd83_of_cim_vol(cim_vol)
00190
00191 admin_state = Volume.ADMIN_STATE_ENABLED
00192
00193 plugin_data = cim_path_to_path_str(cim_vol.path)
00194
00195 return Volume(
00196 vol_id_of_cim_vol(cim_vol), user_name, vpd_83,
00197 cim_vol["BlockSize"], cim_vol["NumberOfBlocks"], admin_state, sys_id,
00198 pool_id, plugin_data)
00199
00200
00201 def lsm_vol_to_cim_vol_path(smis_common, lsm_vol):
00202 """
00203 Convert lsm.Volume to CIMInstanceName of CIM_StorageVolume using
00204 lsm.Volume.plugin_data
00205 """
00206 if not lsm_vol.plugin_data:
00207 raise LsmError(
00208 ErrorNumber.PLUGIN_BUG,
00209 "Got lsm.Volume instance with empty plugin_data")
00210 if smis_common.system_list and \
00211 lsm_vol.system_id not in smis_common.system_list:
00212 raise LsmError(
00213 ErrorNumber.NOT_FOUND_SYSTEM,
00214 "System filtered in URI")
00215
00216 return path_str_to_cim_path(lsm_vol.plugin_data)
00217
00218
00219 def volume_name_exists(smis_common, volume_name):
00220 """
00221 Try to minimize time to search.
00222 :param volume_name: Volume ElementName
00223 :return: True if volume exists with 'name', else False
00224 """
00225 all_cim_vols = smis_common.EnumerateInstances(
00226 'CIM_StorageVolume', PropertyList=['ElementName'])
00227 for exist_cim_vol in all_cim_vols:
00228 if volume_name == exist_cim_vol['ElementName']:
00229 return True
00230 return False
00231
00232
00233 def volume_create_error_handler(smis_common, method_data, exec_info=None):
00234 """
00235 When we got CIMError, we check whether we got a duplicate volume name.
00236 The method_data is the requested volume name.
00237 """
00238 if volume_name_exists(smis_common, method_data):
00239 raise LsmError(ErrorNumber.NAME_CONFLICT,
00240 "Volume with name '%s' already exists!" % method_data)
00241
00242 if exec_info is None:
00243 (error_type, error_msg, error_trace) = sys.exc_info()
00244 else:
00245 (error_type, error_msg, error_trace) = exec_info
00246 raise error_type, error_msg, error_trace