class NetAppHandler(object): # TODO OID_SERIAL_NUM = '1.3.6.1.4.1.789.1.1.9.0' OID_TRAP_DATA = '1.3.6.1.4.1.789.1.1.12.0' SECONDS_TO_MS = 1000 def __init__(self, **kwargs): self.ssh_pool = SSHPool(**kwargs) @staticmethod def parse_alert(alert): try: alert_info = alert.get(NetAppHandler.OID_TRAP_DATA) alert_arr = alert_info.split(":") if len(alert_arr) > 1: alert_name = alert_arr[0] description = alert_arr[1] if netapp_constants.SEVERITY_MAP.get(alert_name): severity = netapp_constants.SEVERITY_MAP.get(alert_name) a = { 'alert_id': '', 'alert_name': alert_name, 'severity': severity, 'category': constants.Category.EVENT, 'type': constants.EventType.EQUIPMENT_ALARM, 'occur_time': int(time.time()), 'description': description, 'sequence_number': '', 'resource_type': constants.DEFAULT_RESOURCE_TYPE, 'location': '' } return a except exception.DelfinException as e: err_msg = "Failed to parse alert from " \ "netapp_fas fas: %s" % (six.text_type(e.msg)) LOG.error(err_msg) raise e except Exception as err: err_msg = "Failed to parse alert from " \ "netapp_fas fas: %s" % (six.text_type(err)) LOG.error(err_msg) raise exception.InvalidResults(err_msg) def login(self): try: self.exec_ssh_command('version') except Exception as e: LOG.error("Failed to login netapp_fas %s" % (six.text_type(e))) raise e @staticmethod def do_exec(command_str, ssh): result = None try: utils.check_ssh_injection(command_str) if command_str is not None and ssh is not None: stdin, stdout, stderr = ssh.exec_command(command_str) res, err = stdout.read(), stderr.read() re = res if res else err result = re.decode() except paramiko.AuthenticationException as ae: LOG.error('doexec Authentication error:{}'.format(ae)) raise exception.InvalidUsernameOrPassword() except Exception as e: err = six.text_type(e) LOG.error('doexec InvalidUsernameOrPassword error') if 'timed out' in err: raise exception.SSHConnectTimeout() elif 'No authentication methods available' in err \ or 'Authentication failed' in err: raise exception.InvalidUsernameOrPassword() elif 'not a valid RSA private key file' in err: raise exception.InvalidPrivateKey() else: raise exception.SSHException(err) return result def exec_ssh_command(self, command): try: with self.ssh_pool.item() as ssh: ssh_info = NetAppHandler.do_exec(command, ssh) return ssh_info except Exception as e: msg = "Failed to ssh netapp_fas %s: %s" % \ (command, six.text_type(e)) raise exception.SSHException(msg) @staticmethod def change_capacity_to_bytes(unit): unit = unit.upper() if unit == 'TB': res = units.Ti elif unit == 'GB': res = units.Gi elif unit == 'MB': res = units.Mi elif unit == 'KB': res = units.Ki else: res = 1 return int(res) def parse_string(self, value): capacity = 0 if value: if value.isdigit(): capacity = float(value) else: unit = value[-2:] capacity = float(value[:-2]) * int( self.change_capacity_to_bytes(unit)) return capacity def get_storage(self): try: STATUS_MAP = { 'ok': constants.StorageStatus.NORMAL, 'ok-with-suppressed': constants.StorageStatus.NORMAL, 'degraded': constants.StorageStatus.ABNORMAL, 'unreachable': constants.StorageStatus.ABNORMAL } raw_capacity = total_capacity = used_capacity = free_capacity = 0 system_info = self.exec_ssh_command( netapp_constants.CLUSTER_SHOW_COMMAND) version = self.exec_ssh_command( netapp_constants.VERSION_SHOW_COMMAND) status_info = self.exec_ssh_command( netapp_constants.STORAGE_STATUS_COMMAND) version_arr = version.split('\n') status = STATUS_MAP.get(status_info.split("\n")[2]) disk_list = self.list_disks(None) pool_list = self.list_storage_pools(None) storage_map = {} self.handle_detail(system_info, storage_map, split=':') for disk in disk_list: raw_capacity += disk['capacity'] for pool in pool_list: total_capacity += pool['total_capacity'] free_capacity += pool['free_capacity'] used_capacity += pool['used_capacity'] s = { "name": storage_map['ClusterName'], "vendor": netapp_constants.STORAGE_VENDOR, "model": '', "status": status, "serial_number": storage_map['ClusterSerialNumber'], "firmware_version": version_arr[0], "location": '', "total_capacity": total_capacity, "raw_capacity": raw_capacity, "used_capacity": used_capacity, "free_capacity": free_capacity } return s except exception.DelfinException as e: err_msg = "Failed to get storage from " \ "netapp_fas fas: %s" % (six.text_type(e.msg)) LOG.error(err_msg) raise e except Exception as err: err_msg = "Failed to get storage from " \ "netapp_fas fas: %s" % (six.text_type(err)) LOG.error(err_msg) raise exception.InvalidResults(err_msg) @staticmethod def handle_detail(system_info, storage_map, split): detail_arr = system_info.split('\n') for detail in detail_arr: if detail is not None and detail != '': strinfo = detail.split(split + " ") key = strinfo[0].replace(' ', '') value = '' if len(strinfo) > 1: value = strinfo[1] storage_map[key] = value def get_aggregate(self, storage_id): STATUS_MAP = { 'online': constants.StoragePoolStatus.NORMAL, 'creating': constants.StoragePoolStatus.NORMAL, 'mounting': constants.StoragePoolStatus.NORMAL, 'relocating': constants.StoragePoolStatus.NORMAL, 'quiesced': constants.StoragePoolStatus.OFFLINE, 'quiescing': constants.StoragePoolStatus.OFFLINE, 'unmounted': constants.StoragePoolStatus.OFFLINE, 'unmounting': constants.StoragePoolStatus.OFFLINE, 'destroying': constants.StoragePoolStatus.ABNORMAL, 'partial': constants.StoragePoolStatus.ABNORMAL, 'frozen': constants.StoragePoolStatus.ABNORMAL, 'reverted': constants.StoragePoolStatus.NORMAL, 'restricted': constants.StoragePoolStatus.ABNORMAL, 'inconsistent': constants.StoragePoolStatus.ABNORMAL, 'iron_restricted': constants.StoragePoolStatus.ABNORMAL, 'unknown': constants.StoragePoolStatus.OFFLINE, 'offline': constants.StoragePoolStatus.OFFLINE, 'failed': constants.StoragePoolStatus.ABNORMAL, 'remote_cluster': constants.StoragePoolStatus.NORMAL, } agg_list = [] agg_info = self.exec_ssh_command( netapp_constants.AGGREGATE_SHOW_DETAIL_COMMAND) agg_arr = agg_info.split( netapp_constants.AGGREGATE_SPLIT_STR) agg_map = {} for agg in agg_arr[1:]: self.handle_detail(agg, agg_map, split=':') status = STATUS_MAP.get(agg_map['State']) p = { 'name': agg_map['e'], 'storage_id': storage_id, 'native_storage_pool_id': agg_map['UUIDString'], 'description': '', 'status': status, 'storage_type': constants.StorageType.UNIFIED, 'subscribed_capacity': '', 'total_capacity': int(self.parse_string(agg_map['Size'])), 'used_capacity': int(self.parse_string(agg_map['UsedSize'])), 'free_capacity': int(self.parse_string(agg_map['AvailableSize'])), } agg_list.append(p) return agg_list def get_pool(self, storage_id): pool_list = [] pool_info = self.exec_ssh_command( netapp_constants.POOLS_SHOW_DETAIL_COMMAND) pool_arr = pool_info.split(netapp_constants.POOLS_SPLIT_STR) pool_map = {} for pool_str in pool_arr[1:]: self.handle_detail(pool_str, pool_map, split=':') status = \ constants.StoragePoolStatus.NORMAL \ if pool_map['IsPoolHealthy?'] == 'true' \ else constants.StoragePoolStatus.OFFLINE p = { 'name': pool_map['ame'], 'storage_id': storage_id, 'native_storage_pool_id': pool_map['UUIDofStoragePool'], 'description': '', 'status': status, 'storage_type': constants.StorageType.BLOCK, 'subscribed_capacity': '', 'total_capacity': int(self.parse_string(pool_map['StoragePoolTotalSize'])), 'used_capacity': int(self.parse_string(pool_map['StoragePoolTotalSize'])) - int(self.parse_string(pool_map['StoragePoolUsableSize'])), 'free_capacity': int(self.parse_string(pool_map['StoragePoolUsableSize'])) } pool_list.append(p) return pool_list def list_storage_pools(self, storage_id): try: pool_list = self.get_pool(storage_id) agg_list = self.get_aggregate(storage_id) return agg_list + pool_list except exception.DelfinException as e: err_msg = "Failed to get storage pool from " \ "netapp_fas fas: %s" % (six.text_type(e)) LOG.error(err_msg) raise e except Exception as err: err_msg = "Failed to get storage pool from " \ "netapp_fas fas: %s" % (six.text_type(err)) LOG.error(err_msg) raise exception.InvalidResults(err_msg) def list_volumes(self, storage_id): try: STATUS_MAP = { 'online': constants.VolumeStatus.AVAILABLE, 'offline': constants.VolumeStatus.ERROR, 'nvfail': constants.VolumeStatus.ERROR, 'space-error': constants.VolumeStatus.ERROR, 'foreign-lun-error': constants.VolumeStatus.ERROR, } volume_list = [] volume_info = self.exec_ssh_command( netapp_constants.LUN_SHOW_DETAIL_COMMAND) volume_arr = volume_info.split(netapp_constants.LUN_SPLIT_STR) fs_list = self.list_filesystems(storage_id) volume_map = {} for volume_str in volume_arr[1:]: self.handle_detail(volume_str, volume_map, split=':') if volume_map is not None or volume_map != {}: pool_id = '' status = STATUS_MAP.get(volume_map['State']) for fs in fs_list: if fs['name'] == volume_map['VolumeName']: pool_id = fs['native_pool_id'] type = constants.VolumeType.THIN \ if volume_map['SpaceAllocation'] == 'enabled' \ else constants.VolumeType.THICK v = { 'name': volume_map['LUNName'], 'storage_id': storage_id, 'description': '', 'status': status, 'native_volume_id': volume_map['LUNUUID'], 'native_storage_pool_id': pool_id, 'wwn': '', 'compressed': '', 'deduplicated': '', 'type': type, 'total_capacity': int(self.parse_string(volume_map['LUNSize'])), 'used_capacity': int(self.parse_string(volume_map['UsedSize'])), 'free_capacity': int(self.parse_string(volume_map['LUNSize'])) - int(self.parse_string(volume_map['UsedSize'])) } volume_list.append(v) return volume_list except exception.DelfinException as e: err_msg = "Failed to get storage volume from " \ "netapp_fas fas: %s" % (six.text_type(e)) LOG.error(err_msg) raise e except Exception as err: err_msg = "Failed to get storage volume from " \ "netapp_fas fas: %s" % (six.text_type(err)) LOG.error(err_msg) raise exception.InvalidResults(err_msg) def list_alerts(self, query_para): try: alert_list = [] alert_info = self.exec_ssh_command( netapp_constants.ALTER_SHOW_DETAIL_COMMAND) event_info = self.exec_ssh_command( netapp_constants.EVENT_SHOW_DETAIL_COMMAND) """Query the two alarms separately""" AlertHandler.list_events(self, event_info, query_para, alert_list) AlertHandler.list_alerts(self, alert_info, query_para, alert_list) return alert_list except exception.DelfinException as e: err_msg = "Failed to get storage alert: %s" % (six.text_type(e)) LOG.error(err_msg) raise e except Exception as err: err_msg = "Failed to get storage alert: %s" % (six.text_type(err)) LOG.error(err_msg) raise exception.InvalidResults(err_msg) def clear_alert(self, alert): try: ssh_command = \ netapp_constants.CLEAR_ALERT_COMMAND + alert['alert_id'] self.exec_ssh_command(ssh_command) except exception.DelfinException as e: err_msg = "Failed to get storage alert from " \ "netapp_fas fas: %s" % (six.text_type(e)) LOG.error(err_msg) raise e except Exception as err: err_msg = "Failed to get storage alert from " \ "netapp_fas fas: %s" % (six.text_type(err)) LOG.error(err_msg) raise exception.InvalidResults(err_msg) def list_controllers(self, storage_id): try: controller_list = [] controller_info = self.exec_ssh_command( netapp_constants.CONTROLLER_SHOW_DETAIL_COMMAND) controller_arr = controller_info.split( netapp_constants.CONTROLLER_SPLIT_STR) controller_map = {} for controller_str in controller_arr[1:]: self.handle_detail(controller_str, controller_map, split=':') if controller_map is not None or controller_map != {}: status = constants.ControllerStatus.NORMAL \ if controller_map['Health'] == 'true' \ else constants.ControllerStatus.OFFLINE c = { 'name': controller_map['e'], 'storage_id': storage_id, 'native_controller_id': controller_map['SystemID'], 'status': status, 'location': controller_map['Location'], 'soft_version': '', 'cpu_info': '', 'memory_size': '', } controller_list.append(c) return controller_list except exception.DelfinException as e: err_msg = "Failed to get storage controllers from " \ "netapp_fas fas: %s" % (six.text_type(e)) LOG.error(err_msg) raise e except Exception as err: err_msg = "Failed to get storage controllers from " \ "netapp_fas fas: %s" % (six.text_type(err)) LOG.error(err_msg) raise exception.InvalidResults(err_msg) def get_network_port(self, storage_id): try: LOGICAL_TYPE_MAP = { 'data': constants.PortLogicalType.FRONTEND, 'cluster': constants.PortLogicalType.FRONTEND, 'node-mgmt': constants.PortLogicalType.MANAGEMENT, 'cluster-mgmt': constants.PortLogicalType.INTERNAL, 'intercluster': constants.PortLogicalType.INTERCONNECT, } ports_list = [] interfaces_info = self.exec_ssh_command( netapp_constants.INTERFACE_SHOW_DETAIL_COMMAND) interface_arr = interfaces_info.split( netapp_constants.INTERFACE_SPLIT_STR) interface_map = {} ipv4 = ipv4_mask = ipv6 = ipv6_mask = '-' """Traversal to get port IP address information""" for interface_info in interface_arr[1:]: self.handle_detail(interface_info, interface_map, split=':') logical_type = LOGICAL_TYPE_MAP.get(interface_map['Role']) type = interface_map['DataProtocol'] if interface_map['Addressfamily'] == 'ipv4': ipv4 += interface_map['NetworkAddress'] + ',' ipv4_mask += interface_map['Netmask'] + ',' else: ipv6 += interface_map['NetworkAddress'] + ',' ipv6_mask += interface_map['Netmask'] + ',' p = { 'name': interface_map['LogicalInterfaceName'], 'storage_id': storage_id, 'native_port_id': interface_map['LogicalInterfaceName'], 'location': '', 'connection_status': constants.PortConnectionStatus.CONNECTED if interface_map['OperationalStatus'] == 'up' else constants.PortConnectionStatus.DISCONNECTED, 'health_status': constants.PortHealthStatus.NORMAL if interface_map['OperationalStatus'] == 'healthy' else constants.PortHealthStatus.ABNORMAL, 'type': type, 'logical_type': logical_type, 'speed': '', 'max_speed': '', 'native_parent_id': '', 'wwn': '', 'mac_address': '', 'ipv4': ipv4, 'ipv4_mask': ipv4_mask, 'ipv6': ipv6, 'ipv6_mask': ipv6_mask, } ports_list.append(p) return ports_list except exception.DelfinException as e: err_msg = "Failed to get storage ports from " \ "netapp_fas fas: %s" % (six.text_type(e)) LOG.error(err_msg) raise e except Exception as err: err_msg = "Failed to get storage ports from " \ "netapp_fas fas: %s" % (six.text_type(err)) LOG.error(err_msg) raise exception.InvalidResults(err_msg) def get_eth_port(self, storage_id): try: eth_list = [] eth_info = self.exec_ssh_command( netapp_constants.PORT_SHOW_DETAIL_COMMAND) eth_arr = eth_info.split( netapp_constants.PORT_SPLIT_STR) for eth in eth_arr[1:]: eth_map = {} self.handle_detail(eth, eth_map, split=':') e = { 'name': eth_map['Port'], 'storage_id': storage_id, 'native_port_id': eth_map['Port'], 'location': '', 'connection_status': constants.PortConnectionStatus.CONNECTED if eth_map['Link'] == 'up' else constants.PortConnectionStatus.DISCONNECTED, 'health_status': constants.PortHealthStatus.NORMAL if eth_map['PortHealthStatus'] == 'healthy' else constants.PortHealthStatus.ABNORMAL, 'type': constants.PortType.ETH, 'logical_type': '', 'speed': eth_map['SpeedOperational'], 'max_speed': eth_map['MTU'], 'native_parent_id': '', 'wwn': '', 'mac_address': eth_map['MACAddress'], 'ipv4': '', 'ipv4_mask': '', 'ipv6': '', 'ipv6_mask': '', } eth_list.append(e) return eth_list except exception.DelfinException as e: err_msg = "Failed to get storage ports from " \ "netapp_fas fas: %s" % (six.text_type(e)) LOG.error(err_msg) raise e except Exception as err: err_msg = "Failed to get storage ports from " \ "netapp_fas fas: %s" % (six.text_type(err)) LOG.error(err_msg) raise exception.InvalidResults(err_msg) def get_fc_port(self, storage_id): try: TYPE_MAP = { 'fibre-channel': constants.PortType.FC, 'ethernet': constants.PortType.FCOE } fc_list = [] fc_info = self.exec_ssh_command( netapp_constants.FC_PORT_SHOW_DETAIL_COMMAND) fc_arr = fc_info.split( netapp_constants.PORT_SPLIT_STR) for fc in fc_arr[1:]: fc_map = {} self.handle_detail(fc, fc_map, split=':') type = TYPE_MAP.get(fc_map['PhysicalProtocol']) f = { 'name': fc_map['Adapter'], 'storage_id': storage_id, 'native_port_id': fc_map['Adapter'], 'location': '', 'connection_status': constants.PortConnectionStatus.CONNECTED if fc_map['AdministrativeStatus'] == 'up' else constants.PortConnectionStatus.DISCONNECTED, 'health_status': constants.PortHealthStatus.NORMAL if fc_map['OperationalStatus'] == 'online' else constants.PortHealthStatus.ABNORMAL, 'type': type, 'logical_type': '', 'speed': fc_map['DataLinkRate(Gbit)'], 'max_speed': fc_map['MaximumSpeed'], 'native_parent_id': '', 'wwn': fc_map['AdapterWWNN'], 'mac_address': '', 'ipv4': '', 'ipv4_mask': '', 'ipv6': '', 'ipv6_mask': '', } fc_list.append(f) return fc_list except exception.DelfinException as e: err_msg = "Failed to get storage ports from " \ "netapp_fas fas: %s" % (six.text_type(e)) LOG.error(err_msg) raise e except Exception as err: err_msg = "Failed to get storage ports from " \ "netapp_fas fas: %s" % (six.text_type(err)) LOG.error(err_msg) raise exception.InvalidResults(err_msg) def list_ports(self, storage_id): ports_list = \ self.get_network_port(storage_id) + \ self.get_fc_port(storage_id) + \ self.get_eth_port(storage_id) return ports_list def list_disks(self, storage_id): try: TYPE_MAP = { 'ATA': constants.DiskPhysicalType.SATA, 'BSAS': constants.DiskPhysicalType, 'FCAL': constants.DiskPhysicalType, 'FSAS': constants.DiskPhysicalType, 'LUN ': constants.DiskPhysicalType, 'SAS': constants.DiskPhysicalType.SAS, 'MSATA': constants.DiskPhysicalType, 'SSD': constants.DiskPhysicalType.SSD, 'VMDISK': constants.DiskPhysicalType, 'unknown': constants.DiskPhysicalType.UNKNOWN, } LOGICAL_MAP = { 'aggregate': constants.DiskLogicalType.MEMBER, 'spare': constants.DiskLogicalType.HOTSPARE, 'unknown': constants.DiskLogicalType.UNKNOWN, 'free': constants.DiskLogicalType.FREE, 'broken': constants.DiskLogicalType, 'foreign': constants.DiskLogicalType, 'labelmaint': constants.DiskLogicalType, 'maintenance': constants.DiskLogicalType, 'shared': constants.DiskLogicalType, 'unassigned': constants.DiskLogicalType, 'unsupported': constants.DiskLogicalType, 'remote': constants.DiskLogicalType, 'mediator': constants.DiskLogicalType, } disks_list = [] physicals_list = [] disks_info = self.exec_ssh_command( netapp_constants.DISK_SHOW_DETAIL_COMMAND) disks_arr = disks_info.split( netapp_constants.DISK_SPLIT_STR) physicals_info = self.exec_ssh_command( netapp_constants.DISK_SHOW_PHYSICAL_COMMAND) disks_map = {} physical_arr = physicals_info.split('\n') speed = physical_type = firmware = '-' for i in range(2, len(physical_arr), 2): physicals_list.append(physical_arr[i].split()) for disk_str in disks_arr[1:]: self.handle_detail(disk_str, disks_map, split=':') logical_type = LOGICAL_MAP.get(disks_map['ContainerType']) """Map disk physical information""" for physical_info in physicals_list: if len(physical_info) > 6: if physical_info[0] == disks_map['k']: physical_type = TYPE_MAP.get(physical_info[1]) speed = physical_info[5] firmware = physical_info[4] status = constants.DiskStatus.NORMAL \ if disks_map['Errors:'] is None \ or disks_map['Errors:'] == "" \ else constants.DiskStatus.OFFLINE d = { 'name': disks_map['k'], 'storage_id': storage_id, 'native_disk_id': disks_map['k'], 'serial_number': disks_map['SerialNumber'], 'manufacturer': disks_map['Vendor'], 'model': disks_map['Model'], 'firmware': firmware, 'speed': speed, 'capacity': int(self.parse_string(disks_map['PhysicalSize'])), 'status': status, 'physical_type': physical_type, 'logical_type': logical_type, 'health_score': '', 'native_disk_group_id': disks_map['Aggregate'], 'location': '', } disks_list.append(d) return disks_list except exception.DelfinException as e: err_msg = "Failed to get storage disks from " \ "netapp_fas fas: %s" % (six.text_type(e)) LOG.error(err_msg) raise e except Exception as err: err_msg = "Failed to get storage disks from " \ "netapp_fas fas: %s" % (six.text_type(err)) LOG.error(err_msg) raise exception.InvalidResults(err_msg) def list_qtrees(self, storage_id): try: qt_list = [] qt_info = self.exec_ssh_command( netapp_constants.QTREE_SHOW_DETAIL_COMMAND) qt_arr = qt_info.split(netapp_constants.QTREE_SPLIT_STR) qt_map = {} for qt in qt_arr[1:]: self.handle_detail(qt, qt_map, split=':') q = { 'name': qt_map['QtreeName'], 'storage_id': storage_id, 'native_qtree_id': qt_map['Actual(Non-Junction)QtreePath'], 'native_filesystem_id': qt_map['VolumeName'], 'security_mode': qt_map['SecurityStyle'], } qt_list.append(q) return qt_list except exception.DelfinException as err: err_msg = "Failed to get storage qtrees from " \ "netapp_fas fas: %s" % (six.text_type(err)) LOG.error(err_msg) raise err except Exception as err: err_msg = "Failed to get storage qtrees from " \ "netapp_fas fas: %s" % (six.text_type(err)) LOG.error(err_msg) raise exception.InvalidResults(err_msg) def list_shares(self, storage_id): try: shares_list = [] cifs_share_info = self.exec_ssh_command( netapp_constants.CIFS_SHARE_SHOW_DETAIL_COMMAND) cifs_share_arr = cifs_share_info.split( netapp_constants.CIFS_SHARE_SPLIT_STR) protocol_info = self.exec_ssh_command( netapp_constants.SHARE_AGREEMENT_SHOW_COMMAND) cifs_share_map = {} protocol_map = {} protocol_arr = protocol_info.split('\n') for protocol in protocol_arr[2:]: agr_arr = protocol.split() if len(agr_arr) > 1: protocol_map[agr_arr[0]] = agr_arr[1] for cifs_share in cifs_share_arr[1:]: self.handle_detail(cifs_share, cifs_share_map, split=':') protocol = protocol_map.get(cifs_share_map['r']) s = { 'name': cifs_share_map['Share'], 'storage_id': storage_id, 'native_share_id': cifs_share_map['Share'], 'native_filesystem_id': cifs_share_map['VolumeName'], 'path': cifs_share_map['Path'], 'protocol': protocol } shares_list.append(s) return shares_list except exception.DelfinException as err: err_msg = "Failed to get storage shares from " \ "netapp_fas fas: %s" % (six.text_type(err)) LOG.error(err_msg) raise err except Exception as err: err_msg = "Failed to get storage shares from " \ "netapp_fas fas: %s" % (six.text_type(err)) LOG.error(err_msg) raise exception.InvalidResults(err_msg) def list_filesystems(self, storage_id): try: STATUS_MAP = { 'online': constants.FilesystemStatus.NORMAL, 'restricted': constants.FilesystemStatus.FAULTY, 'offline': constants.FilesystemStatus.NORMAL, 'force-online': constants.FilesystemStatus.FAULTY, 'force-offline': constants.FilesystemStatus.FAULTY, } fs_list = [] fs_info = self.exec_ssh_command( netapp_constants.FS_SHOW_DETAIL_COMMAND) fs_arr = fs_info.split( netapp_constants.FS_SPLIT_STR) thin_fs_info = self.exec_ssh_command( netapp_constants.THIN_FS_SHOW_COMMAND) pool_list = self.list_storage_pools(storage_id) thin_fs_arr = thin_fs_info.split("\n") type = constants.FSType.THICK fs_map = {} for fs_str in fs_arr[1:]: self.handle_detail(fs_str, fs_map, split=':') if fs_map is not None or fs_map != {}: pool_id = "" """get pool id""" for pool in pool_list: if pool['name'] == fs_map['AggregateName']: pool_id = pool['native_storage_pool_id'] deduplicated = False \ if fs_map['SpaceSavedbyDeduplication'] == '0B' \ else True if len(thin_fs_arr) > 2: for thin_vol in thin_fs_arr[2:]: thin_arr = thin_vol.split() if len(thin_arr) > 4: if thin_arr[1] == fs_map['VolumeName']: type = constants.VolumeType.THIN compressed = False \ if fs_map['VolumeContainsSharedorCompressedData'] == 'false' \ else True status = STATUS_MAP.get(fs_map['VolumeState']) f = { 'name': fs_map['VolumeName'], 'storage_id': storage_id, 'native_filesystem_id': fs_map['VolumeName'], 'native_pool_id': pool_id, 'compressed': compressed, 'deduplicated': deduplicated, 'worm': fs_map['SnapLockType'], 'status': status, 'type': type, 'total_capacity': int(self.parse_string(fs_map['VolumeSize'])), 'used_capacity': int(self.parse_string(fs_map['UsedSize'])), 'free_capacity': int(self.parse_string(fs_map['VolumeSize'])) - int(self.parse_string(fs_map['UsedSize'])) } fs_list.append(f) return fs_list except exception.DelfinException as e: err_msg = "Failed to get storage volume from " \ "netapp_fas fas: %s" % (six.text_type(e)) LOG.error(err_msg) raise e except Exception as err: err_msg = "Failed to get storage volume from " \ "netapp_fas fas: %s" % (six.text_type(err)) LOG.error(err_msg) raise exception.InvalidResults(err_msg) def add_trap_config(self, context, trap_config): pass def remove_trap_config(self, context, trap_config): pass
class SSHHandler(object): # 显示配置参数的值 CONFIG_GET = 'config_get [ name=machine_serial_number ]' # 打印系统的当前版本 VERSION_GET = 'version_get' def __init__(self, **kwargs): self.kwargs = kwargs self.ssh_pool = SSHPool(**kwargs) def login(self): try: with self.ssh_pool.item() as ssh: SSHHandler.do_exec('lssystem', ssh) except Exception as e: LOG.error("Failed to login ibm a9000r %s" % (six.text_type(e))) raise e # 显示配置参数的值 machine_serial_number的获取 def get_storage_serial_number(self): serialNumber = None try: serialNumber = self.exec_ssh_command(SSHHandler.CONFIG_GET) except Exception as e: LOG.error("Get all storage machine_serial_number error: %s", six.text_type(e)) return serialNumber # 可打印系统的当前版本 firmware_version字段获取 def get_storage_version_get(self): firmwareVersion = None try: # ssh_client = SSHClient(**self.kwargs) # firmwareVersion = ssh_client.do_exec(SSHHandler.VERSION_GET) firmwareVersion = self.exec_ssh_command(SSHHandler.VERSION_GET) except Exception as e: LOG.error("Get all storage firmware_version error: %s", six.text_type(e)) return firmwareVersion def exec_ssh_command(self, command): try: with self.ssh_pool.item() as ssh: ssh_info = SSHHandler.do_exec(command, ssh) return ssh_info except Exception as e: msg = "Failed to ssh ibm a9000r ssh_handler %s: %s" % \ (command, six.text_type(e)) raise exception.SSHException(msg) def exec_ssh_command(self, command): try: with self.ssh_pool.item() as ssh: ssh_info = SSHHandler.do_exec(command, ssh) return ssh_info except Exception as e: msg = "Failed to ssh ibm storwize_svc %s: %s" % \ (command, six.text_type(e)) raise exception.SSHException(msg) @staticmethod def do_exec(command_str, ssh): """Execute command""" try: utils.check_ssh_injection(command_str) if command_str is not None and ssh is not None: stdin, stdout, stderr = ssh.exec_command(command_str) res, err = stdout.read(), stderr.read() re = res if res else err result = re.decode() except paramiko.AuthenticationException as ae: LOG.error('doexec Authentication error:{}'.format(ae)) raise exception.InvalidUsernameOrPassword() except Exception as e: err = six.text_type(e) LOG.error('doexec InvalidUsernameOrPassword error') if 'timed out' in err: raise exception.SSHConnectTimeout() elif 'No authentication methods available' in err \ or 'Authentication failed' in err: raise exception.InvalidUsernameOrPassword() elif 'not a valid RSA private key file' in err: raise exception.InvalidPrivateKey() else: raise exception.SSHException(err) return result
class SSHHandler(object): OID_ERR_ID = '1.3.6.1.4.1.2.6.190.4.3' OID_SEQ_NUMBER = '1.3.6.1.4.1.2.6.190.4.9' OID_LAST_TIME = '1.3.6.1.4.1.2.6.190.4.10' OID_OBJ_TYPE = '1.3.6.1.4.1.2.6.190.4.11' OID_OBJ_NAME = '1.3.6.1.4.1.2.6.190.4.17' OID_SEVERITY = '1.3.6.1.6.3.1.1.4.1.0' TRAP_SEVERITY_MAP = { '1.3.6.1.4.1.2.6.190.1': constants.Severity.CRITICAL, '1.3.6.1.4.1.2.6.190.2': constants.Severity.WARNING, '1.3.6.1.4.1.2.6.190.3': constants.Severity.INFORMATIONAL, } SEVERITY_MAP = { "warning": "Warning", "informational": "Informational", "error": "Major" } SECONDS_TO_MS = 1000 def __init__(self, **kwargs): self.ssh_pool = SSHPool(**kwargs) @staticmethod def handle_split(split_str, split_char, arr_number): split_value = '' if split_str is not None and split_str != '': tmp_value = split_str.split(split_char, 1) if arr_number == 1 and len(tmp_value) > 1: split_value = tmp_value[arr_number].strip() elif arr_number == 0: split_value = tmp_value[arr_number].strip() return split_value @staticmethod def parse_alert(alert): try: alert_model = dict() alert_name = SSHHandler.handle_split( alert.get(SSHHandler.OID_ERR_ID), ':', 1) error_info = SSHHandler.handle_split( alert.get(SSHHandler.OID_ERR_ID), ':', 0) alert_id = SSHHandler.handle_split(error_info, '=', 1) severity = SSHHandler.TRAP_SEVERITY_MAP.get( alert.get(SSHHandler.OID_SEVERITY), constants.Severity.INFORMATIONAL) alert_model['alert_id'] = str(alert_id) alert_model['alert_name'] = alert_name alert_model['severity'] = severity alert_model['category'] = constants.Category.FAULT alert_model['type'] = constants.EventType.EQUIPMENT_ALARM alert_model['sequence_number'] = SSHHandler. \ handle_split(alert.get(SSHHandler.OID_SEQ_NUMBER), '=', 1) timestamp = SSHHandler. \ handle_split(alert.get(SSHHandler.OID_LAST_TIME), '=', 1) time_type = '%a %b %d %H:%M:%S %Y' occur_time = int(time.mktime(time.strptime(timestamp, time_type))) alert_model['occur_time'] = int(occur_time * SSHHandler.SECONDS_TO_MS) alert_model['description'] = alert_name alert_model['resource_type'] = SSHHandler.handle_split( alert.get(SSHHandler.OID_OBJ_TYPE), '=', 1) alert_model['location'] = SSHHandler.handle_split( alert.get(SSHHandler.OID_OBJ_NAME), '=', 1) return alert_model except Exception as e: LOG.error(e) msg = ("Failed to build alert model as some attributes missing " "in alert message:%s.") % (six.text_type(e)) raise exception.InvalidResults(msg) def login(self): try: with self.ssh_pool.item() as ssh: SSHHandler.do_exec('lssystem', ssh) except Exception as e: LOG.error("Failed to login ibm storwize_svc %s" % (six.text_type(e))) raise e @staticmethod def do_exec(command_str, ssh): """Execute command""" try: utils.check_ssh_injection(command_str) if command_str is not None and ssh is not None: stdin, stdout, stderr = ssh.exec_command(command_str) res, err = stdout.read(), stderr.read() re = res if res else err result = re.decode() except paramiko.AuthenticationException as ae: LOG.error('doexec Authentication error:{}'.format(ae)) raise exception.InvalidUsernameOrPassword() except Exception as e: err = six.text_type(e) LOG.error('doexec InvalidUsernameOrPassword error') if 'timed out' in err: raise exception.SSHConnectTimeout() elif 'No authentication methods available' in err \ or 'Authentication failed' in err: raise exception.InvalidUsernameOrPassword() elif 'not a valid RSA private key file' in err: raise exception.InvalidPrivateKey() else: raise exception.SSHException(err) return result def exec_ssh_command(self, command): try: with self.ssh_pool.item() as ssh: ssh_info = SSHHandler.do_exec(command, ssh) return ssh_info except Exception as e: msg = "Failed to ssh ibm storwize_svc %s: %s" % \ (command, six.text_type(e)) raise exception.SSHException(msg) def change_capacity_to_bytes(self, unit): unit = unit.upper() if unit == 'TB': result = units.Ti elif unit == 'GB': result = units.Gi elif unit == 'MB': result = units.Mi elif unit == 'KB': result = units.Ki else: result = 1 return int(result) def parse_string(self, value): capacity = 0 if value: if value.isdigit(): capacity = float(value) else: unit = value[-2:] capacity = float(value[:-2]) * int( self.change_capacity_to_bytes(unit)) return capacity def get_storage(self): try: system_info = self.exec_ssh_command('lssystem') enclosure_info = self.exec_ssh_command('lsenclosure -delim :') enclosure_res = enclosure_info.split('\n') enclosure = enclosure_res[1].split(':') serial_number = enclosure[7] storage_map = {} self.handle_detail(system_info, storage_map, split=' ') status = 'normal' if storage_map.get('statistics_status') == 'on' \ else 'offline' location = storage_map.get('location') free_capacity = self.parse_string( storage_map.get('total_free_space')) used_capacity = self.parse_string( storage_map.get('total_used_capacity')) raw_capacity = self.parse_string( storage_map.get('total_drive_raw_capacity')) subscribed_capacity = self.parse_string( storage_map.get('virtual_capacity')) firmware_version = '' if storage_map.get('code_level') is not None: firmware_version = storage_map.get('code_level').split(' ')[0] s = { 'name': storage_map.get('name'), 'vendor': 'IBM', 'model': storage_map.get('product_name'), 'status': status, 'serial_number': serial_number, 'firmware_version': firmware_version, 'location': location, 'total_capacity': int(free_capacity + used_capacity), 'raw_capacity': int(raw_capacity), 'subscribed_capacity': int(subscribed_capacity), 'used_capacity': int(used_capacity), 'free_capacity': int(free_capacity) } return s except exception.DelfinException as e: err_msg = "Failed to get storage: %s" % (six.text_type(e.msg)) LOG.error(err_msg) raise e except Exception as err: err_msg = "Failed to get storage: %s" % (six.text_type(err)) LOG.error(err_msg) raise exception.InvalidResults(err_msg) def handle_detail(self, deltail_info, detail_map, split): detail_arr = deltail_info.split('\n') for detail in detail_arr: if detail is not None and detail != '': strinfo = detail.split(split, 1) key = strinfo[0] value = '' if len(strinfo) > 1: value = strinfo[1] detail_map[key] = value def list_storage_pools(self, storage_id): try: pool_list = [] pool_info = self.exec_ssh_command('lsmdiskgrp') pool_res = pool_info.split('\n') for i in range(1, len(pool_res)): if pool_res[i] is None or pool_res[i] == '': continue pool_str = ' '.join(pool_res[i].split()) strinfo = pool_str.split(' ') detail_command = 'lsmdiskgrp %s' % strinfo[0] deltail_info = self.exec_ssh_command(detail_command) pool_map = {} self.handle_detail(deltail_info, pool_map, split=' ') status = 'normal' if pool_map.get('status') == 'online' \ else 'offline' total_cap = self.parse_string(pool_map.get('capacity')) free_cap = self.parse_string(pool_map.get('free_capacity')) used_cap = self.parse_string(pool_map.get('used_capacity')) subscribed_capacity = self.parse_string( pool_map.get('virtual_capacity')) p = { 'name': pool_map.get('name'), 'storage_id': storage_id, 'native_storage_pool_id': pool_map.get('id'), 'description': '', 'status': status, 'storage_type': constants.StorageType.BLOCK, 'subscribed_capacity': int(subscribed_capacity), 'total_capacity': int(total_cap), 'used_capacity': int(used_cap), 'free_capacity': int(free_cap) } pool_list.append(p) return pool_list except exception.DelfinException as e: err_msg = "Failed to get storage pool: %s" % (six.text_type(e)) LOG.error(err_msg) raise e except Exception as err: err_msg = "Failed to get storage pool: %s" % (six.text_type(err)) LOG.error(err_msg) raise exception.InvalidResults(err_msg) def list_volumes(self, storage_id): try: volume_list = [] volume_info = self.exec_ssh_command('lsvdisk') volume_res = volume_info.split('\n') for i in range(1, len(volume_res)): if volume_res[i] is None or volume_res[i] == '': continue volume_str = ' '.join(volume_res[i].split()) strinfo = volume_str.split(' ') volume_name = strinfo[1] detail_command = 'lsvdisk -delim : %s' % volume_name deltail_info = self.exec_ssh_command(detail_command) volume_map = {} self.handle_detail(deltail_info, volume_map, split=':') status = 'normal' if volume_map.get('status') == 'online' \ else 'offline' volume_type = 'thin' if volume_map.get('se_copy') == 'yes' \ else 'thick' total_capacity = self.parse_string(volume_map.get('capacity')) free_capacity = self.parse_string( volume_map.get('free_capacity')) used_capacity = self.parse_string( volume_map.get('used_capacity')) compressed = True deduplicated = True if volume_map.get('compressed_copy') == 'no': compressed = False if volume_map.get('deduplicated_copy') == 'no': deduplicated = False v = { 'name': volume_map.get('name'), 'storage_id': storage_id, 'description': '', 'status': status, 'native_volume_id': str(volume_map.get('id')), 'native_storage_pool_id': volume_map.get('mdisk_grp_id'), 'wwn': str(volume_map.get('vdisk_UID')), 'type': volume_type, 'total_capacity': int(total_capacity), 'used_capacity': int(used_capacity), 'free_capacity': int(free_capacity), 'compressed': compressed, 'deduplicated': deduplicated } volume_list.append(v) return volume_list except exception.DelfinException as e: err_msg = "Failed to get storage volume: %s" % (six.text_type(e)) LOG.error(err_msg) raise e except Exception as err: err_msg = "Failed to get storage volume: %s" % (six.text_type(err)) LOG.error(err_msg) raise exception.InvalidResults(err_msg) def list_alerts(self, query_para): try: alert_list = [] alert_info = self.exec_ssh_command('lseventlog -monitoring yes') alert_res = alert_info.split('\n') for i in range(1, len(alert_res)): if alert_res[i] is None or alert_res[i] == '': continue alert_str = ' '.join(alert_res[i].split()) strinfo = alert_str.split(' ', 1) detail_command = 'lseventlog %s' % strinfo[0] deltail_info = self.exec_ssh_command(detail_command) alert_map = {} self.handle_detail(deltail_info, alert_map, split=' ') occur_time = int(alert_map.get('last_timestamp_epoch')) * \ self.SECONDS_TO_MS if not alert_util.is_alert_in_time_range( query_para, occur_time): continue alert_name = alert_map.get('event_id_text', '') event_id = alert_map.get('event_id') location = alert_map.get('object_name', '') resource_type = alert_map.get('object_type', '') severity = self.SEVERITY_MAP.get( alert_map.get('notification_type')) alert_model = { 'alert_id': event_id, 'alert_name': alert_name, 'severity': severity, 'category': constants.Category.FAULT, 'type': 'EquipmentAlarm', 'sequence_number': alert_map.get('sequence_number'), 'occur_time': occur_time, 'description': alert_name, 'resource_type': resource_type, 'location': location } alert_list.append(alert_model) return alert_list except exception.DelfinException as e: err_msg = "Failed to get storage alert: %s" % (six.text_type(e)) LOG.error(err_msg) raise e except Exception as err: err_msg = "Failed to get storage alert: %s" % (six.text_type(err)) LOG.error(err_msg) raise exception.InvalidResults(err_msg)
class SSHHandler(object): OID_ERR_ID = '1.3.6.1.4.1.2.6.190.4.3' OID_SEQ_NUMBER = '1.3.6.1.4.1.2.6.190.4.9' OID_LAST_TIME = '1.3.6.1.4.1.2.6.190.4.10' OID_OBJ_TYPE = '1.3.6.1.4.1.2.6.190.4.11' OID_OBJ_NAME = '1.3.6.1.4.1.2.6.190.4.17' OID_SEVERITY = '1.3.6.1.6.3.1.1.4.1.0' TRAP_SEVERITY_MAP = { '1.3.6.1.4.1.2.6.190.1': constants.Severity.CRITICAL, '1.3.6.1.4.1.2.6.190.2': constants.Severity.WARNING, '1.3.6.1.4.1.2.6.190.3': constants.Severity.INFORMATIONAL, } SEVERITY_MAP = { "warning": "Warning", "informational": "Informational", "error": "Major" } CONTRL_STATUS_MAP = { "online": constants.ControllerStatus.NORMAL, "offline": constants.ControllerStatus.OFFLINE, "service": constants.ControllerStatus.NORMAL, "flushing": constants.ControllerStatus.UNKNOWN, "pending": constants.ControllerStatus.UNKNOWN, "adding": constants.ControllerStatus.UNKNOWN, "deleting": constants.ControllerStatus.UNKNOWN } DISK_PHYSICAL_TYPE = { 'fc': constants.DiskPhysicalType.FC, 'sas_direct': constants.DiskPhysicalType.SAS } VOLUME_PERF_METRICS = { 'readIops': 'ro', 'writeIops': 'wo', 'readThroughput': 'rb', 'writeThroughput': 'wb', 'readIoSize': 'rb', 'writeIoSize': 'wb', 'responseTime': 'res_time', 'throughput': 'tb', 'iops': 'to', 'ioSize': 'tb', 'cacheHitRatio': 'hrt', 'readCacheHitRatio': 'rhr', 'writeCacheHitRatio': 'whr' } DISK_PERF_METRICS = { 'readIops': 'ro', 'writeIops': 'wo', 'readThroughput': 'rb', 'writeThroughput': 'wb', 'responseTime': 'res_time', 'throughput': 'tb', 'iops': 'to' } CONTROLLER_PERF_METRICS = { 'readIops': 'ro', 'writeIops': 'wo', 'readThroughput': 'rb', 'writeThroughput': 'wb', 'responseTime': 'res_time', 'throughput': 'tb', 'iops': 'to' } PORT_PERF_METRICS = { 'readIops': 'ro', 'writeIops': 'wo', 'readThroughput': 'rb', 'writeThroughput': 'wb', 'throughput': 'tb', 'responseTime': 'res_time', 'iops': 'to' } TARGET_RESOURCE_RELATION = { constants.ResourceType.DISK: 'mdsk', constants.ResourceType.VOLUME: 'vdsk', constants.ResourceType.PORT: 'port', constants.ResourceType.CONTROLLER: 'node' } RESOURCE_PERF_MAP = { constants.ResourceType.DISK: DISK_PERF_METRICS, constants.ResourceType.VOLUME: VOLUME_PERF_METRICS, constants.ResourceType.PORT: PORT_PERF_METRICS, constants.ResourceType.CONTROLLER: CONTROLLER_PERF_METRICS } SECONDS_TO_MS = 1000 ALERT_NOT_FOUND_CODE = 'CMMVC8275E' BLOCK_SIZE = 512 BYTES_TO_BIT = 8 def __init__(self, **kwargs): self.ssh_pool = SSHPool(**kwargs) @staticmethod def handle_split(split_str, split_char, arr_number): split_value = '' if split_str is not None and split_str != '': tmp_value = split_str.split(split_char, 1) if arr_number == 1 and len(tmp_value) > 1: split_value = tmp_value[arr_number].strip() elif arr_number == 0: split_value = tmp_value[arr_number].strip() return split_value @staticmethod def parse_alert(alert): try: alert_model = dict() alert_name = SSHHandler.handle_split( alert.get(SSHHandler.OID_ERR_ID), ':', 1) error_info = SSHHandler.handle_split( alert.get(SSHHandler.OID_ERR_ID), ':', 0) alert_id = SSHHandler.handle_split(error_info, '=', 1) severity = SSHHandler.TRAP_SEVERITY_MAP.get( alert.get(SSHHandler.OID_SEVERITY), constants.Severity.INFORMATIONAL) alert_model['alert_id'] = str(alert_id) alert_model['alert_name'] = alert_name alert_model['severity'] = severity alert_model['category'] = constants.Category.FAULT alert_model['type'] = constants.EventType.EQUIPMENT_ALARM alert_model['sequence_number'] = SSHHandler. \ handle_split(alert.get(SSHHandler.OID_SEQ_NUMBER), '=', 1) timestamp = SSHHandler. \ handle_split(alert.get(SSHHandler.OID_LAST_TIME), '=', 1) time_type = '%a %b %d %H:%M:%S %Y' occur_time = int(time.mktime(time.strptime(timestamp, time_type))) alert_model['occur_time'] = int(occur_time * SSHHandler.SECONDS_TO_MS) alert_model['description'] = alert_name alert_model['resource_type'] = SSHHandler.handle_split( alert.get(SSHHandler.OID_OBJ_TYPE), '=', 1) alert_model['location'] = SSHHandler.handle_split( alert.get(SSHHandler.OID_OBJ_NAME), '=', 1) return alert_model except Exception as e: LOG.error(e) msg = ("Failed to build alert model as some attributes missing " "in alert message:%s.") % (six.text_type(e)) raise exception.InvalidResults(msg) def login(self): try: with self.ssh_pool.item() as ssh: result = SSHHandler.do_exec('lssystem', ssh) if 'is not a recognized command' in result: raise exception.InvalidIpOrPort() except Exception as e: LOG.error("Failed to login ibm storwize_svc %s" % (six.text_type(e))) raise e @staticmethod def do_exec(command_str, ssh): """Execute command""" try: utils.check_ssh_injection(command_str.split()) if command_str is not None and ssh is not None: stdin, stdout, stderr = ssh.exec_command(command_str) res, err = stdout.read(), stderr.read() re = res if res else err result = re.decode() except paramiko.AuthenticationException as ae: LOG.error('doexec Authentication error:{}'.format(ae)) raise exception.InvalidUsernameOrPassword() except Exception as e: err = six.text_type(e) LOG.error('doexec InvalidUsernameOrPassword error') if 'timed out' in err: raise exception.SSHConnectTimeout() elif 'No authentication methods available' in err \ or 'Authentication failed' in err: raise exception.InvalidUsernameOrPassword() elif 'not a valid RSA private key file' in err: raise exception.InvalidPrivateKey() else: raise exception.SSHException(err) return result def exec_ssh_command(self, command): try: with self.ssh_pool.item() as ssh: ssh_info = SSHHandler.do_exec(command, ssh) return ssh_info except Exception as e: msg = "Failed to ssh ibm storwize_svc %s: %s" % \ (command, six.text_type(e)) raise exception.SSHException(msg) def change_capacity_to_bytes(self, unit): unit = unit.upper() if unit == 'TB': result = units.Ti elif unit == 'GB': result = units.Gi elif unit == 'MB': result = units.Mi elif unit == 'KB': result = units.Ki else: result = 1 return int(result) def parse_string(self, value): capacity = 0 if value: if value.isdigit(): capacity = float(value) else: unit = value[-2:] capacity = float(value[:-2]) * int( self.change_capacity_to_bytes(unit)) return capacity def get_storage(self): try: system_info = self.exec_ssh_command('lssystem') storage_map = {} self.handle_detail(system_info, storage_map, split=' ') serial_number = storage_map.get('id') status = 'normal' if storage_map.get('statistics_status') == 'on' \ else 'offline' location = storage_map.get('location') free_capacity = self.parse_string( storage_map.get('total_free_space')) used_capacity = self.parse_string( storage_map.get('total_used_capacity')) raw_capacity = self.parse_string( storage_map.get('total_mdisk_capacity')) subscribed_capacity = self.parse_string( storage_map.get('virtual_capacity')) firmware_version = '' if storage_map.get('code_level') is not None: firmware_version = storage_map.get('code_level').split(' ')[0] s = { 'name': storage_map.get('name'), 'vendor': 'IBM', 'model': storage_map.get('product_name'), 'status': status, 'serial_number': serial_number, 'firmware_version': firmware_version, 'location': location, 'total_capacity': int(free_capacity + used_capacity), 'raw_capacity': int(raw_capacity), 'subscribed_capacity': int(subscribed_capacity), 'used_capacity': int(used_capacity), 'free_capacity': int(free_capacity) } return s except exception.DelfinException as e: err_msg = "Failed to get storage: %s" % (six.text_type(e.msg)) LOG.error(err_msg) raise e except Exception as err: err_msg = "Failed to get storage: %s" % (six.text_type(err)) LOG.error(err_msg) raise exception.InvalidResults(err_msg) def handle_detail(self, deltail_info, detail_map, split): detail_arr = deltail_info.split('\n') for detail in detail_arr: if detail is not None and detail != '': strinfo = detail.split(split, 1) key = strinfo[0] value = '' if len(strinfo) > 1: value = strinfo[1] detail_map[key] = value def list_storage_pools(self, storage_id): try: pool_list = [] pool_info = self.exec_ssh_command('lsmdiskgrp') pool_res = pool_info.split('\n') for i in range(1, len(pool_res)): if pool_res[i] is None or pool_res[i] == '': continue pool_str = ' '.join(pool_res[i].split()) strinfo = pool_str.split(' ') detail_command = 'lsmdiskgrp %s' % strinfo[0] deltail_info = self.exec_ssh_command(detail_command) pool_map = {} self.handle_detail(deltail_info, pool_map, split=' ') status = 'normal' if pool_map.get('status') == 'online' \ else 'offline' total_cap = self.parse_string(pool_map.get('capacity')) free_cap = self.parse_string(pool_map.get('free_capacity')) used_cap = self.parse_string(pool_map.get('used_capacity')) subscribed_capacity = self.parse_string( pool_map.get('virtual_capacity')) p = { 'name': pool_map.get('name'), 'storage_id': storage_id, 'native_storage_pool_id': pool_map.get('id'), 'description': '', 'status': status, 'storage_type': constants.StorageType.BLOCK, 'subscribed_capacity': int(subscribed_capacity), 'total_capacity': int(total_cap), 'used_capacity': int(used_cap), 'free_capacity': int(free_cap) } pool_list.append(p) return pool_list except exception.DelfinException as e: err_msg = "Failed to get storage pool: %s" % (six.text_type(e)) LOG.error(err_msg) raise e except Exception as err: err_msg = "Failed to get storage pool: %s" % (six.text_type(err)) LOG.error(err_msg) raise exception.InvalidResults(err_msg) def list_volumes(self, storage_id): try: volume_list = [] volume_info = self.exec_ssh_command('lsvdisk') volume_res = volume_info.split('\n') for i in range(1, len(volume_res)): if volume_res[i] is None or volume_res[i] == '': continue volume_str = ' '.join(volume_res[i].split()) strinfo = volume_str.split(' ') volume_id = strinfo[0] detail_command = 'lsvdisk -delim : %s' % volume_id deltail_info = self.exec_ssh_command(detail_command) volume_map = {} self.handle_detail(deltail_info, volume_map, split=':') status = 'normal' if volume_map.get('status') == 'online' \ else 'offline' volume_type = 'thin' if volume_map.get('se_copy') == 'yes' \ else 'thick' total_capacity = self.parse_string(volume_map.get('capacity')) free_capacity = self.parse_string( volume_map.get('free_capacity')) used_capacity = self.parse_string( volume_map.get('used_capacity')) compressed = True deduplicated = True if volume_map.get('compressed_copy') == 'no': compressed = False if volume_map.get('deduplicated_copy') == 'no': deduplicated = False v = { 'name': volume_map.get('name'), 'storage_id': storage_id, 'description': '', 'status': status, 'native_volume_id': str(volume_map.get('id')), 'native_storage_pool_id': volume_map.get('mdisk_grp_id'), 'wwn': str(volume_map.get('vdisk_UID')), 'type': volume_type, 'total_capacity': int(total_capacity), 'used_capacity': int(used_capacity), 'free_capacity': int(free_capacity), 'compressed': compressed, 'deduplicated': deduplicated } volume_list.append(v) return volume_list except exception.DelfinException as e: err_msg = "Failed to get storage volume: %s" % (six.text_type(e)) LOG.error(err_msg) raise e except Exception as err: err_msg = "Failed to get storage volume: %s" % (six.text_type(err)) LOG.error(err_msg) raise exception.InvalidResults(err_msg) def list_alerts(self, query_para): try: alert_list = [] alert_info = self.exec_ssh_command('lseventlog -monitoring yes ' '-message no') alert_res = alert_info.split('\n') for i in range(1, len(alert_res)): if alert_res[i] is None or alert_res[i] == '': continue alert_str = ' '.join(alert_res[i].split()) strinfo = alert_str.split(' ', 1) detail_command = 'lseventlog %s' % strinfo[0] deltail_info = self.exec_ssh_command(detail_command) alert_map = {} self.handle_detail(deltail_info, alert_map, split=' ') occur_time = int(alert_map.get('last_timestamp_epoch')) * \ self.SECONDS_TO_MS if not alert_util.is_alert_in_time_range( query_para, occur_time): continue alert_name = alert_map.get('event_id_text', '') event_id = alert_map.get('event_id') location = alert_map.get('object_name', '') resource_type = alert_map.get('object_type', '') severity = self.SEVERITY_MAP.get( alert_map.get('notification_type')) if severity == 'Informational' or severity is None: continue alert_model = { 'alert_id': event_id, 'alert_name': alert_name, 'severity': severity, 'category': constants.Category.FAULT, 'type': 'EquipmentAlarm', 'sequence_number': alert_map.get('sequence_number'), 'occur_time': occur_time, 'description': alert_name, 'resource_type': resource_type, 'location': location } alert_list.append(alert_model) return alert_list except exception.DelfinException as e: err_msg = "Failed to get storage alert: %s" % (six.text_type(e)) LOG.error(err_msg) raise e except Exception as err: err_msg = "Failed to get storage alert: %s" % (six.text_type(err)) LOG.error(err_msg) raise exception.InvalidResults(err_msg) def fix_alert(self, alert): command_line = 'cheventlog -fix %s' % alert result = self.exec_ssh_command(command_line) if result: if self.ALERT_NOT_FOUND_CODE not in result: raise exception.InvalidResults(six.text_type(result)) LOG.warning("Alert %s doesn't exist.", alert) def list_controllers(self, storage_id): try: controller_list = [] controller_cmd = 'lsnode' control_info = self.exec_ssh_command(controller_cmd) if 'command not found' in control_info: controller_cmd = 'lsnodecanister' control_info = self.exec_ssh_command(controller_cmd) control_res = control_info.split('\n') for i in range(1, len(control_res)): if control_res[i] is None or control_res[i] == '': continue control_str = ' '.join(control_res[i].split()) str_info = control_str.split(' ') control_id = str_info[0] detail_command = '%s %s' % (controller_cmd, control_id) deltail_info = self.exec_ssh_command(detail_command) control_map = {} self.handle_detail(deltail_info, control_map, split=' ') status = SSHHandler.CONTRL_STATUS_MAP.get( control_map.get('status'), constants.ControllerStatus.UNKNOWN) controller_result = { 'name': control_map.get('name'), 'storage_id': storage_id, 'native_controller_id': control_map.get('id'), 'status': status, 'soft_version': control_map.get('code_level', '').split(' ')[0], 'location': control_map.get('name') } controller_list.append(controller_result) return controller_list except Exception as err: err_msg = "Failed to get controller attributes from Storwize: %s"\ % (six.text_type(err)) LOG.error(err_msg) raise exception.InvalidResults(err_msg) def list_disks(self, storage_id): try: disk_list = [] disk_info = self.exec_ssh_command('lsmdisk') disk_res = disk_info.split('\n') for i in range(1, len(disk_res)): if disk_res[i] is None or disk_res[i] == '': continue control_str = ' '.join(disk_res[i].split()) str_info = control_str.split(' ') disk_id = str_info[0] detail_command = 'lsmdisk %s' % disk_id deltail_info = self.exec_ssh_command(detail_command) disk_map = {} self.handle_detail(deltail_info, disk_map, split=' ') status = constants.DiskStatus.NORMAL if disk_map.get('status') == 'offline': status = constants.DiskStatus.OFFLINE physical_type = SSHHandler.DISK_PHYSICAL_TYPE.get( disk_map.get('fabric_type'), constants.DiskPhysicalType.UNKNOWN) location = '%s_%s' % (disk_map.get('controller_name'), disk_map.get('name')) disk_result = { 'name': disk_map.get('name'), 'storage_id': storage_id, 'native_disk_id': disk_map.get('id'), 'capacity': int(self.parse_string(disk_map.get('capacity'))), 'status': status, 'physical_type': physical_type, 'native_disk_group_id': disk_map.get('mdisk_grp_name'), 'location': location } disk_list.append(disk_result) return disk_list except Exception as err: err_msg = "Failed to get disk attributes from Storwize: %s" % \ (six.text_type(err)) raise exception.InvalidResults(err_msg) def get_fc_port(self, storage_id): port_list = [] fc_info = self.exec_ssh_command('lsportfc') fc_res = fc_info.split('\n') for i in range(1, len(fc_res)): if fc_res[i] is None or fc_res[i] == '': continue control_str = ' '.join(fc_res[i].split()) str_info = control_str.split(' ') port_id = str_info[0] detail_command = 'lsportfc %s' % port_id deltail_info = self.exec_ssh_command(detail_command) port_map = {} self.handle_detail(deltail_info, port_map, split=' ') status = constants.PortHealthStatus.NORMAL conn_status = constants.PortConnectionStatus.CONNECTED if port_map.get('status') != 'active': status = constants.PortHealthStatus.ABNORMAL conn_status = constants.PortConnectionStatus.DISCONNECTED port_type = constants.PortType.FC if port_map.get('type') == 'ethernet': port_type = constants.PortType.ETH location = '%s_%s' % (port_map.get('node_name'), port_map.get('id')) speed = None if port_map.get('port_speed')[:-2].isdigit(): speed = int( self.handle_port_bps(port_map.get('port_speed'), 'fc')) port_result = { 'name': location, 'storage_id': storage_id, 'native_port_id': port_map.get('id'), 'location': location, 'connection_status': conn_status, 'health_status': status, 'type': port_type, 'speed': speed, 'native_parent_id': port_map.get('node_name'), 'wwn': port_map.get('WWPN') } port_list.append(port_result) return port_list def get_iscsi_port(self, storage_id): port_list = [] for i in range(1, 3): port_array = [] port_command = 'lsportip %s' % i port_info = self.exec_ssh_command(port_command) port_arr = port_info.split('\n') port_map = {} for detail in port_arr: if detail is not None and detail != '': strinfo = detail.split(' ', 1) key = strinfo[0] value = '' if len(strinfo) > 1: value = strinfo[1] port_map[key] = value else: if len(port_map) > 1: port_array.append(port_map) port_map = {} continue for port in port_array: if port.get('failover') == 'yes': continue status = constants.PortHealthStatus.ABNORMAL if port.get('state') == 'online': status = constants.PortHealthStatus.NORMAL conn_status = constants.PortConnectionStatus.DISCONNECTED if port.get('link_state') == 'active': conn_status = constants.PortConnectionStatus.CONNECTED port_type = constants.PortType.ETH location = '%s_%s' % (port.get('node_name'), port.get('id')) port_result = { 'name': location, 'storage_id': storage_id, 'native_port_id': location, 'location': location, 'connection_status': conn_status, 'health_status': status, 'type': port_type, 'speed': int(self.handle_port_bps(port.get('speed'), 'eth')), 'native_parent_id': port.get('node_name'), 'mac_address': port.get('MAC'), 'ipv4': port.get('IP_address'), 'ipv4_mask': port.get('mask'), 'ipv6': port.get('IP_address_6') } port_list.append(port_result) return port_list @staticmethod def change_speed_to_bytes(unit): unit = unit.upper() if unit == 'TB': result = units.T elif unit == 'GB': result = units.G elif unit == 'MB': result = units.M elif unit == 'KB': result = units.k else: result = 1 return int(result) def handle_port_bps(self, value, port_type): speed = 0 if value: if value.isdigit(): speed = float(value) else: if port_type == 'fc': unit = value[-2:] speed = float(value[:-2]) * int( self.change_speed_to_bytes(unit)) else: unit = value[-4:-2] speed = float(value[:-4]) * int( self.change_speed_to_bytes(unit)) return speed def list_ports(self, storage_id): try: port_list = [] port_list.extend(self.get_fc_port(storage_id)) port_list.extend(self.get_iscsi_port(storage_id)) return port_list except Exception as err: err_msg = "Failed to get ports attributes from Storwize: %s" % \ (six.text_type(err)) raise exception.InvalidResults(err_msg) @staticmethod def handle_stats_filename(file_name, file_map): name_arr = file_name.split('_') file_type = '%s_%s_%s' % (name_arr[0], name_arr[1], name_arr[2]) file_time = '20%s%s' % (name_arr[3], name_arr[4]) time_pattern = '%Y%m%d%H%M%S' tools = Tools() occur_time = tools.time_str_to_timestamp(file_time, time_pattern) if file_map.get(file_type): file_map[file_type][occur_time] = file_name else: file_map[file_type] = {occur_time: file_name} def get_stats_filelist(self, file_map): stats_file_command = 'lsdumps -prefix /dumps/iostats' file_list = self.exec_ssh_command(stats_file_command) file_line = file_list.split('\n') for file in islice(file_line, 1, None): if file: file_arr = ' '.join(file.split()).split(' ') if len(file_arr) > 1: file_name = file_arr[1] SSHHandler.handle_stats_filename(file_name, file_map) for file_stats in file_map: file_map[file_stats] = sorted(file_map.get(file_stats).items(), key=lambda x: x[0], reverse=False) def packege_data(self, storage_id, resource_type, metrics, metric_map): resource_id = None resource_name = None unit = None for resource_info in metric_map: if resource_type == constants.ResourceType.PORT: port_info = self.get_fc_port(storage_id) if port_info: for fc_port in port_info: if resource_info.strip('0x').upper() == fc_port.get( 'wwn').upper(): resource_id = fc_port.get('native_port_id') resource_name = fc_port.get('name') break else: resource_arr = resource_info.split('_') resource_id = resource_arr[0] resource_name = resource_arr[1] for target in metric_map.get(resource_info): if resource_type == constants.ResourceType.PORT: unit = consts.PORT_CAP[target]['unit'] elif resource_type == constants.ResourceType.VOLUME: unit = consts.VOLUME_CAP[target]['unit'] elif resource_type == constants.ResourceType.DISK: unit = consts.DISK_CAP[target]['unit'] elif resource_type == constants.ResourceType.CONTROLLER: unit = consts.CONTROLLER_CAP[target]['unit'] if 'responseTime' == target: for res_time in metric_map.get(resource_info).get(target): for iops_time in metric_map.get(resource_info).get( 'iops'): if res_time == iops_time: res_value = metric_map.get(resource_info).get( target).get(res_time) iops_value = metric_map.get(resource_info).get( 'iops').get(iops_time) res_value = \ res_value / iops_value if iops_value else 0 res_value = round(res_value, 3) metric_map[resource_info][target][res_time] = \ res_value break labels = { 'storage_id': storage_id, 'resource_type': resource_type, 'resource_id': resource_id, 'resource_name': resource_name, 'type': 'RAW', 'unit': unit } metric_value = constants.metric_struct( name=target, labels=labels, values=metric_map.get(resource_info).get(target)) metrics.append(metric_value) @staticmethod def count_metric_data(last_data, now_data, interval, target, metric_type, metric_map, res_id): if not target: return if 'CACHEHITRATIO' not in metric_type.upper(): value = SSHHandler.count_difference(now_data.get(target), last_data.get(target)) else: value = now_data.get( SSHHandler.VOLUME_PERF_METRICS.get(metric_type)) if 'THROUGHPUT' in metric_type.upper(): value = value / interval / units.Mi elif 'IOSIZE' in metric_type.upper(): value = value / units.Ki elif 'IOPS' in metric_type.upper() or 'RESPONSETIME' \ in metric_type.upper(): value = value / interval value = round(value, 3) if metric_map.get(res_id): if metric_map.get(res_id).get(metric_type): if metric_map.get(res_id).get(metric_type).get( now_data.get('time')): metric_map[res_id][metric_type][now_data.get('time')] \ += value else: metric_map[res_id][metric_type][now_data.get('time')] \ = value else: metric_map[res_id][metric_type] = {now_data.get('time'): value} else: metric_map[res_id] = {metric_type: {now_data.get('time'): value}} @staticmethod def count_difference(now_value, last_value): value = 0 if now_value >= last_value: value = now_value - last_value else: value = now_value return value @staticmethod def handle_volume_cach_hit(now_data, last_data): rh = SSHHandler.count_difference(now_data.get('rh'), last_data.get('rh')) wh = SSHHandler.count_difference(now_data.get('wh'), last_data.get('wh')) rht = SSHHandler.count_difference(now_data.get('rht'), last_data.get('rht')) wht = SSHHandler.count_difference(now_data.get('wht'), last_data.get('wht')) rhr = rh * 100 / rht if rht > 0 else 0 whr = wh * 100 / wht if wht > 0 else 0 hrt = rhr + whr now_data['rhr'] = rhr now_data['whr'] = whr now_data['hrt'] = hrt def get_date_from_each_file(self, file, metric_map, target_list, resource_type, last_data): with self.ssh_pool.item() as ssh: local_path = '%s/%s' % (os.path.abspath(os.path.join( os.getcwd())), consts.LOCAL_FILE_PATH) file_xml = Tools.get_remote_file_to_xml(ssh, file[1], local_path, consts.REMOTE_FILE_PATH) if not file_xml: return for data in file_xml: if re.sub(u"\\{.*?}", "", data.tag) == \ SSHHandler.TARGET_RESOURCE_RELATION.get( resource_type): if resource_type == constants.ResourceType.PORT: if data.attrib.get('fc_wwpn'): resource_info = data.attrib.get('fc_wwpn') else: continue elif resource_type == constants. \ ResourceType.CONTROLLER: resource_info = '%s_%s' % (int( data.attrib.get('node_id'), 16), data.attrib.get('id')) else: resource_info = '%s_%s' % (data.attrib.get('idx'), data.attrib.get('id')) now_data = SSHHandler.package_xml_data( data.attrib, file[0], resource_type) if last_data.get(resource_info): interval = ( int(file[0]) - last_data.get(resource_info).get('time')) / units.k if interval <= 0: break if resource_type == constants.ResourceType.VOLUME: SSHHandler.handle_volume_cach_hit( now_data, last_data.get(resource_info)) for target in target_list: device_target = SSHHandler. \ RESOURCE_PERF_MAP.get(resource_type) SSHHandler.count_metric_data( last_data.get(resource_info), now_data, interval, device_target.get(target), target, metric_map, resource_info) last_data[resource_info] = now_data else: last_data[resource_info] = now_data def get_stats_from_file(self, file_list, metric_map, target_list, resource_type, start_time, end_time): if not file_list: return find_first_file = False recent_file = None last_data = {} for file in file_list: if file[0] >= start_time and file[0] <= end_time: if find_first_file is False: if recent_file: self.get_date_from_each_file(recent_file, metric_map, target_list, resource_type, last_data) self.get_date_from_each_file(file, metric_map, target_list, resource_type, last_data) find_first_file = True else: self.get_date_from_each_file(file, metric_map, target_list, resource_type, last_data) recent_file = file @staticmethod def package_xml_data(file_data, file_time, resource_type): rb = 0 wb = 0 res_time = 0 rh = 0 wh = 0 rht = 0 wht = 0 if resource_type == constants.ResourceType.PORT: rb = int(file_data.get('cbr')) + int(file_data.get('hbr')) + int( file_data.get('lnbr')) + int( file_data.get('rmbr')) * SSHHandler.BYTES_TO_BIT wb = int(file_data.get('cbt')) + int(file_data.get('hbt')) + int( file_data.get('lnbt')) + int( file_data.get('rmbt')) * SSHHandler.BYTES_TO_BIT ro = int(file_data.get('cer')) + int(file_data.get('her')) + int( file_data.get('lner')) + int(file_data.get('rmer')) wo = int(file_data.get('cet')) + int(file_data.get('het')) + int( file_data.get('lnet')) + int(file_data.get('rmet')) res_time = int(file_data.get('dtdt', 0)) / units.Ki else: if resource_type == constants.ResourceType.VOLUME: rb = int(file_data.get('rb')) * SSHHandler.BLOCK_SIZE wb = int(file_data.get('wb')) * SSHHandler.BLOCK_SIZE rh = int(file_data.get('ctrhs')) wh = int(file_data.get('ctwhs')) rht = int(file_data.get('ctrs')) wht = int(file_data.get('ctws')) res_time = int(file_data.get('xl')) elif resource_type == constants.ResourceType.DISK: rb = int(file_data.get('rb')) * SSHHandler.BLOCK_SIZE wb = int(file_data.get('wb')) * SSHHandler.BLOCK_SIZE res_time = int(file_data.get('rq')) + int(file_data.get('wq')) elif resource_type == constants.ResourceType.CONTROLLER: rb = int(file_data.get('rb')) * SSHHandler.BYTES_TO_BIT wb = int(file_data.get('wb')) * SSHHandler.BYTES_TO_BIT res_time = int(file_data.get('rq')) + int(file_data.get('wq')) ro = int(file_data.get('ro')) wo = int(file_data.get('wo')) now_data = { 'rb': rb, 'wb': wb, 'ro': ro, 'wo': wo, 'tb': rb + wb, 'to': ro + wo, 'rh': rh, 'wh': wh, 'rht': rht, 'wht': wht, 'res_time': res_time, 'time': int(file_time) } return now_data def get_stats_file_data(self, file_map, res_type, metrics, storage_id, target_list, start_time, end_time): metric_map = {} for file_tye in file_map: file_list = file_map.get(file_tye) if 'Nv' in file_tye and res_type == constants.ResourceType.VOLUME: self.get_stats_from_file(file_list, metric_map, target_list, constants.ResourceType.VOLUME, start_time, end_time) elif 'Nm' in file_tye and res_type == constants.ResourceType.DISK: self.get_stats_from_file(file_list, metric_map, target_list, constants.ResourceType.DISK, start_time, end_time) elif 'Nn' in file_tye and res_type == constants.ResourceType.PORT: self.get_stats_from_file(file_list, metric_map, target_list, constants.ResourceType.PORT, start_time, end_time) elif 'Nn' in file_tye and res_type == \ constants.ResourceType.CONTROLLER: self.get_stats_from_file(file_list, metric_map, target_list, constants.ResourceType.CONTROLLER, start_time, end_time) self.packege_data(storage_id, res_type, metrics, metric_map) def collect_perf_metrics(self, storage_id, resource_metrics, start_time, end_time): metrics = [] file_map = {} try: self.get_stats_filelist(file_map) if resource_metrics.get(constants.ResourceType.VOLUME): self.get_stats_file_data( file_map, constants.ResourceType.VOLUME, metrics, storage_id, resource_metrics.get(constants.ResourceType.VOLUME), start_time, end_time) if resource_metrics.get(constants.ResourceType.DISK): self.get_stats_file_data( file_map, constants.ResourceType.DISK, metrics, storage_id, resource_metrics.get(constants.ResourceType.DISK), start_time, end_time) if resource_metrics.get(constants.ResourceType.PORT): self.get_stats_file_data( file_map, constants.ResourceType.PORT, metrics, storage_id, resource_metrics.get(constants.ResourceType.PORT), start_time, end_time) if resource_metrics.get(constants.ResourceType.CONTROLLER): self.get_stats_file_data( file_map, constants.ResourceType.CONTROLLER, metrics, storage_id, resource_metrics.get(constants.ResourceType.CONTROLLER), start_time, end_time) except Exception as err: err_msg = "Failed to collect metrics from svc: %s" % \ (six.text_type(err)) LOG.error(err_msg) raise exception.InvalidResults(err_msg) return metrics def get_latest_perf_timestamp(self): latest_time = 0 stats_file_command = 'lsdumps -prefix /dumps/iostats' file_list = self.exec_ssh_command(stats_file_command) file_line = file_list.split('\n') for file in islice(file_line, 1, None): if file: file_arr = ' '.join(file.split()).split(' ') if len(file_arr) > 1: file_name = file_arr[1] name_arr = file_name.split('_') file_time = '20%s%s' % (name_arr[3], name_arr[4]) time_pattern = '%Y%m%d%H%M%S' tools = Tools() occur_time = tools.time_str_to_timestamp( file_time, time_pattern) if latest_time < occur_time: latest_time = occur_time return latest_time