diff --git a/delfin/drivers/dell_emc/unity/alert_handler.py b/delfin/drivers/dell_emc/unity/alert_handler.py index 9ef1dddd1..ca544e300 100644 --- a/delfin/drivers/dell_emc/unity/alert_handler.py +++ b/delfin/drivers/dell_emc/unity/alert_handler.py @@ -131,9 +131,11 @@ def parse_queried_alerts(self, alert_model_list, alert_dict, query_para): alert_model['description'] = content.get('description') alert_model['resource_type'] = resource_type alert_model['location'] = location - alert_model_list.append(alert_model) alert_model['match_key'] = hashlib.md5( content.get('message').encode()).hexdigest() + if alert_model['severity'] == 'Informational': + continue + alert_model_list.append(alert_model) except Exception as e: LOG.error(e) err_msg = "Failed to build alert model as some attributes " \ diff --git a/delfin/drivers/dell_emc/unity/consts.py b/delfin/drivers/dell_emc/unity/consts.py index 5a2f884c6..c4d848246 100644 --- a/delfin/drivers/dell_emc/unity/consts.py +++ b/delfin/drivers/dell_emc/unity/consts.py @@ -13,6 +13,8 @@ # License for the specific language governing permissions and limitations # under the License. +DEFAULT_TIMEOUT = 10 +ALERT_TIMEOUT = 20 TRAP_DESC = { "1:127486a": ["WARNING", "ALRT_LCC_FW_UPGRADE_FAILED", "The link control card (LCC) will continue to function with " diff --git a/delfin/drivers/dell_emc/unity/rest_handler.py b/delfin/drivers/dell_emc/unity/rest_handler.py index 6ba34f2a3..6533d4583 100644 --- a/delfin/drivers/dell_emc/unity/rest_handler.py +++ b/delfin/drivers/dell_emc/unity/rest_handler.py @@ -19,6 +19,7 @@ from delfin import cryptor from delfin import exception +from delfin.drivers.dell_emc.unity import consts from delfin.drivers.utils.rest_client import RestClient LOG = logging.getLogger(__name__) @@ -56,14 +57,12 @@ def login(self): """Login dell_emc unity storage array.""" try: with self.session_lock: - data = {} if self.session is None: self.init_http_head() self.session.headers.update({"X-EMC-REST-CLIENT": "true"}) self.session.auth = requests.auth.HTTPBasicAuth( self.rest_username, cryptor.decode(self.rest_password)) - res = self.call_with_token( - RestHandler.REST_AUTH_URL, data, 'GET') + res = self.call_with_token(RestHandler.REST_AUTH_URL) if res.status_code == 200: self.session.headers[RestHandler.AUTH_KEY] = \ cryptor.encode(res.headers[RestHandler.AUTH_KEY]) @@ -81,14 +80,15 @@ def login(self): LOG.error("Login error: %s", six.text_type(e)) raise e - def call_with_token(self, url, data, method): + def call_with_token(self, url, data=None, method='GET', + calltimeout=consts.DEFAULT_TIMEOUT): auth_key = None if self.session: auth_key = self.session.headers.get(RestHandler.AUTH_KEY, None) if auth_key: self.session.headers[RestHandler.AUTH_KEY] \ = cryptor.decode(auth_key) - res = self.do_call(url, data, method) + res = self.do_call(url, data, method, calltimeout) if auth_key: self.session.headers[RestHandler.AUTH_KEY] = auth_key return res @@ -96,7 +96,7 @@ def call_with_token(self, url, data, method): def logout(self): try: if self.san_address: - self.call(RestHandler.REST_LOGOUT_URL, method='POST') + self.call(RestHandler.REST_LOGOUT_URL, None, 'POST') if self.session: self.session.close() except Exception as e: @@ -104,21 +104,23 @@ def logout(self): LOG.error(err_msg) raise e - def get_rest_info(self, url, data=None, method='GET'): + def get_rest_info(self, url, data=None, method='GET', + calltimeout=consts.DEFAULT_TIMEOUT): result_json = None - res = self.call(url, data, method) + res = self.call(url, data, method, calltimeout) if res.status_code == 200: result_json = res.json() return result_json - def call(self, url, data=None, method=None): + def call(self, url, data=None, method='GET', + calltimeout=consts.DEFAULT_TIMEOUT): try: - res = self.call_with_token(url, data, method) + res = self.call_with_token(url, data, method, calltimeout) if res.status_code == 401: LOG.error("Failed to get token, status_code:%s,error_mesg:%s" % (res.status_code, res.text)) self.login() - res = self.call_with_token(url, data, method) + res = self.call_with_token(url, data, method, calltimeout) elif res.status_code == 503: raise exception.InvalidResults(res.text) return res @@ -167,7 +169,18 @@ def get_all_alerts(self, page_number): 'messageId,message,description,' 'descriptionId,state', page_number) - result_json = self.get_rest_info(url) + result_json = self.get_rest_info( + url, None, 'GET', consts.ALERT_TIMEOUT) + return result_json + + def get_all_alerts_without_state(self, page_number): + url = '%s?%s&page=%s' % (RestHandler.REST_ALERTS_URL, + 'fields=id,timestamp,severity,component,' + 'messageId,message,description,' + 'descriptionId', + page_number) + result_json = self.get_rest_info( + url, None, 'GET', consts.ALERT_TIMEOUT) return result_json def remove_alert(self, alert_id): @@ -180,16 +193,15 @@ def remove_alert(self, alert_id): def get_all_controllers(self): url = '%s?%s' % (RestHandler.REST_CONTROLLER_URL, 'fields=id,name,health,model,slotNumber,' - 'emcPartNumber,emcSerialNumber,manufacturer,' - 'memorySize') + 'manufacturer,memorySize') result_json = self.get_rest_info(url) return result_json def get_all_disks(self): url = '%s?%s' % (RestHandler.REST_DISK_URL, 'fields=id,name,health,model,slotNumber,' - 'manufacturer,version,emcSerialNumber,wwn' - 'emcPartNumber,rpm,size,diskGroup') + 'manufacturer,version,emcSerialNumber,wwn,' + 'rpm,size,diskGroup,diskTechnology') result_json = self.get_rest_info(url) return result_json @@ -203,7 +215,7 @@ def get_all_fcports(self): def get_all_ethports(self): url = '%s?%s' % (RestHandler.REST_ETHPORT_URL, 'fields=id,name,health,portNumber,storageProcessor,' - 'speed,isLinkUp,macAddress,maxMtu') + 'speed,isLinkUp,macAddress') result_json = self.get_rest_info(url) return result_json @@ -221,6 +233,13 @@ def get_all_filesystems(self): result_json = self.get_rest_info(url) return result_json + def get_all_filesystems_without_flr(self): + url = '%s?%s' % (RestHandler.REST_FILESYSTEM_URL, + 'fields=id,name,health,sizeAllocated,accessPolicy,' + 'sizeTotal,sizeUsed,isThinEnabled,pool') + result_json = self.get_rest_info(url) + return result_json + def get_all_nfsshares(self): url = '%s?%s' % (RestHandler.REST_NFSSHARE_URL, 'fields=id,filesystem,name,path') @@ -249,7 +268,6 @@ def get_all_userquotas(self): def get_quota_configs(self): url = '%s?%s' % (RestHandler.REST_QUOTACONFIG_URL, - 'fields=id,filesystem,treeQuota,quotaPolicy,' - 'isUserQuotaEnabled,isAccessDenyEnabled') + 'fields=id,filesystem,treeQuota,quotaPolicy') result_json = self.get_rest_info(url) return result_json diff --git a/delfin/drivers/dell_emc/unity/unity.py b/delfin/drivers/dell_emc/unity/unity.py index 98d026481..ff2688621 100644 --- a/delfin/drivers/dell_emc/unity/unity.py +++ b/delfin/drivers/dell_emc/unity/unity.py @@ -40,6 +40,14 @@ class UnityStorDriver(driver.StorageDriver): 7: constants.ControllerStatus.NORMAL, 10: constants.ControllerStatus.DEGRADED } + DISK_TYPE_MAP = {1: constants.DiskPhysicalType.SAS, + 2: constants.DiskPhysicalType.NL_SAS, + 6: constants.DiskPhysicalType.FLASH, + 7: constants.DiskPhysicalType.FLASH, + 8: constants.DiskPhysicalType.FLASH, + 9: constants.DiskPhysicalType.FLASH, + 99: constants.DiskPhysicalType.VMDISK + } def __init__(self, **kwargs): super().__init__(**kwargs) @@ -80,11 +88,13 @@ def get_storage(self, context): used = content.get('sizeUsed') subs = content.get('sizeSubscribed') break - soft_version = version_info.get('entries') - for soft_info in soft_version: - content = soft_info.get('content', {}) - version = content.get('id') - break + if version_info: + soft_version = version_info.get('entries') + for soft_info in soft_version: + content = soft_info.get('content', {}) + if content: + version = content.get('id') + break system_result = { 'name': name, 'vendor': 'DELL EMC', @@ -164,6 +174,8 @@ def list_volumes(self, context): volume_list = [] while True: luns = self.rest_handler.get_all_luns(page_number) + if luns is None: + break if 'entries' not in luns: break if len(luns['entries']) < 1: @@ -178,6 +190,11 @@ def list_alerts(self, context, query_para=None): alert_model_list = [] while True: alert_list = self.rest_handler.get_all_alerts(page_number) + if not alert_list: + alert_list = self.rest_handler.get_all_alerts_without_state( + page_number) + if alert_list is None: + break if 'entries' not in alert_list: break if len(alert_list['entries']) < 1: @@ -232,7 +249,7 @@ def get_eth_ports(self): port_list = [] ports = self.rest_handler.get_all_ethports() ip_interfaces = self.rest_handler.get_port_interface() - if ports is not None: + if ports: port_entries = ports.get('entries') for port in port_entries: content = port.get('content') @@ -250,22 +267,23 @@ def get_eth_ports(self): ipv4_mask = None ipv6 = None ipv6_mask = None - for ip_info in ip_interfaces.get('entries'): - ip_content = ip_info.get('content') - if not ip_content: - continue - if content.get('id') == ip_content.get( - 'ipPort').get('id'): - if ip_content.get('ipProtocolVersion') == 4: - ipv4 = UnityStorDriver.handle_port_ip( - ipv4, ip_content.get('ipAddress')) - ipv4_mask = UnityStorDriver.handle_port_ip( - ipv4_mask, ip_content.get('netmask')) - else: - ipv6 = UnityStorDriver.handle_port_ip( - ipv6, ip_content.get('ipAddress')) - ipv6_mask = UnityStorDriver.handle_port_ip( - ipv6_mask, ip_content.get('netmask')) + if ip_interfaces: + for ip_info in ip_interfaces.get('entries'): + ip_content = ip_info.get('content') + if not ip_content: + continue + if content.get('id') == ip_content.get( + 'ipPort').get('id'): + if ip_content.get('ipProtocolVersion') == 4: + ipv4 = UnityStorDriver.handle_port_ip( + ipv4, ip_content.get('ipAddress')) + ipv4_mask = UnityStorDriver.handle_port_ip( + ipv4_mask, ip_content.get('netmask')) + else: + ipv6 = UnityStorDriver.handle_port_ip( + ipv6, ip_content.get('ipAddress')) + ipv6_mask = UnityStorDriver.handle_port_ip( + ipv6_mask, ip_content.get('netmask')) port_result = { 'name': content.get('name'), 'storage_id': self.storage_id, @@ -275,7 +293,8 @@ def get_eth_ports(self): 'health_status': status, 'type': constants.PortType.ETH, 'logical_type': '', - 'max_speed': int(content.get('speed')) * units.Mi, + 'speed': int(content.get('speed')) * units.M, + 'max_speed': int(content.get('speed')) * units.M, 'native_parent_id': content.get('storageProcessor', {}).get('id'), 'wwn': '', @@ -291,28 +310,38 @@ def get_eth_ports(self): def get_fc_ports(self): port_list = [] ports = self.rest_handler.get_all_fcports() - if ports is not None: + if ports: port_entries = ports.get('entries') for port in port_entries: content = port.get('content') if not content: continue health_value = content.get('health', {}).get('value') + connect_value = \ + content.get('health', {}).get('descriptionIds', []) + if 'ALRT_PORT_LINK_DOWN_NOT_IN_USE' in connect_value: + conn_status = constants.PortConnectionStatus.DISCONNECTED + elif 'ALRT_PORT_LINK_UP' in connect_value: + conn_status = constants.PortConnectionStatus.CONNECTED + else: + conn_status = constants.PortConnectionStatus.UNKNOWN if health_value in UnityStorDriver.HEALTH_OK: status = constants.PortHealthStatus.NORMAL else: status = constants.PortHealthStatus.ABNORMAL - conn_status = status port_result = { 'name': content.get('name'), 'storage_id': self.storage_id, 'native_port_id': content.get('id'), - 'location': content.get('slotNumber'), + 'location': content.get('name'), 'connection_status': conn_status, 'health_status': status, 'type': constants.PortType.FC, 'logical_type': '', - 'max_speed': int(content.get('currentSpeed')) * units.Gi, + 'speed': int( + content.get('currentSpeed', 0)) * units.G, + 'max_speed': int( + content.get('currentSpeed', 0)) * units.G, 'native_parent_id': content.get('storageProcessor', {}).get('id'), 'wwn': content.get('wwn') @@ -342,10 +371,17 @@ def list_disks(self, context): if not content: continue health_value = content.get('health', {}).get('value') + slot_info = \ + content.get('health', {}).get('descriptionIds', []) + if 'ALRT_DISK_SLOT_EMPTY' in slot_info: + continue if health_value in UnityStorDriver.HEALTH_OK: status = constants.DiskStatus.NORMAL else: status = constants.DiskStatus.ABNORMAL + physical_type = UnityStorDriver.DISK_TYPE_MAP.get( + content.get('diskTechnology'), + constants.DiskPhysicalType.UNKNOWN) disk_result = { 'name': content.get('name'), 'storage_id': self.storage_id, @@ -357,11 +393,11 @@ def list_disks(self, context): 'speed': int(content.get('rpm')), 'capacity': int(content.get('size')), 'status': status, - 'physical_type': constants.DiskPhysicalType.SAS, + 'physical_type': physical_type, 'logical_type': '', 'native_disk_group_id': content.get('diskGroup', {}).get('id'), - 'location': content.get('slotNumber') + 'location': content.get('name') } disk_list.append(disk_result) return disk_list @@ -374,6 +410,8 @@ def list_disks(self, context): def list_filesystems(self, context): try: files = self.rest_handler.get_all_filesystems() + if not files: + files = self.rest_handler.get_all_filesystems_without_flr() fs_list = [] if files is not None: fs_entries = files.get('entries') @@ -445,6 +483,8 @@ def list_qtrees(self, context): def get_share_qtree(self, path, qtree_list): qtree_id = None + if not qtree_list: + return qtree_id qts_entries = qtree_list.get('entries') for qtree in qts_entries: content = qtree.get('content') @@ -470,16 +510,17 @@ def get_share(self, protocol, qtree_list, filesystems): content = share.get('content') if not content: continue - file_entries = filesystems.get('entries') file_name = '' - for file in file_entries: - file_content = file.get('content') - if not file_content: - continue - if file_content.get('id') == content.get( - 'filesystem', {}).get('id'): - file_name = file_content.get('name') - break + if filesystems: + file_entries = filesystems.get('entries') + for file in file_entries: + file_content = file.get('content') + if not file_content: + continue + if file_content.get('id') == content.get( + 'filesystem', {}).get('id'): + file_name = file_content.get('name') + break path = '/%s%s' % (file_name, content.get('path')) if \ file_name != '' else content.get('path') fs = { @@ -505,6 +546,9 @@ def list_shares(self, context): share_list = [] qtrees = self.rest_handler.get_all_qtrees() filesystems = self.rest_handler.get_all_filesystems() + if not filesystems: + filesystems = \ + self.rest_handler.get_all_filesystems_without_flr() share_list.extend(self.get_share('cifs', qtrees, filesystems)) share_list.extend(self.get_share('nfs', qtrees, filesystems)) return share_list diff --git a/delfin/drivers/utils/rest_client.py b/delfin/drivers/utils/rest_client.py index 80b794208..91c71cefc 100644 --- a/delfin/drivers/utils/rest_client.py +++ b/delfin/drivers/utils/rest_client.py @@ -22,11 +22,12 @@ from delfin import exception from delfin import ssl_utils -from delfin.drivers.hpe.hpe_3par import consts from delfin.i18n import _ LOG = logging.getLogger(__name__) +SOCKET_TIMEOUT = 10 + class RestClient(object): @@ -65,7 +66,7 @@ def init_http_head(self): ssl_utils.get_host_name_ignore_adapter()) def do_call(self, url, data, method, - calltimeout=consts.SOCKET_TIMEOUT): + calltimeout=SOCKET_TIMEOUT): if 'http' not in url: if self.san_address: url = '%s%s' % (self.san_address, url) diff --git a/delfin/tests/unit/drivers/dell_emc/unity/test_emc_unity.py b/delfin/tests/unit/drivers/dell_emc/unity/test_emc_unity.py index 86c17d43d..16fbc6950 100644 --- a/delfin/tests/unit/drivers/dell_emc/unity/test_emc_unity.py +++ b/delfin/tests/unit/drivers/dell_emc/unity/test_emc_unity.py @@ -365,6 +365,7 @@ "sasExpanderVersion": "", "rpm": 12288, "size": 12121212, + "diskTechnology": 1, "diskGroup": { "id": "dp1" } @@ -387,7 +388,7 @@ 'physical_type': 'sas', 'logical_type': '', 'native_disk_group_id': 'dp1', - 'location': 12 + 'location': 'disk1' } ] GET_ALL_ETHPORTS = { @@ -667,7 +668,8 @@ 'health_status': 'normal', 'type': 'eth', 'logical_type': '', - 'max_speed': 10485760000, + 'speed': 10000000000, + 'max_speed': 10000000000, 'native_parent_id': 'spa', 'wwn': '', 'mac_address': '00:50:56:81:E1:50', @@ -684,7 +686,8 @@ 'health_status': 'normal', 'type': 'eth', 'logical_type': '', - 'max_speed': 10485760000, + 'speed': 10000000000, + 'max_speed': 10000000000, 'native_parent_id': 'spa', 'wwn': '', 'mac_address': '00:50:56:81:E8:4B', @@ -701,7 +704,8 @@ 'health_status': 'normal', 'type': 'eth', 'logical_type': '', - 'max_speed': 10485760000, + 'speed': 10000000000, + 'max_speed': 10000000000, 'native_parent_id': 'spa', 'wwn': '', 'mac_address': '00:50:56:81:11:EF', @@ -718,7 +722,8 @@ 'health_status': 'normal', 'type': 'eth', 'logical_type': '', - 'max_speed': 10485760000, + 'speed': 10000000000, + 'max_speed': 10000000000, 'native_parent_id': 'spa', 'wwn': '', 'mac_address': '00:50:56:81:DB:5D', @@ -735,7 +740,8 @@ 'health_status': 'normal', 'type': 'eth', 'logical_type': '', - 'max_speed': 10485760000, + 'speed': 10000000000, + 'max_speed': 10000000000, 'native_parent_id': 'spa', 'wwn': '', 'mac_address': '00:50:56:81:E5:05', @@ -747,12 +753,13 @@ 'name': 'SP A FC Port 0', 'storage_id': '12345', 'native_port_id': 'spa_fc0', - 'location': None, - 'connection_status': 'normal', + 'location': 'SP A FC Port 0', + 'connection_status': 'connected', 'health_status': 'normal', 'type': 'fc', 'logical_type': '', - 'max_speed': 10737418240, + 'speed': 10000000000, + 'max_speed': 10000000000, 'native_parent_id': 'spa', 'wwn': 'fffffffffff' }