def __init__( self, _id, _name, _vpd83, _block_size, _num_of_blocks, _admin_state, _system_id, _pool_id, _plugin_data=None, ): self._id = _id # Identifier self._name = _name # Human recognisable name if _vpd83 and not Volume.vpd83_verify(_vpd83): raise LsmError( ErrorNumber.INVALID_ARGUMENT, "Incorrect format of VPD 0x83 NAA(3) string: '%s', " "expecting 32 or 16 lower case hex characters" % _vpd83, ) self._vpd83 = _vpd83 # SCSI page 83 unique ID self._block_size = _block_size # Block size self._num_of_blocks = _num_of_blocks # Number of blocks self._admin_state = _admin_state # enable or disabled by admin self._system_id = _system_id # System id this volume belongs self._pool_id = _pool_id # Pool id this volume belongs self._plugin_data = _plugin_data
def initiator_id_verify(init_id, init_type=None, raise_exception=False): """ Public method which can be used to verify an initiator id :param init_id: :param init_type: :param raise_exception: Will throw a LsmError INVALID_ARGUMENT if not a valid initiator address :return:(Bool, init_type, init_id) Note: init_id will be returned in normalized format if it's a WWPN """ if init_id.startswith('iqn') or init_id.startswith( 'eui') or init_id.startswith('naa'): if init_type is None or init_type == AccessGroup.INIT_TYPE_ISCSI_IQN: return True, AccessGroup.INIT_TYPE_ISCSI_IQN, init_id if AccessGroup._regex_wwpn.match(str(init_id)): if init_type is None or init_type == AccessGroup.INIT_TYPE_WWPN: return (True, AccessGroup.INIT_TYPE_WWPN, AccessGroup._wwpn_to_lsm_type(init_id)) if raise_exception: raise LsmError( ErrorNumber.INVALID_ARGUMENT, "Initiator id '%s' is invalid" % init_id, ) return False, None, None
def link_type(self): """ Integer. New in version 1.3. Link type, possible values are: lsm.Disk.LINK_TYPE_UNKNOWN Failed to detect link type lsm.Disk.LINK_TYPE_FC Fibre Channel lsm.Disk.LINK_TYPE_SSA Serial Storage Architecture, Old IBM tech. lsm.Disk.LINK_TYPE_SBP Serial Bus Protocol, used by IEEE 1394. lsm.Disk.LINK_TYPE_SRP SCSI RDMA Protocol lsm.Disk.LINK_TYPE_ISCSI Internet Small Computer System Interface lsm.Disk.LINK_TYPE_SAS Serial Attached SCSI lsm.Disk.LINK_TYPE_ADT Automation/Drive Interface Transport Protocol, often used by Tape. lsm.Disk.LINK_TYPE_ATA PATA/IDE or SATA. lsm.Disk.LINK_TYPE_USB USB disk. lsm.Disk.LINK_TYPE_SOP SCSI over PCI-E lsm.Disk.LINK_TYPE_PCIE PCI-E, e.g. NVMe """ if self._link_type == Disk.LINK_TYPE_NO_SUPPORT: raise LsmError(ErrorNumber.NO_SUPPORT, "Disk.link_type is not supported by this plugin " "yet") return self._link_type
def __init__( self, _id, _name, _disk_type, _block_size, _num_of_blocks, _status, _system_id, _plugin_data=None, _vpd83="", _location="", _rpm=RPM_NO_SUPPORT, _link_type=LINK_TYPE_NO_SUPPORT, ): self._id = _id self._name = _name self._disk_type = _disk_type self._block_size = _block_size self._num_of_blocks = _num_of_blocks self._status = _status self._system_id = _system_id self._plugin_data = _plugin_data if _vpd83 and not Volume.vpd83_verify(_vpd83): raise LsmError( ErrorNumber.INVALID_ARGUMENT, "Incorrect format of VPD 0x83 NAA(3) string: '%s', " "expecting 32 or 16 lower case hex characters" % _vpd83, ) self._vpd83 = _vpd83 self._location = _location self._rpm = _rpm self._link_type = _link_type
def location(self): """ String. Disk location in storage topology. New in version 1.3. """ if self._location == '': raise LsmError(ErrorNumber.NO_SUPPORT, "Disk.location property is not supported by this " "plugin yet") return self._location
def _recv_msg(self): """ Reads header first to get the length and then the remaining bytes of the message. """ try: l = self._read_all(self.HDR_LEN) msg = self._read_all(int(l)) # common.Info("RECV: ", msg) except socket.error as e: raise LsmError(ErrorNumber.TRANSPORT_COMMUNICATION, "Error while reading a message from the plug-in", str(e)) except _SocketEOF: raise LsmError( ErrorNumber.TRANSPORT_COMMUNICATION, "Error while reading a message from the plug-in, EOF") return msg
def read_resp(self): data = self._recv_msg() resp = json.loads(data, cls=_DataDecoder) if 'result' in resp: return resp['result'], resp['id'] else: e = resp['error'] raise LsmError(**e)
def _standardize_init_list(init_ids): rc = [] for i in init_ids: valid, init_type, init_id = AccessGroup.initiator_id_verify(i) if valid: rc.append(init_id) else: raise LsmError(LsmError.ErrorNumber.INVALID_ARGUMENT, "Invalid initiator ID %s" % i) return rc
def fw_version(self): """ String. Firmware version string. New in version 1.3. On some system, it might contain multiple version strings, example: "Package: 23.32.0-0009, FW: 3.440.05-3712" """ if self._fw_version == '': raise LsmError(ErrorNumber.NO_SUPPORT, "System.fw_version() is not supported by this " "plugin yet") return self._fw_version
def read_cache_pct(self): """ Integer. Read cache percentage. New in version 1.3. Possible values: * 0-100 The read cache percentage. The write cache percentage will then be 100 - read_cache_pct """ if self._read_cache_pct == System.READ_CACHE_PCT_NO_SUPPORT: raise LsmError(ErrorNumber.NO_SUPPORT, "System.read_cache_pct is not supported by this " "plugin yet") return self._read_cache_pct
def vpd83(self): """ String. SCSI VPD83 ID. New in version 1.3. Only available for DAS(direct attached storage) systems. The VPD83 ID could be used in 'lsm.SCSI.disk_paths_of_vpd83()' when physical disk is exposed to OS directly. """ if self._vpd83 == '': raise LsmError( ErrorNumber.NO_SUPPORT, "Disk.vpd83 is not supported by current disk or plugin") return self._vpd83
def send_req(self, method, args): """ Sends a request given a method and arguments. Note: arguments must be in the form that can be automatically serialized to json """ try: msg = {'method': method, 'id': 100, 'params': args} data = json.dumps(msg, cls=_DataEncoder) self._send_msg(data) except socket.error as se: raise LsmError(ErrorNumber.TRANSPORT_COMMUNICATION, "Error while sending a message to the plug-in", str(se))
def get_socket(path): """ Returns a connected socket from the passed in path. """ try: s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) if os.path.exists(path): if os.access(path, os.R_OK | os.W_OK): s.connect(path) else: raise LsmError( ErrorNumber.PLUGIN_SOCKET_PERMISSION, "Permissions are incorrect for IPC " "socket file") else: raise LsmError(ErrorNumber.PLUGIN_NOT_EXIST, "Plug-in appears to not exist") except socket.error: # self, code, message, data=None, *args, **kwargs raise LsmError(ErrorNumber.PLUGIN_IPC_FAIL, "Unable to connect to lsmd, daemon started?") return s
def rpm(self): """ Integer. New in version 1.3. Disk rotation speed - revolutions per minute(RPM): -1 (LSM_DISK_RPM_UNKNOWN): Unknown RPM 0 (LSM_DISK_RPM_NON_ROTATING_MEDIUM): Non-rotating medium (e.g., SSD) 1 (LSM_DISK_RPM_ROTATING_UNKNOWN_SPEED): Rotational disk with unknown speed >1: Normal rotational disk (e.g., HDD) """ if self._rpm == Disk.RPM_NO_SUPPORT: raise LsmError(ErrorNumber.NO_SUPPORT, "Disk.rpm is not supported by this plugin yet") return self._rpm
def mode(self): """ Integer(enumerated value). System mode. New in version 1.3. Only available for HW RAID systems at this time. Possible values: * lsm.System.MODE_HARDWARE_RAID The logical volume(aka, RAIDed virtual disk) can be exposed to OS while hardware RAID card is handling the RAID algorithm. Physical disk can not be exposed to OS directly. * lsm.System.MODE_HBA The physical disks can be exposed to OS directly. SCSI enclosure service might be exposed to OS also. """ if self._mode == System.MODE_NO_SUPPORT: raise LsmError(ErrorNumber.NO_SUPPORT, "System.mode is not supported by this plugin yet") return self._mode
def _wwpn_to_lsm_type(wwpn, raise_error: bool = True): """ Convert provided WWPN string into LSM standard one: LSM WWPN format: ^(?:[0-9a-f]{2}:){7}[0-9a-f]{2}$ LSM WWPN Example: 10:00:00:00:c9:95:2f:de Acceptable WWPN format is: ^[0x|0X]{0,1}(:?[0-9A-Fa-f]{2}[\.\-:]{0,1}){7}[0-9A-Fa-f]{2}$ Acceptable WWPN example: 10:00:00:00:c9:95:2f:de 10:00:00:00:C9:95:2F:DE 10-00-00-00-C9-95-2F-DE 10-00-00-00-c9-95-2f-de 10.00.00.00.C9.95.2F.DE 10.00.00.00.c9.95.2f.de 0x10000000c9952fde 0X10000000C9952FDE 10000000c9952fde 10000000C9952FDE Return the LSM WWPN Return None if raise_error is False and not a valid WWPN. """ if AccessGroup._regex_wwpn.match(str(wwpn)): s = str(wwpn) s = s.lower() s = re.sub(r'0x', "", s) s = re.sub(r'[^0-9a-f]', "", s) s = ":".join(re.findall(r'..', s)) return s if raise_error: raise LsmError( ErrorNumber.INVALID_ARGUMENT, "Invalid WWPN Initiator: %s" % wwpn, ) return None