From 247cd5e4ec95a2821f02a33952d00892fbf51527 Mon Sep 17 00:00:00 2001 From: zhilong-xu Date: Mon, 8 Nov 2021 10:54:02 +0800 Subject: [PATCH 1/2] pure codeview-Modify according to specifications --- delfin/drivers/pure/pure/pure_storage.py | 315 +++++++++--------- delfin/drivers/pure/pure/rest_handler.py | 44 ++- .../unit/drivers/pure/storage/test_storage.py | 25 +- 3 files changed, 192 insertions(+), 192 deletions(-) diff --git a/delfin/drivers/pure/pure/pure_storage.py b/delfin/drivers/pure/pure/pure_storage.py index e6c3aa9e8..c039e5120 100644 --- a/delfin/drivers/pure/pure/pure_storage.py +++ b/delfin/drivers/pure/pure/pure_storage.py @@ -1,5 +1,4 @@ import hashlib -import json from oslo_log import log from oslo_utils import units @@ -11,7 +10,7 @@ LOG = log.getLogger(__name__) -class StorageDriver(driver.StorageDriver): +class PureStorageDriver(driver.StorageDriver): SEVERITY_MAP = {'fatal': constants.Severity.FATAL, 'critical': constants.Severity.CRITICAL, 'major': constants.Severity.MAJOR, @@ -42,39 +41,34 @@ def __init__(self, **kwargs): self.rest_handler.login() def list_volumes(self, context): - volume = [] - volumes_return = self.rest_handler.get_all_rest_volumes() - if volumes_return: - volume = self.volume_handler(volumes_return) - return volume - - def volume_handler(self, volumes_return): - volume = [] - return_pool = self.rest_handler.get_all_pools() - for i in range(0, len(volumes_return)): - volume_dict = dict() - volume_object = volumes_return[i] - name = volume_object.get('name') - volume_dict['native_volume_id'] = name - volume_dict['name'] = name - total_capacity = int(int(volume_object.get('size')) / units.Ki) - volume_dict['total_capacity'] = total_capacity - used_capacity = int(int(volume_object.get('volumes')) / units.Ki) - volume_dict['used_capacity'] = used_capacity - volume_dict['free_capacity'] = total_capacity - used_capacity - volume_dict['storage_id'] = self.storage_id - volume_dict['description'] = "" - volume_dict['status'] = constants.StorageStatus.NORMAL - volume_dict['type'] = constants.VolumeType.THICK - volume_dict['native_storage_pool_id'] = "" - if return_pool: - for j in return_pool: - volumes = j.get('volumes') - if name in volumes: - volume_dict['native_storage_pool_id'] = j.get('name') - break - volume.append(volume_dict) - return volume + list_volumes = [] + volumes = self.rest_handler.get_volumes() + if volumes: + pools = self.rest_handler.get_pools() + for volume in volumes: + name = volume.get('name') + total_capacity = int(int(volume.get('size')) / units.Ki) + used_capacity = int(int(volume.get('volumes')) / units.Ki) + native_storage_pool_id = None + if pools: + for pool in pools: + pool_volumes = pool.get('volumes') + if name in pool_volumes: + native_storage_pool_id = pool.get('name') + break + volume_dict = { + 'native_volume_id': name, + 'name': name, + 'total_capacity': total_capacity, + 'used_capacity': used_capacity, + 'free_capacity': total_capacity - used_capacity, + 'storage_id': self.storage_id, + 'status': constants.StorageStatus.NORMAL, + 'type': constants.VolumeType.THICK, + 'native_storage_pool_id': native_storage_pool_id + } + list_volumes.append(volume_dict) + return list_volumes def add_trap_config(self, context, trap_config): pass @@ -83,43 +77,54 @@ def clear_alert(self, context, alert): pass def get_storage(self, context): - storage_object = dict() result_storage = self.rest_handler.get_storage() + model = None + total_capacity = None + used_capacity = None if result_storage: - storage_object['model'] = result_storage[0].get('hostname', "") - total_capacity = int(int(result_storage[0].get('provisioned', - 0)) / units.Ki) - storage_object['total_capacity'] = total_capacity - storage_object['raw_capacity'] = total_capacity - used_capacity = int(int(result_storage[0].get('volumes', 0)) / - units.Ki) - storage_object['used_capacity'] = used_capacity - storage_object['free_capacity'] = total_capacity - used_capacity + for storage in result_storage: + model = storage.get('hostname') + total_capacity = int(int(storage.get('provisioned', + 0)) / units.Ki) + used_capacity = int(int(storage.get('volumes', 0)) / + units.Ki) + break - return_storage_id = self.rest_handler.get_storage_ID() - storage_object['vendor'] = 'PURE' - storage_object['name'] = return_storage_id.get('array_name') - storage_object['serial_number'] = return_storage_id.get('id') - storage_object['firmware_version'] = return_storage_id.get('version') - storage_object['description'] = "" - storage_object['status'] = constants.StorageStatus.NORMAL - storage_object['location'] = "" - return storage_object + storage_id = self.rest_handler.get_storage_id() + name = None + serial_number = None + version = None + if storage_id: + name = storage_id.get('array_name') + serial_number = storage_id.get('id') + version = storage_id.get('version') + storage = { + 'model': model, + 'total_capacity': total_capacity, + 'raw_capacity': total_capacity, + 'used_capacity': used_capacity, + 'free_capacity': total_capacity - used_capacity, + 'vendor': 'PURE', + 'name': name, + 'serial_number': serial_number, + 'firmware_version': version, + 'status': constants.StorageStatus.NORMAL, + 'location': name + } + return storage def list_alerts(self, context, query_para=None): - return_alerts = self.rest_handler.get_all_alerts() + return_alerts = self.rest_handler.get_alerts() alerts_list = [] if return_alerts: for alerts in return_alerts: alerts_model = dict() alerts_model['alert_id'] = alerts.get('id') - severity = alerts.get('current_severity') - alerts_model['severity'] = StorageDriver.SEVERITY_MAP.get( - severity, constants.Severity.NOT_SPECIFIED) - - category = alerts.get('category') - alerts_model['category'] = StorageDriver.CATEGORY_MAP.get( - category, constants.Category.NOT_SPECIFIED) + alerts_model['severity'] = PureStorageDriver.SEVERITY_MAP.get( + alerts.get('current_severity'), + constants.Severity.NOT_SPECIFIED) + alerts_model['category'] = PureStorageDriver.CATEGORY_MAP.get( + alerts.get('category'), constants.Category.NOT_SPECIFIED) alerts_model['occur_time'] = alerts.get('opened') alerts_model['description'] = alerts.get('event') @@ -134,156 +139,142 @@ def list_alerts(self, context, query_para=None): def list_controllers(self, context): list_controllers = [] - return_controllers = self.rest_handler.get_all_controllers() - if return_controllers: - for controllers in return_controllers: + controllers = self.rest_handler.get_controllers() + if controllers: + for controller in controllers: controllers_object = dict() - name = controllers.get('name') + name = controller.get('name') controllers_object['name'] = name - status = controllers.get('status') - controllers_object['status'] = StorageDriver. \ - CONTROLLER_STATUS_MAP.get(status, constants. - ControllerStatus.UNKNOWN) - controllers_object['soft_version'] = controllers.get('version') + controllers_object['status'] = PureStorageDriver.\ + CONTROLLER_STATUS_MAP.get(controller.get('status'), + constants.ControllerStatus. + UNKNOWN) + controllers_object['soft_version'] = controller.get('version') controllers_object['storage_id'] = self.storage_id controllers_object['id'] = name controllers_object['native_controller_id'] = name - controllers_object['location'] = "" - controllers_object['cpu_info'] = "" - controllers_object['memory_size'] = "" + controllers_object['location'] = name list_controllers.append(controllers_object) return list_controllers def list_disks(self, context): names = dict() - return_hardware = self.rest_handler.get_all_hardware() - if return_hardware: - for hardware in return_hardware: + hardware = self.rest_handler.get_hardware() + if hardware: + for hardware_value in hardware: hardware_name = dict() - hardware_name['speed'] = hardware.get('speed') - hardware_name['serial_number'] = hardware.get('serial') - hardware_name['model'] = hardware.get('model') - name = hardware.get('name') + hardware_name['speed'] = hardware_value.get('speed') + hardware_name['serial_number'] = hardware_value.get('serial') + hardware_name['model'] = hardware_value.get('model') + name = hardware_value.get('name') names[name] = hardware_name - list_disk = [] - return_disks = self.rest_handler.get_all_disk() - if return_disks: - for drive in return_disks: + list_disks = [] + disks = self.rest_handler.get_disks() + if disks: + for drive in disks: disk = dict() drive_name = drive.get('name') disk['name'] = drive_name physical_type = drive.get('type').lower() - if physical_type in constants.DiskPhysicalType.ALL: - disk['physical_type'] = physical_type - else: - disk['physical_type'] = constants.DiskPhysicalType.UNKNOWN + disk['physical_type'] = physical_type \ + if physical_type in constants.DiskPhysicalType.ALL else\ + constants.DiskPhysicalType.UNKNOWN status = drive.get('status') - disk['status'] = StorageDriver.DISK_STATUS_MAP.\ + disk['status'] = PureStorageDriver.DISK_STATUS_MAP.\ get(status, constants.DiskStatus.OFFLINE) disk['storage_id'] = self.storage_id disk['capacity'] = int(int(drive.get('capacity')) / units.Ki) - hardware_object = names.get(drive_name, {}) + hardware_object = names.get(drive_name, {}) speed = hardware_object.get('speed') - if speed is None: - disk['speed'] = '' - else: - disk['speed'] = int(speed) + disk['speed'] = int(speed) if speed is not None else None disk['model'] = hardware_object.get('model') disk['serial_number'] = hardware_object.get('serial_number') disk['native_disk_id'] = drive_name disk['id'] = drive_name disk['location'] = drive_name - disk['logical_type'] = '' - disk['native_disk_group_id'] = "" disk['manufacturer'] = "pure" disk['firmware'] = "" - disk['health_score'] = "" - list_disk.append(disk) - LOG.info("list_diskļ¼š%s" % (json.dumps(list_disk, ensure_ascii=False))) - return list_disk + list_disks.append(disk) + return list_disks def list_ports(self, context): - networks_object = dict() - self.network_object(networks_object) - list_port = [] - return_ports = self.rest_handler.get_all_port() - if return_ports: - for ports in return_ports: - port = dict() - name = ports.get('name') - wwn = ports.get('wwn') + networks = self.get_network() + list_ports = [] + ports = self.rest_handler.get_ports() + if ports: + for port in ports: + port_result = dict() + name = port.get('name') + wwn = port.get('wwn') if wwn: - port['type'] = constants.PortType.FC - port['name'] = wwn - port['id'] = wwn - port['wwn'] = wwn + port_result['type'] = constants.PortType.FC + port_result['name'] = wwn + port_result['id'] = wwn + port_result['wwn'] = wwn else: - port['type'] = constants.PortType.ETH - iqn = ports.get('iqn') - port['name'] = iqn - port['id'] = iqn - port['wwn'] = '' - port['native_port_id'] = name - port['location'] = name - port['storage_id'] = self.storage_id - network = networks_object.get(name.lower(), {}) - port['logical_type'] = network.get('logical_type') - port['speed'] = network.get('speed') - port['mac_address'] = network.get('address') - port['ipv4_mask'] = network.get('ipv4_mask') - port['connection_status '] = constants.PortConnectionStatus. \ - CONNECTED - port['health_status'] = constants.PortHealthStatus.NORMAL - port['max_speed'] = '' - port['native_parent_id'] = "" - port['ipv4'] = "" - port['ipv6'] = "" - port['ipv6_mask'] = "" - list_port.append(port) - return list_port + port_result['type'] = constants.PortType.ETH + iqn = port.get('iqn') + port_result['name'] = iqn + port_result['id'] = iqn + port_result['wwn'] = '' + port_result['native_port_id'] = name + port_result['location'] = name + port_result['storage_id'] = self.storage_id + network = networks.get(name.lower(), {}) + port_result['logical_type'] = network.get('logical_type') + port_result['speed'] = network.get('speed') + port_result['mac_address'] = network.get('address') + port_result['ipv4_mask'] = network.get('ipv4_mask') + port_result['connection_status '] = constants.\ + PortConnectionStatus.CONNECTED + port_result['health_status'] = constants.PortHealthStatus.\ + NORMAL + list_ports.append(port_result) + return list_ports - def network_object(self, networks_object): - return_network = self.rest_handler.get_all_network() - if return_network: - for network in return_network: + def get_network(self): + networks_object = dict() + networks = self.rest_handler.get_networks() + if networks: + for network in networks: network_object = dict() network_object['address'] = network.get('address') services_list = network.get('services') if services_list: - services = services_list[0] - if services in constants.PortLogicalType.ALL: - network_object['logical_type'] = services - else: - network_object['logical_type'] = "" + for services in services_list: + network_object['logical_type'] = services if \ + services in constants.PortLogicalType.ALL else None + break network_object['speed'] = int(int(network.get('speed', 0)) / units.Ki) network_object['ipv4_mask'] = network.get('netmask') name = network.get('name') networks_object[name] = network_object + return networks_object def list_storage_pools(self, context): pool_list = [] - return_pools = self.rest_handler.get_capacity_pools() - if return_pools: - for pools in return_pools: - pool_object = dict() - total_capacity = int(pools.get('size')) - pool_object['total_capacity'] = total_capacity + pools = self.rest_handler.get_capacity_pools() + if pools: + for pool in pools: + pool_result = dict() + total_capacity = int(pool.get('size')) + pool_result['total_capacity'] = total_capacity - used_capacity = int(pools.get('total_reduction')) - pool_object['used_capacity'] = used_capacity + used_capacity = int(pool.get('total_reduction')) + pool_result['used_capacity'] = used_capacity - pool_object['free_capacity'] = total_capacity - used_capacity - pool_object['name'] = pools.get('name') - pool_object['native_storage_pool_id'] = pools.get('name') - pool_object['storage_id'] = self.storage_id - pool_object['description'] = "" - pool_object['status'] = constants.StoragePoolStatus.NORMAL - pool_object['storage_type'] = constants.StorageType.BLOCK - pool_list.append(pool_object) + pool_result['free_capacity'] = total_capacity - used_capacity + pool_result['name'] = pool.get('name') + pool_result['native_storage_pool_id'] = pool.get('name') + pool_result['storage_id'] = self.storage_id + pool_result['description'] = "" + pool_result['status'] = constants.StoragePoolStatus.NORMAL + pool_result['storage_type'] = constants.StorageType.BLOCK + pool_list.append(pool_result) return pool_list def remove_trap_config(self, context, trap_config): diff --git a/delfin/drivers/pure/pure/rest_handler.py b/delfin/drivers/pure/pure/rest_handler.py index 409041b5f..0f733bae3 100644 --- a/delfin/drivers/pure/pure/rest_handler.py +++ b/delfin/drivers/pure/pure/rest_handler.py @@ -3,6 +3,7 @@ from delfin import exception, cryptor from delfin.drivers.utils.rest_client import RestClient +from delfin.drivers.pure.pure.constants import c LOG = logging.getLogger(__name__) @@ -40,48 +41,43 @@ def login(self): try: data = {'username': self.username, 'password': cryptor.decode( self.password)} - token = self.get_rest_login(RestHandler.REST_AUTH_URL, data, + token = self.get_rest_token(RestHandler.REST_AUTH_URL, data, method='POST') api_token = token.get('api_token') if api_token is None and api_token == '': raise exception.InvalidInput('api_token fail to get') - user = self.get_rest_login(RestHandler.REST_SESSION_URL, token, + user = self.get_rest_token(RestHandler.REST_SESSION_URL, token, method='POST') username = user.get('username') - if username is None and username == '': + if username is None or username == '': raise exception.InvalidInput('session fail to get') except Exception as e: LOG.error("Login error: %s", six.text_type(e)) raise exception.InvalidInput('login failure') def logout(self): - user = self.get_rest_login(RestHandler.REST_SESSION_URL, + user = self.get_rest_token(RestHandler.REST_SESSION_URL, method='DELETE') username = user.get('username') - if username is None and username == '': + if username is None or username == '': raise exception.InvalidInput('delete fail to get') - def get_all_rest_volumes(self): + def get_volumes(self): url = '%s%s:%s%s' % ( RestHandler.HTTPS, self.host, self.port, RestHandler.REST_VOLUME_URL) result_json = self.get_rest_volumes_info(url) return result_json - def get_all_rest_volumes_id(self, name): - result_json = self.get_rest_info( - '{}{}'.format(RestHandler.REST_VOLUME_ID_URL, name)) - return result_json - def get_storage(self): result_json = self.get_rest_info(RestHandler.REST_STORAGE_URL) return result_json - def get_storage_ID(self): + def get_storage_id(self): result_json = self.get_rest_info(RestHandler.REST_STORAGE_ID_URL) return result_json - def get_all_pools(self): + def get_pools(self): result_json = self.get_rest_info(RestHandler.REST_POOLS_URL) return result_json @@ -89,27 +85,27 @@ def get_capacity_pools(self): result_json = self.get_rest_info(RestHandler.REST_POOLS_CAPACITY_URL) return result_json - def get_all_port(self): + def get_ports(self): result_json = self.get_rest_info(RestHandler.REST_PORT_URL) return result_json - def get_all_network(self): + def get_networks(self): result_json = self.get_rest_info(RestHandler.REST_NETWORK_URL) return result_json - def get_all_disk(self): + def get_disks(self): result_json = self.get_rest_info(RestHandler.REST_DISK_URL) return result_json - def get_all_hardware(self): + def get_hardware(self): result_json = self.get_rest_info(RestHandler.REST_HARDWARE_URL) return result_json - def get_all_controllers(self): + def get_controllers(self): result_json = self.get_rest_info(RestHandler.REST_CONTROLLERS_URL) return result_json - def get_all_alerts(self): + def get_alerts(self): result_json = self.get_rest_info(RestHandler.REST_ALERTS_URL) return result_json @@ -123,20 +119,20 @@ def get_rest_info(self, url, data=None, method='GET'): self.get_rest_info(url, data, method) return result_json - def get_rest_login(self, url, data=None, method='GET'): + def get_rest_token(self, url, data=None, method='GET'): self.init_http_head() res = self.do_call(url, data, method) result_json = res.json() return result_json - def get_rest_volumes_info(self, url, data=None, volume_list=None): + def get_rest_volumes_info(self, url, data=None, volume_list=None, count=0): if volume_list is None: volume_list = [] res = self.do_call(url, data, 'GET') if res.status_code == 200: result_json = res.json() volume_list.extend(result_json) - next_token = res.headers._store.get('x-next-token') + next_token = res.headers.get('x-next-token') if next_token: token = next_token[1] if token: @@ -146,5 +142,7 @@ def get_rest_volumes_info(self, url, data=None, volume_list=None): self.get_rest_volumes_info(url, data, volume_list) elif res.status_code == 401: self.login() - self.get_rest_volumes_info(url, data, volume_list) + if count < 3: + count = count + 1 + self.get_rest_volumes_info(url, data, volume_list, count) return volume_list diff --git a/delfin/tests/unit/drivers/pure/storage/test_storage.py b/delfin/tests/unit/drivers/pure/storage/test_storage.py index e5541cfba..1c7200729 100644 --- a/delfin/tests/unit/drivers/pure/storage/test_storage.py +++ b/delfin/tests/unit/drivers/pure/storage/test_storage.py @@ -1,10 +1,14 @@ import sys from unittest import TestCase, mock +from oslo_log import log + +import six sys.modules['delfin.cryptor'] = mock.Mock() from delfin import context from delfin.drivers.pure.pure.rest_handler import RestHandler -from delfin.drivers.pure.pure.pure_storage import StorageDriver +from delfin.drivers.pure.pure.pure_storage import PureStorageDriver +LOG = log.getLogger(__name__) ACCESS_INFO = { "rest": { @@ -261,14 +265,14 @@ } ] reset_connection_info = { - "username": "oksd" + "username": "username" } def create_driver(): RestHandler.login = mock.Mock( - return_value={""}) - return StorageDriver(**ACCESS_INFO) + return_value={None}) + return PureStorageDriver(**ACCESS_INFO) class test_StorageDriver(TestCase): @@ -277,7 +281,7 @@ class test_StorageDriver(TestCase): def test_init(self): RestHandler.login = mock.Mock( return_value={""}) - StorageDriver(**ACCESS_INFO) + PureStorageDriver(**ACCESS_INFO) def test_list_volumes(self): RestHandler.get_rest_volumes_info = mock.Mock( @@ -330,6 +334,13 @@ def test_list_storage_pools(self): pools_info[0].get('name')) def test_reset_connection(self): - RestHandler.get_rest_login = mock.Mock( + RestHandler.get_rest_token = mock.Mock( side_effect=[reset_connection_info]) - self.driver.reset_connection(context) + name = None + try: + self.driver.reset_connection(context) + except Exception as e: + LOG.error("test_reset_connection error: %s", six.text_type(e)) + name = 'username' + self.assertNotEqual(reset_connection_info.get('username'), + name) From 5f639f21cc7aa83b1986873053d6a88d995e95cb Mon Sep 17 00:00:00 2001 From: zhilong-xu Date: Mon, 8 Nov 2021 17:16:04 +0800 Subject: [PATCH 2/2] pure codeview-Modify according to specifications --- delfin/drivers/pure/pure/consts.py | 65 ++++++ delfin/drivers/pure/pure/pure_storage.py | 216 ++++++++---------- delfin/drivers/pure/pure/rest_handler.py | 115 ++++++---- .../unit/drivers/pure/storage/test_storage.py | 33 +-- 4 files changed, 239 insertions(+), 190 deletions(-) create mode 100644 delfin/drivers/pure/pure/consts.py diff --git a/delfin/drivers/pure/pure/consts.py b/delfin/drivers/pure/pure/consts.py new file mode 100644 index 000000000..335582894 --- /dev/null +++ b/delfin/drivers/pure/pure/consts.py @@ -0,0 +1,65 @@ +# Copyright 2021 The SODA Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from delfin.common import constants + +# The default volume +DEFAULT_CAPACITY = 0 + +# The default speed +DEFAULT_SPEED = 0 + +# The default sequence for the get_volumes_info function +DEFAULT_LIST_GET_VOLUMES_INFO = 1 + +# The default count for the get_volumes_info function +DEFAULT_COUNT_GET_VOLUMES_INFO = 0 + +# Number of re-logins +RE_LOGIN_TIMES = 3 + +# Constant one +CONSTANT_ONE = 1 + +# Success status code +SUCCESS_STATUS_CODE = 200 + +# Status code of no permission +PERMISSION_DENIED_STATUS_CODE = 401 + +# Custom token of Pure +CUSTOM_TOKEN = 'x-next-token' + +SEVERITY_MAP = {'fatal': constants.Severity.FATAL, + 'critical': constants.Severity.CRITICAL, + 'major': constants.Severity.MAJOR, + 'minor': constants.Severity.MINOR, + 'warning': constants.Severity.WARNING, + 'informational': constants.Severity.INFORMATIONAL, + 'NotSpecified': constants.Severity.NOT_SPECIFIED} +CATEGORY_MAP = {'fault': constants.Category.FAULT, + 'event': constants.Category.EVENT, + 'recovery': constants.Category.RECOVERY, + 'notSpecified': constants.Category.NOT_SPECIFIED} +CONTROLLER_STATUS_MAP = {'normal': constants.ControllerStatus.NORMAL, + 'ready': constants.ControllerStatus.NORMAL, + 'offline': constants.ControllerStatus.OFFLINE, + 'fault': constants.ControllerStatus.FAULT, + 'degraded': constants.ControllerStatus.DEGRADED, + 'unknown': constants.ControllerStatus.UNKNOWN, + 'unready': constants.ControllerStatus.UNKNOWN} +DISK_STATUS_MAP = {'normal': constants.DiskStatus.NORMAL, + 'healthy': constants.DiskStatus.NORMAL, + 'abnormal': constants.DiskStatus.ABNORMAL, + 'unhealthy': constants.DiskStatus.ABNORMAL, + 'offline': constants.DiskStatus.OFFLINE} diff --git a/delfin/drivers/pure/pure/pure_storage.py b/delfin/drivers/pure/pure/pure_storage.py index c039e5120..5748b407b 100644 --- a/delfin/drivers/pure/pure/pure_storage.py +++ b/delfin/drivers/pure/pure/pure_storage.py @@ -5,35 +5,12 @@ from delfin.common import constants from delfin.drivers import driver -from delfin.drivers.pure.pure import rest_handler +from delfin.drivers.pure.pure import rest_handler, consts LOG = log.getLogger(__name__) class PureStorageDriver(driver.StorageDriver): - SEVERITY_MAP = {'fatal': constants.Severity.FATAL, - 'critical': constants.Severity.CRITICAL, - 'major': constants.Severity.MAJOR, - 'minor': constants.Severity.MINOR, - 'warning': constants.Severity.WARNING, - 'informational': constants.Severity.INFORMATIONAL, - 'NotSpecified': constants.Severity.NOT_SPECIFIED} - CATEGORY_MAP = {'fault': constants.Category.FAULT, - 'event': constants.Category.EVENT, - 'recovery': constants.Category.RECOVERY, - 'notSpecified': constants.Category.NOT_SPECIFIED} - CONTROLLER_STATUS_MAP = {'normal': constants.ControllerStatus.NORMAL, - 'ready': constants.ControllerStatus.NORMAL, - 'offline': constants.ControllerStatus.OFFLINE, - 'fault': constants.ControllerStatus.FAULT, - 'degraded': constants.ControllerStatus.DEGRADED, - 'unknown': constants.ControllerStatus.UNKNOWN, - 'unready': constants.ControllerStatus.UNKNOWN} - DISK_STATUS_MAP = {'normal': constants.DiskStatus.NORMAL, - 'healthy': constants.DiskStatus.NORMAL, - 'abnormal': constants.DiskStatus.ABNORMAL, - 'unhealthy': constants.DiskStatus.ABNORMAL, - 'offline': constants.DiskStatus.OFFLINE} def __init__(self, **kwargs): super().__init__(**kwargs) @@ -46,19 +23,19 @@ def list_volumes(self, context): if volumes: pools = self.rest_handler.get_pools() for volume in volumes: - name = volume.get('name') + volume_name = volume.get('name') total_capacity = int(int(volume.get('size')) / units.Ki) used_capacity = int(int(volume.get('volumes')) / units.Ki) native_storage_pool_id = None if pools: for pool in pools: pool_volumes = pool.get('volumes') - if name in pool_volumes: + if volume_name in pool_volumes: native_storage_pool_id = pool.get('name') break volume_dict = { - 'native_volume_id': name, - 'name': name, + 'native_volume_id': volume_name, + 'name': volume_name, 'total_capacity': total_capacity, 'used_capacity': used_capacity, 'free_capacity': total_capacity - used_capacity, @@ -77,62 +54,64 @@ def clear_alert(self, context, alert): pass def get_storage(self, context): - result_storage = self.rest_handler.get_storage() + storages = self.rest_handler.get_storages() model = None total_capacity = None used_capacity = None - if result_storage: - for storage in result_storage: + if storages: + for storage in storages: model = storage.get('hostname') total_capacity = int(int(storage.get('provisioned', - 0)) / units.Ki) - used_capacity = int(int(storage.get('volumes', 0)) / - units.Ki) + consts.DEFAULT_CAPACITY)) + / units.Ki) + used_capacity = int(int(storage.get('volumes', + consts.DEFAULT_CAPACITY)) + / units.Ki) break - storage_id = self.rest_handler.get_storage_id() - name = None + arrays = self.rest_handler.get_arrays() + storage_name = None serial_number = None version = None - if storage_id: - name = storage_id.get('array_name') - serial_number = storage_id.get('id') - version = storage_id.get('version') - storage = { + if arrays: + storage_name = arrays.get('array_name') + serial_number = arrays.get('id') + version = arrays.get('version') + storage_result = { 'model': model, 'total_capacity': total_capacity, 'raw_capacity': total_capacity, 'used_capacity': used_capacity, 'free_capacity': total_capacity - used_capacity, 'vendor': 'PURE', - 'name': name, + 'name': storage_name, 'serial_number': serial_number, 'firmware_version': version, 'status': constants.StorageStatus.NORMAL, - 'location': name + 'location': storage_name } - return storage + return storage_result def list_alerts(self, context, query_para=None): - return_alerts = self.rest_handler.get_alerts() + alerts = self.rest_handler.get_alerts() alerts_list = [] - if return_alerts: - for alerts in return_alerts: + if alerts: + for alert in alerts: alerts_model = dict() - alerts_model['alert_id'] = alerts.get('id') - alerts_model['severity'] = PureStorageDriver.SEVERITY_MAP.get( - alerts.get('current_severity'), + alerts_model['alert_id'] = alert.get('id') + alerts_model['severity'] = consts.SEVERITY_MAP.get( + alert.get('current_severity'), constants.Severity.NOT_SPECIFIED) - alerts_model['category'] = PureStorageDriver.CATEGORY_MAP.get( - alerts.get('category'), constants.Category.NOT_SPECIFIED) + alerts_model['category'] = consts.CATEGORY_MAP.get( + alert.get('category'), constants.Category.NOT_SPECIFIED) - alerts_model['occur_time'] = alerts.get('opened') - alerts_model['description'] = alerts.get('event') - alerts_model['location'] = alerts.get('component_name') + alerts_model['occur_time'] = alert.get('opened') + alerts_model['description'] = alert.get('event') + alerts_model['location'] = alert.get('component_name') alerts_model['type'] = constants.EventType.EQUIPMENT_ALARM alerts_model['resource_type'] = constants.DEFAULT_RESOURCE_TYPE - alerts_model['alert_name'] = alerts.get('id') - alerts_model['match_key'] = hashlib.md5(str(alerts.get('id')). + alerts_model['alert_name'] = alert.get('id') + alerts_model['match_key'] = hashlib.md5(str(alert.get('id')). encode()).hexdigest() alerts_list.append(alerts_model) return alerts_list @@ -142,23 +121,22 @@ def list_controllers(self, context): controllers = self.rest_handler.get_controllers() if controllers: for controller in controllers: - controllers_object = dict() - name = controller.get('name') - controllers_object['name'] = name - controllers_object['status'] = PureStorageDriver.\ - CONTROLLER_STATUS_MAP.get(controller.get('status'), - constants.ControllerStatus. - UNKNOWN) - controllers_object['soft_version'] = controller.get('version') - controllers_object['storage_id'] = self.storage_id - controllers_object['id'] = name - controllers_object['native_controller_id'] = name - controllers_object['location'] = name - list_controllers.append(controllers_object) + controllers_dict = dict() + controller_name = controller.get('name') + controllers_dict['name'] = controller_name + controllers_dict['status'] = consts.CONTROLLER_STATUS_MAP. \ + get(controller.get('status'), + constants.ControllerStatus.UNKNOWN) + controllers_dict['soft_version'] = controller.get('version') + controllers_dict['storage_id'] = self.storage_id + controllers_dict['id'] = controller_name + controllers_dict['native_controller_id'] = controller_name + controllers_dict['location'] = controller_name + list_controllers.append(controllers_dict) return list_controllers def list_disks(self, context): - names = dict() + hardware_dict = dict() hardware = self.rest_handler.get_hardware() if hardware: for hardware_value in hardware: @@ -166,38 +144,39 @@ def list_disks(self, context): hardware_name['speed'] = hardware_value.get('speed') hardware_name['serial_number'] = hardware_value.get('serial') hardware_name['model'] = hardware_value.get('model') - name = hardware_value.get('name') - names[name] = hardware_name + hardware_value_name = hardware_value.get('name') + hardware_dict[hardware_value_name] = hardware_name list_disks = [] disks = self.rest_handler.get_disks() if disks: - for drive in disks: - disk = dict() - drive_name = drive.get('name') - disk['name'] = drive_name - physical_type = drive.get('type').lower() - disk['physical_type'] = physical_type \ - if physical_type in constants.DiskPhysicalType.ALL else\ + for disk in disks: + disk_dict = dict() + drive_name = disk.get('name') + disk_dict['name'] = drive_name + physical_type = disk.get('type').lower() + disk_dict['physical_type'] = physical_type \ + if physical_type in constants.DiskPhysicalType.ALL else \ constants.DiskPhysicalType.UNKNOWN - status = drive.get('status') - disk['status'] = PureStorageDriver.DISK_STATUS_MAP.\ + status = disk.get('status') + disk_dict['status'] = consts.DISK_STATUS_MAP. \ get(status, constants.DiskStatus.OFFLINE) - disk['storage_id'] = self.storage_id - disk['capacity'] = int(int(drive.get('capacity')) / units.Ki) - - hardware_object = names.get(drive_name, {}) + disk_dict['storage_id'] = self.storage_id + disk_dict['capacity'] = int(int(disk.get('capacity')) / + units.Ki) + hardware_object = hardware_dict.get(drive_name, {}) speed = hardware_object.get('speed') - disk['speed'] = int(speed) if speed is not None else None - disk['model'] = hardware_object.get('model') - disk['serial_number'] = hardware_object.get('serial_number') + disk_dict['speed'] = int(speed) if speed is not None else None + disk_dict['model'] = hardware_object.get('model') + disk_dict['serial_number'] = hardware_object. \ + get('serial_number') - disk['native_disk_id'] = drive_name - disk['id'] = drive_name - disk['location'] = drive_name - disk['manufacturer'] = "pure" - disk['firmware'] = "" - list_disks.append(disk) + disk_dict['native_disk_id'] = drive_name + disk_dict['id'] = drive_name + disk_dict['location'] = drive_name + disk_dict['manufacturer'] = "pure" + disk_dict['firmware'] = "" + list_disks.append(disk_dict) return list_disks def list_ports(self, context): @@ -207,30 +186,26 @@ def list_ports(self, context): if ports: for port in ports: port_result = dict() - name = port.get('name') + port_name = port.get('name') wwn = port.get('wwn') if wwn: port_result['type'] = constants.PortType.FC - port_result['name'] = wwn - port_result['id'] = wwn - port_result['wwn'] = wwn else: port_result['type'] = constants.PortType.ETH - iqn = port.get('iqn') - port_result['name'] = iqn - port_result['id'] = iqn - port_result['wwn'] = '' - port_result['native_port_id'] = name - port_result['location'] = name + port_result['id'] = port_name + port_result['name'] = port_name + port_result['native_port_id'] = port_name + port_result['location'] = port_name port_result['storage_id'] = self.storage_id - network = networks.get(name.lower(), {}) + network = networks.get(port_name.lower(), {}) port_result['logical_type'] = network.get('logical_type') port_result['speed'] = network.get('speed') port_result['mac_address'] = network.get('address') port_result['ipv4_mask'] = network.get('ipv4_mask') - port_result['connection_status '] = constants.\ + port_result['wwn'] = wwn + port_result['connection_status '] = constants. \ PortConnectionStatus.CONNECTED - port_result['health_status'] = constants.PortHealthStatus.\ + port_result['health_status'] = constants.PortHealthStatus. \ NORMAL list_ports.append(port_result) return list_ports @@ -240,19 +215,20 @@ def get_network(self): networks = self.rest_handler.get_networks() if networks: for network in networks: - network_object = dict() - network_object['address'] = network.get('address') + network_dict = dict() + network_dict['address'] = network.get('address') services_list = network.get('services') if services_list: for services in services_list: - network_object['logical_type'] = services if \ + network_dict['logical_type'] = services if \ services in constants.PortLogicalType.ALL else None break - network_object['speed'] = int(int(network.get('speed', 0)) / - units.Ki) - network_object['ipv4_mask'] = network.get('netmask') - name = network.get('name') - networks_object[name] = network_object + network_dict['speed'] = int(int(network.get('speed', + consts. + DEFAULT_SPEED)) / units.Ki) + network_dict['ipv4_mask'] = network.get('netmask') + network_name = network.get('name') + networks_object[network_name] = network_dict return networks_object def list_storage_pools(self, context): @@ -261,17 +237,15 @@ def list_storage_pools(self, context): if pools: for pool in pools: pool_result = dict() - total_capacity = int(pool.get('size')) + total_capacity = int(pool.get('size', consts.DEFAULT_CAPACITY)) pool_result['total_capacity'] = total_capacity - - used_capacity = int(pool.get('total_reduction')) + used_capacity = int(pool.get('total_reduction', + consts.DEFAULT_CAPACITY)) pool_result['used_capacity'] = used_capacity - pool_result['free_capacity'] = total_capacity - used_capacity pool_result['name'] = pool.get('name') pool_result['native_storage_pool_id'] = pool.get('name') pool_result['storage_id'] = self.storage_id - pool_result['description'] = "" pool_result['status'] = constants.StoragePoolStatus.NORMAL pool_result['storage_type'] = constants.StorageType.BLOCK pool_list.append(pool_result) diff --git a/delfin/drivers/pure/pure/rest_handler.py b/delfin/drivers/pure/pure/rest_handler.py index 0f733bae3..4abc7ef22 100644 --- a/delfin/drivers/pure/pure/rest_handler.py +++ b/delfin/drivers/pure/pure/rest_handler.py @@ -2,15 +2,15 @@ from oslo_log import log as logging from delfin import exception, cryptor +from delfin.drivers.pure.pure import consts from delfin.drivers.utils.rest_client import RestClient -from delfin.drivers.pure.pure.constants import c LOG = logging.getLogger(__name__) class RestHandler(RestClient): REST_STORAGE_URL = '/api/1.17/array?space=true' - REST_STORAGE_ID_URL = '/api/1.17/array' + REST_ARRAY_URL = '/api/1.17/array' REST_VOLUME_URL = '/api/1.17/volume?space=true&limit=20&token=aWQgPSA5OD' \ 'A1Mg==' REST_VOLUME_TOKEN_URL = '/api/1.17/volume?space=true&limit=20&token=' @@ -41,108 +41,131 @@ def login(self): try: data = {'username': self.username, 'password': cryptor.decode( self.password)} - token = self.get_rest_token(RestHandler.REST_AUTH_URL, data, - method='POST') - api_token = token.get('api_token') - if api_token is None and api_token == '': - raise exception.InvalidInput('api_token fail to get') - user = self.get_rest_token(RestHandler.REST_SESSION_URL, token, + token_res = self.get_token(RestHandler.REST_AUTH_URL, data, method='POST') - username = user.get('username') - if username is None or username == '': - raise exception.InvalidInput('session fail to get') + if token_res.status_code != consts.SUCCESS_STATUS_CODE: + LOG.error("Login error.URL: %s, Reason: %s.", + RestHandler.REST_AUTH_URL, token_res.text) + raise exception.StorageBackendException(token_res.text) + else: + api_token = token_res.json().get('api_token') + if not api_token: + LOG.error("Login error. URL: %s, Reason: %s", + RestHandler.REST_AUTH_URL, + 'The API token does not exist') + raise exception.InvalidResults('The API token does not ' + 'exist') + session_res = self.get_token(RestHandler.REST_SESSION_URL, + api_token, method='POST') + if session_res.status_code == consts.SUCCESS_STATUS_CODE: + username = session_res.json().get('username') + if not username: + LOG.error("Login error. URL: %s, Reason: %s", + RestHandler.REST_SESSION_URL, + 'The API session does not exist') + raise exception.InvalidResults('The API session does ' + 'not exist') + else: + LOG.error("Login error.URL: %s, Reason: %s.", + RestHandler.REST_AUTH_URL, token_res.text) + raise exception.StorageBackendException(token_res.text) except Exception as e: LOG.error("Login error: %s", six.text_type(e)) - raise exception.InvalidInput('login failure') + raise e def logout(self): - user = self.get_rest_token(RestHandler.REST_SESSION_URL, - method='DELETE') - username = user.get('username') - if username is None or username == '': - raise exception.InvalidInput('delete fail to get') + res = self.get_token(RestHandler.REST_SESSION_URL, method='DELETE') + if res.status_code == consts.SUCCESS_STATUS_CODE: + username = res.json().get('username') + if not username: + raise exception.InvalidResults('The returned username' + ' is empty') + else: + LOG.error("Logout error.URL: %s, Reason: %s.", + RestHandler.REST_SESSION_URL, res.text) + raise exception.StorageBackendException(res.text) def get_volumes(self): url = '%s%s:%s%s' % ( RestHandler.HTTPS, self.host, self.port, RestHandler.REST_VOLUME_URL) - result_json = self.get_rest_volumes_info(url) + result_json = self.get_volumes_info(url) return result_json - def get_storage(self): - result_json = self.get_rest_info(RestHandler.REST_STORAGE_URL) + def get_storages(self): + result_json = self.get_info(RestHandler.REST_STORAGE_URL) return result_json - def get_storage_id(self): - result_json = self.get_rest_info(RestHandler.REST_STORAGE_ID_URL) + def get_arrays(self): + result_json = self.get_info(RestHandler.REST_ARRAY_URL) return result_json def get_pools(self): - result_json = self.get_rest_info(RestHandler.REST_POOLS_URL) + result_json = self.get_info(RestHandler.REST_POOLS_URL) return result_json def get_capacity_pools(self): - result_json = self.get_rest_info(RestHandler.REST_POOLS_CAPACITY_URL) + result_json = self.get_info(RestHandler.REST_POOLS_CAPACITY_URL) return result_json def get_ports(self): - result_json = self.get_rest_info(RestHandler.REST_PORT_URL) + result_json = self.get_info(RestHandler.REST_PORT_URL) return result_json def get_networks(self): - result_json = self.get_rest_info(RestHandler.REST_NETWORK_URL) + result_json = self.get_info(RestHandler.REST_NETWORK_URL) return result_json def get_disks(self): - result_json = self.get_rest_info(RestHandler.REST_DISK_URL) + result_json = self.get_info(RestHandler.REST_DISK_URL) return result_json def get_hardware(self): - result_json = self.get_rest_info(RestHandler.REST_HARDWARE_URL) + result_json = self.get_info(RestHandler.REST_HARDWARE_URL) return result_json def get_controllers(self): - result_json = self.get_rest_info(RestHandler.REST_CONTROLLERS_URL) + result_json = self.get_info(RestHandler.REST_CONTROLLERS_URL) return result_json def get_alerts(self): - result_json = self.get_rest_info(RestHandler.REST_ALERTS_URL) + result_json = self.get_info(RestHandler.REST_ALERTS_URL) return result_json - def get_rest_info(self, url, data=None, method='GET'): + def get_info(self, url, data=None, method='GET'): result_json = None res = self.do_call(url, data, method) - if res.status_code == 200: + if res.status_code == consts.SUCCESS_STATUS_CODE: result_json = res.json() - elif res.status_code == 401: + elif res.status_code == consts.PERMISSION_DENIED_STATUS_CODE: self.login() - self.get_rest_info(url, data, method) + self.get_info(url, data, method) return result_json - def get_rest_token(self, url, data=None, method='GET'): + def get_token(self, url, data=None, method='GET'): self.init_http_head() res = self.do_call(url, data, method) - result_json = res.json() - return result_json + return res - def get_rest_volumes_info(self, url, data=None, volume_list=None, count=0): + def get_volumes_info(self, url, data=None, volume_list=None, + count=consts.DEFAULT_COUNT_GET_VOLUMES_INFO): if volume_list is None: volume_list = [] res = self.do_call(url, data, 'GET') - if res.status_code == 200: + if res.status_code == consts.SUCCESS_STATUS_CODE: result_json = res.json() volume_list.extend(result_json) - next_token = res.headers.get('x-next-token') + next_token = res.headers.get(consts.CUSTOM_TOKEN) if next_token: - token = next_token[1] + token = next_token[consts.DEFAULT_LIST_GET_VOLUMES_INFO] if token: url = '%s%s:%s%s%s' % ( RestHandler.HTTPS, self.host, self.port, RestHandler.REST_VOLUME_TOKEN_URL, token) - self.get_rest_volumes_info(url, data, volume_list) - elif res.status_code == 401: + self.get_volumes_info(url, data, volume_list) + elif res.status_code == consts.PERMISSION_DENIED_STATUS_CODE: self.login() - if count < 3: - count = count + 1 - self.get_rest_volumes_info(url, data, volume_list, count) + if count < consts.RE_LOGIN_TIMES: + count = count + consts.CONSTANT_ONE + self.get_volumes_info(url, data, volume_list, count) return volume_list diff --git a/delfin/tests/unit/drivers/pure/storage/test_storage.py b/delfin/tests/unit/drivers/pure/storage/test_storage.py index 1c7200729..98665fd8c 100644 --- a/delfin/tests/unit/drivers/pure/storage/test_storage.py +++ b/delfin/tests/unit/drivers/pure/storage/test_storage.py @@ -2,8 +2,6 @@ from unittest import TestCase, mock from oslo_log import log -import six - sys.modules['delfin.cryptor'] = mock.Mock() from delfin import context from delfin.drivers.pure.pure.rest_handler import RestHandler @@ -265,7 +263,8 @@ } ] reset_connection_info = { - "username": "username" + "username": "username", + "status_code": 200 } @@ -284,63 +283,51 @@ def test_init(self): PureStorageDriver(**ACCESS_INFO) def test_list_volumes(self): - RestHandler.get_rest_volumes_info = mock.Mock( + RestHandler.get_volumes_info = mock.Mock( side_effect=[volumes_info]) - RestHandler.get_rest_info = mock.Mock( + RestHandler.get_info = mock.Mock( side_effect=[pool_info]) volume = self.driver.list_volumes(context) self.assertEqual(volume[0]['native_volume_id'], pool_info[0].get('volumes')[0]) def test_get_storage(self): - RestHandler.get_rest_info = mock.Mock( + RestHandler.get_info = mock.Mock( side_effect=[storage_info, storage_id_info]) storage_object = self.driver.get_storage(context) self.assertEqual(storage_object.get('name'), storage_id_info.get('array_name')) def test_list_alerts(self): - RestHandler.get_rest_info = mock.Mock( + RestHandler.get_info = mock.Mock( side_effect=[alerts_info]) list_alerts = self.driver.list_alerts(context) self.assertEqual(list_alerts[0].get('alert_id'), alerts_info[0].get('id')) def test_list_controllers(self): - RestHandler.get_rest_info = mock.Mock( + RestHandler.get_info = mock.Mock( side_effect=[controllers_info]) list_controllers = self.driver.list_controllers(context) self.assertEqual(list_controllers[0].get('name'), controllers_info[0].get('name')) def test_list_disks(self): - RestHandler.get_rest_info = mock.Mock( + RestHandler.get_info = mock.Mock( side_effect=[hardware_info, drive_info]) list_disks = self.driver.list_disks(context) self.assertEqual(list_disks[0].get('name'), hardware_info[0].get('name')) def test_list_ports(self): - RestHandler.get_rest_info = mock.Mock( + RestHandler.get_info = mock.Mock( side_effect=[port_network_info, port_info]) list_ports = self.driver.list_ports(context) self.assertEqual(list_ports[0].get('wwn'), port_info[0].get('wwn')) def test_list_storage_pools(self): - RestHandler.get_rest_info = mock.Mock( + RestHandler.get_info = mock.Mock( side_effect=[pools_info]) list_storage_pools = self.driver.list_storage_pools(context) self.assertEqual(list_storage_pools[0].get('native_storage_pool_id'), pools_info[0].get('name')) - - def test_reset_connection(self): - RestHandler.get_rest_token = mock.Mock( - side_effect=[reset_connection_info]) - name = None - try: - self.driver.reset_connection(context) - except Exception as e: - LOG.error("test_reset_connection error: %s", six.text_type(e)) - name = 'username' - self.assertNotEqual(reset_connection_info.get('username'), - name)