diff --git a/delfin/drivers/ibm/ds8k/consts.py b/delfin/drivers/ibm/ds8k/consts.py new file mode 100644 index 000000000..d7d907371 --- /dev/null +++ b/delfin/drivers/ibm/ds8k/consts.py @@ -0,0 +1,2 @@ +HOST_PORT_URL = '/api/v1/host_ports' +HOST_URL = '/api/v1/hosts' diff --git a/delfin/drivers/ibm/ds8k/ds8k.py b/delfin/drivers/ibm/ds8k/ds8k.py index 41b25fe09..550109626 100644 --- a/delfin/drivers/ibm/ds8k/ds8k.py +++ b/delfin/drivers/ibm/ds8k/ds8k.py @@ -18,7 +18,7 @@ from delfin import exception from delfin.common import constants from delfin.drivers import driver -from delfin.drivers.ibm.ds8k import rest_handler, alert_handler +from delfin.drivers.ibm.ds8k import rest_handler, alert_handler, consts LOG = log.getLogger(__name__) @@ -35,6 +35,10 @@ class DS8KDriver(driver.StorageDriver): 'fenced': constants.PortHealthStatus.UNKNOWN, 'quiescing': constants.PortHealthStatus.UNKNOWN } + INITIATOR_STATUS_MAP = {'logged in': constants.InitiatorStatus.ONLINE, + 'logged out': constants.InitiatorStatus.OFFLINE, + 'unconfigured': constants.InitiatorStatus.UNKNOWN + } def __init__(self, **kwargs): super().__init__(**kwargs) @@ -259,3 +263,83 @@ def clear_alert(self, context, alert): @staticmethod def get_access_url(): return 'https://{ip}:{port}' + + def list_storage_hosts(self, context): + try: + host_list = [] + hosts = self.rest_handler.get_rest_info(consts.HOST_URL) + if not hosts: + return host_list + host_entries = hosts.get('data', {}).get('hosts', []) + for host in host_entries: + status = constants.HostStatus.NORMAL if \ + host.get('state') == 'online' else \ + constants.HostStatus.OFFLINE + os_type = constants.HostOSTypes.VMWARE_ESX if \ + host.get('hosttype') == 'VMware' else \ + constants.HostOSTypes.UNKNOWN + host_result = { + "name": host.get('name'), + "storage_id": self.storage_id, + "native_storage_host_id": host.get('name'), + "os_type": os_type, + "status": status + } + host_list.append(host_result) + return host_list + except Exception as e: + LOG.error("Failed to get hosts from ds8k") + raise e + + def list_masking_views(self, context): + try: + view_list = [] + hosts = self.rest_handler.get_rest_info(consts.HOST_URL) + if not hosts: + return view_list + host_entries = hosts.get('data', {}).get('hosts', []) + for host in host_entries: + view_url = '%s/%s/mappings' % (consts.HOST_URL, + host.get('name')) + views = self.rest_handler.get_rest_info(view_url) + if not views: + continue + view_entries = views.get('data', {}).get('mappings', []) + for view in view_entries: + view_id = '%s_%s' % (view.get('lunid'), host.get('name')) + view_result = { + "name": view_id, + "native_storage_host_id": host.get('name'), + "storage_id": self.storage_id, + "native_volume_id": view.get('volume', {}).get('id'), + "native_masking_view_id": view_id, + } + view_list.append(view_result) + return view_list + except Exception as e: + LOG.error("Failed to get views from ds8k") + raise e + + def list_storage_host_initiators(self, context): + try: + initiator_list = [] + host_ports = self.rest_handler.get_rest_info(consts.HOST_PORT_URL) + if not host_ports: + return initiator_list + port_entries = host_ports.get('data', {}).get('host_ports', []) + for port in port_entries: + status = DS8KDriver.INITIATOR_STATUS_MAP.get(port.get('state')) + init_result = { + "name": port.get('wwpn'), + "storage_id": self.storage_id, + "native_storage_host_initiator_id": port.get('wwpn'), + "wwn": port.get('wwpn'), + "status": status, + "type": constants.InitiatorType.UNKNOWN, + "native_storage_host_id": port.get('host', {}).get('name') + } + initiator_list.append(init_result) + return initiator_list + except Exception as e: + LOG.error("Failed to get initiators from ds8k") + raise e diff --git a/delfin/tests/unit/drivers/ibm/ibm_ds8k/test_ibm_ds8k.py b/delfin/tests/unit/drivers/ibm/ibm_ds8k/test_ibm_ds8k.py index e3dcd7936..145608c03 100644 --- a/delfin/tests/unit/drivers/ibm/ibm_ds8k/test_ibm_ds8k.py +++ b/delfin/tests/unit/drivers/ibm/ibm_ds8k/test_ibm_ds8k.py @@ -344,6 +344,80 @@ 'resource_type': 'Storage', 'location': 'eeeeeeeee' } +GET_INITORATORS = { + "data": { + "host_ports": + [ + { + "wwpn": "50050763030813A2", + "state": "logged in", + "hosttype": "VMware", + "addrdiscovery": "lunpolling", + "lbs": "512", + "host": { + "name": "myhost" + } + } + ] + } +} +INIT_RESULT = [ + { + 'name': '50050763030813A2', + 'storage_id': '12345', + 'native_storage_host_initiator_id': '50050763030813A2', + 'wwn': '50050763030813A2', + 'status': 'online', + 'type': 'unknown', + 'native_storage_host_id': 'myhost' + } +] +GET_ALL_HOSTS = { + "data": { + "hosts": + [ + { + "name": "test_host", + "state": "online", + "hosttype": "VMware", + "addrmode": "SCSI mask", + "addrdiscovery": "lunpolling", + "lbs": "512" + } + ] + } +} +HOST_RESULT = [ + { + 'name': 'test_host', + 'storage_id': '12345', + 'native_storage_host_id': 'test_host', + 'os_type': 'VMware ESX', + 'status': 'normal' + } +] +GET_HOST_MAPPING = { + "data": { + "mappings": + [ + { + "lunid": "00", + "volume": { + "id": "0005" + } + } + ] + } +} +VIEW_RESULT = [ + { + 'name': '00_test_host', + 'native_storage_host_id': 'test_host', + 'storage_id': '12345', + 'native_volume_id': '0005', + 'native_masking_view_id': '00_test_host' + } +] class TestDS8KDriver(TestCase): @@ -401,3 +475,25 @@ def test_list_list_controllers(self, mock_contrl): mock_contrl.return_value = GET_ALL_CONTROLLERS controller = DS8KDriver(**ACCESS_INFO).list_controllers(context) self.assertEqual(controller, contrl_result) + + @mock.patch.object(RestHandler, 'get_rest_info') + def test_host_initiators(self, mock_init): + RestHandler.login = mock.Mock(return_value=None) + mock_init.return_value = GET_INITORATORS + initiators = DS8KDriver( + **ACCESS_INFO).list_storage_host_initiators(context) + self.assertEqual(initiators, INIT_RESULT) + + @mock.patch.object(RestHandler, 'get_rest_info') + def test_hosts(self, mock_host): + RestHandler.login = mock.Mock(return_value=None) + mock_host.return_value = GET_ALL_HOSTS + hosts = DS8KDriver(**ACCESS_INFO).list_storage_hosts(context) + self.assertEqual(hosts, HOST_RESULT) + + @mock.patch.object(RestHandler, 'get_rest_info') + def test_masking_views(self, mock_view): + RestHandler.login = mock.Mock(return_value=None) + mock_view.side_effect = [GET_ALL_HOSTS, GET_HOST_MAPPING] + views = DS8KDriver(**ACCESS_INFO).list_masking_views(context) + self.assertEqual(views, VIEW_RESULT)