diff --git a/cinder/opts.py b/cinder/opts.py index a857b73db5b..000397f479d 100644 --- a/cinder/opts.py +++ b/cinder/opts.py @@ -138,6 +138,8 @@ from cinder.volume.drivers import linstordrv as \ from cinder.volume.drivers import lvm as cinder_volume_drivers_lvm from cinder.volume.drivers.macrosan import driver as \ cinder_volume_drivers_macrosan_driver +from cinder.volume.drivers.nec.v import nec_v_rest as \ + cinder_volume_drivers_nec_v_necvrest from cinder.volume.drivers.netapp import options as \ cinder_volume_drivers_netapp_options from cinder.volume.drivers.nexenta import options as \ @@ -353,6 +355,9 @@ def list_opts(): cinder_volume_drivers_linstordrv.linstor_opts, cinder_volume_drivers_lvm.volume_opts, cinder_volume_drivers_macrosan_driver.config.macrosan_opts, + cinder_volume_drivers_nec_v_necvrest.COMMON_VOLUME_OPTS, + cinder_volume_drivers_nec_v_necvrest.REST_VOLUME_OPTS, + cinder_volume_drivers_nec_v_necvrest.FC_VOLUME_OPTS, cinder_volume_drivers_netapp_options.netapp_proxy_opts, cinder_volume_drivers_netapp_options.netapp_connection_opts, cinder_volume_drivers_netapp_options.netapp_transport_opts, diff --git a/cinder/tests/unit/volume/drivers/nec/v/__init__.py b/cinder/tests/unit/volume/drivers/nec/v/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/cinder/tests/unit/volume/drivers/nec/v/test_nec_rest_fc.py b/cinder/tests/unit/volume/drivers/nec/v/test_nec_rest_fc.py new file mode 100644 index 00000000000..66a6c4e5e76 --- /dev/null +++ b/cinder/tests/unit/volume/drivers/nec/v/test_nec_rest_fc.py @@ -0,0 +1,383 @@ +# Copyright (C) 2021 NEC corporation +# +# 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. +# +"""Unit tests for NEC Driver.""" + +from unittest import mock + +from oslo_config import cfg +import requests + +from cinder import context as cinder_context +from cinder import db +from cinder.tests.unit import fake_volume +from cinder.tests.unit import test +from cinder.volume import configuration as conf +from cinder.volume.drivers.hitachi import hbsd_rest +from cinder.volume.drivers.hitachi import hbsd_rest_api +from cinder.volume.drivers.nec.v import nec_v_fc +from cinder.volume.drivers.nec.v import nec_v_rest +from cinder.volume import volume_utils + +# Configuration parameter values +CONFIG_MAP = { + 'serial': '886000123456', + 'my_ip': '127.0.0.1', + 'rest_server_ip_addr': '172.16.18.108', + 'rest_server_ip_port': '23451', + 'port_id': 'CL1-A', + 'host_grp_name': 'NEC-0123456789abcdef', + 'host_mode': 'LINUX/IRIX', + 'host_wwn': '0123456789abcdef', + 'target_wwn': '1111111123456789', + 'user_id': 'user', + 'user_pass': 'password', + 'pool_name': 'test_pool', + 'auth_user': 'auth_user', + 'auth_password': 'auth_password', +} + +# Dummy response +DEFAULT_CONNECTOR = { + 'host': 'host', + 'ip': CONFIG_MAP['my_ip'], + 'wwpns': [CONFIG_MAP['host_wwn']], + 'multipath': False, +} + +# Dummy response for REST API +POST_SESSIONS_RESULT = { + "token": "b74777a3-f9f0-4ea8-bd8f-09847fac48d3", + "sessionId": 0, +} + +GET_PORTS_RESULT = { + "data": [ + { + "portId": CONFIG_MAP['port_id'], + "portType": "FIBRE", + "portAttributes": [ + "TAR", + "MCU", + "RCU", + "ELUN" + ], + "fabricMode": True, + "portConnection": "PtoP", + "lunSecuritySetting": True, + "wwn": CONFIG_MAP['target_wwn'], + }, + ], +} + +GET_HOST_WWNS_RESULT = { + "data": [ + { + "hostGroupNumber": 0, + "hostWwn": CONFIG_MAP['host_wwn'], + }, + ], +} + +COMPLETED_SUCCEEDED_RESULT = { + "status": "Completed", + "state": "Succeeded", + "affectedResources": ('a/b/c/1',), +} + + +def _brick_get_connector_properties(multipath=False, enforce_multipath=False): + """Return a predefined connector object.""" + return DEFAULT_CONNECTOR + + +class FakeResponse(): + + def __init__(self, status_code, data=None, headers=None): + self.status_code = status_code + self.data = data + self.text = data + self.content = data + self.headers = {'Content-Type': 'json'} if headers is None else headers + + def json(self): + return self.data + + +class VStorageRESTFCDriverTest(test.TestCase): + """Unit test class for NEC REST interface fibre channel module.""" + + test_existing_ref = {'source-id': '1'} + test_existing_ref_name = { + 'source-name': '15960cc7-38c9-4c5b-b4f1-365be5eeed45'} + + def setUp(self): + """Set up the test environment.""" + def _set_required(opts, required): + for opt in opts: + opt.required = required + + # Initialize Cinder and avoid checking driver options. + rest_required_opts = [ + opt for opt in nec_v_rest.REST_VOLUME_OPTS if opt.required] + common_required_opts = [ + opt for opt in nec_v_rest.COMMON_VOLUME_OPTS if opt.required] + _set_required(rest_required_opts, False) + _set_required(common_required_opts, False) + super(VStorageRESTFCDriverTest, self).setUp() + _set_required(rest_required_opts, True) + _set_required(common_required_opts, True) + + self.configuration = mock.Mock(conf.Configuration) + self.ctxt = cinder_context.get_admin_context() + self._setup_config() + self._setup_driver() + + def _setup_config(self): + """Set configuration parameter values.""" + self.configuration.config_group = "REST" + + self.configuration.volume_backend_name = "RESTFC" + self.configuration.volume_driver = ( + "cinder.volume.drivers.nec.v.nec_v_fc.VStorageFCDriver") + self.configuration.reserved_percentage = "0" + self.configuration.use_multipath_for_image_xfer = False + self.configuration.enforce_multipath_for_image_xfer = False + self.configuration.max_over_subscription_ratio = 500.0 + self.configuration.driver_ssl_cert_verify = False + + self.configuration.nec_v_storage_id = CONFIG_MAP['serial'] + self.configuration.nec_v_pool = "30" + self.configuration.nec_v_snap_pool = None + self.configuration.nec_v_ldev_range = "0-1" + self.configuration.nec_v_target_ports = [CONFIG_MAP['port_id']] + self.configuration.nec_v_compute_target_ports = [ + CONFIG_MAP['port_id']] + self.configuration.nec_v_group_create = True + self.configuration.nec_v_group_delete = True + self.configuration.nec_v_copy_speed = 3 + self.configuration.nec_v_copy_check_interval = 3 + self.configuration.nec_v_async_copy_check_interval = 10 + + self.configuration.san_login = CONFIG_MAP['user_id'] + self.configuration.san_password = CONFIG_MAP['user_pass'] + self.configuration.san_ip = CONFIG_MAP[ + 'rest_server_ip_addr'] + self.configuration.san_api_port = CONFIG_MAP[ + 'rest_server_ip_port'] + self.configuration.nec_v_rest_disable_io_wait = True + self.configuration.nec_v_rest_tcp_keepalive = True + self.configuration.nec_v_discard_zero_page = True + self.configuration.nec_v_rest_number = "0" + self.configuration.nec_v_lun_timeout = hbsd_rest._LUN_TIMEOUT + self.configuration.nec_v_lun_retry_interval = ( + hbsd_rest._LUN_RETRY_INTERVAL) + self.configuration.nec_v_restore_timeout = hbsd_rest._RESTORE_TIMEOUT + self.configuration.nec_v_state_transition_timeout = ( + hbsd_rest._STATE_TRANSITION_TIMEOUT) + self.configuration.nec_v_lock_timeout = hbsd_rest_api._LOCK_TIMEOUT + self.configuration.nec_v_rest_timeout = hbsd_rest_api._REST_TIMEOUT + self.configuration.nec_v_extend_timeout = ( + hbsd_rest_api._EXTEND_TIMEOUT) + self.configuration.nec_v_exec_retry_interval = ( + hbsd_rest_api._EXEC_RETRY_INTERVAL) + self.configuration.nec_v_rest_connect_timeout = ( + hbsd_rest_api._DEFAULT_CONNECT_TIMEOUT) + self.configuration.nec_v_rest_job_api_response_timeout = ( + hbsd_rest_api._JOB_API_RESPONSE_TIMEOUT) + self.configuration.nec_v_rest_get_api_response_timeout = ( + hbsd_rest_api._GET_API_RESPONSE_TIMEOUT) + self.configuration.nec_v_rest_server_busy_timeout = ( + hbsd_rest_api._REST_SERVER_BUSY_TIMEOUT) + self.configuration.nec_v_rest_keep_session_loop_interval = ( + hbsd_rest_api._KEEP_SESSION_LOOP_INTERVAL) + self.configuration.nec_v_rest_another_ldev_mapped_retry_timeout = ( + hbsd_rest_api._ANOTHER_LDEV_MAPPED_RETRY_TIMEOUT) + self.configuration.nec_v_rest_tcp_keepidle = ( + hbsd_rest_api._TCP_KEEPIDLE) + self.configuration.nec_v_rest_tcp_keepintvl = ( + hbsd_rest_api._TCP_KEEPINTVL) + self.configuration.nec_v_rest_tcp_keepcnt = ( + hbsd_rest_api._TCP_KEEPCNT) + self.configuration.nec_v_host_mode_options = [] + + self.configuration.nec_v_zoning_request = False + + self.configuration.san_thin_provision = True + self.configuration.san_private_key = '' + self.configuration.san_clustername = '' + self.configuration.san_ssh_port = '22' + self.configuration.san_is_local = False + self.configuration.ssh_conn_timeout = '30' + self.configuration.ssh_min_pool_conn = '1' + self.configuration.ssh_max_pool_conn = '5' + + self.configuration.use_chap_auth = True + self.configuration.chap_username = CONFIG_MAP['auth_user'] + self.configuration.chap_password = CONFIG_MAP['auth_password'] + + self.configuration.safe_get = self._fake_safe_get + + CONF = cfg.CONF + CONF.my_ip = CONFIG_MAP['my_ip'] + + def _fake_safe_get(self, value): + """Retrieve a configuration value avoiding throwing an exception.""" + try: + val = getattr(self.configuration, value) + except AttributeError: + val = None + return val + + @mock.patch.object(requests.Session, "request") + @mock.patch.object( + volume_utils, 'brick_get_connector_properties', + side_effect=_brick_get_connector_properties) + def _setup_driver( + self, brick_get_connector_properties=None, request=None): + """Set up the driver environment.""" + self.driver = nec_v_fc.VStorageFCDriver( + configuration=self.configuration, db=db) + request.side_effect = [FakeResponse(200, POST_SESSIONS_RESULT), + FakeResponse(200, GET_PORTS_RESULT), + FakeResponse(200, GET_HOST_WWNS_RESULT)] + self.driver.do_setup(None) + self.driver.check_for_setup_error() + self.driver.local_path(None) + # stop the Loopingcall within the do_setup treatment + self.driver.common.client.keep_session_loop.stop() + + def tearDown(self): + self.client = None + super(VStorageRESTFCDriverTest, self).tearDown() + + # API test cases + def test_configuration(self): + drv = nec_v_fc.VStorageFCDriver( + configuration=self.configuration, db=db) + self.assertEqual(drv.configuration.hitachi_storage_id, + drv.configuration.nec_v_storage_id) + self.assertEqual(drv.configuration.hitachi_pool, + drv.configuration.nec_v_pool) + self.assertEqual(drv.configuration.hitachi_snap_pool, + drv.configuration.nec_v_snap_pool) + self.assertEqual(drv.configuration.hitachi_ldev_range, + drv.configuration.nec_v_ldev_range) + self.assertEqual(drv.configuration.hitachi_target_ports, + drv.configuration.nec_v_target_ports) + self.assertEqual(drv.configuration.hitachi_compute_target_ports, + drv.configuration.nec_v_compute_target_ports) + self.assertEqual(drv.configuration.hitachi_group_create, + drv.configuration.nec_v_group_create) + self.assertEqual(drv.configuration.hitachi_group_delete, + drv.configuration.nec_v_group_delete) + self.assertEqual(drv.configuration.hitachi_copy_speed, + drv.configuration.nec_v_copy_speed) + self.assertEqual(drv.configuration.hitachi_copy_check_interval, + drv.configuration.nec_v_copy_check_interval) + self.assertEqual(drv.configuration.hitachi_async_copy_check_interval, + drv.configuration.nec_v_async_copy_check_interval) + self.assertEqual(drv.configuration.hitachi_rest_disable_io_wait, + drv.configuration.nec_v_rest_disable_io_wait) + self.assertEqual(drv.configuration.hitachi_rest_tcp_keepalive, + drv.configuration.nec_v_rest_tcp_keepalive) + self.assertEqual(drv.configuration.hitachi_discard_zero_page, + drv.configuration.nec_v_discard_zero_page) + self.assertEqual(drv.configuration.hitachi_lun_timeout, + drv.configuration.nec_v_lun_timeout) + self.assertEqual(drv.configuration.hitachi_lun_retry_interval, + drv.configuration.nec_v_lun_retry_interval) + self.assertEqual(drv.configuration.hitachi_restore_timeout, + drv.configuration.nec_v_restore_timeout) + self.assertEqual(drv.configuration.hitachi_state_transition_timeout, + drv.configuration.nec_v_state_transition_timeout) + self.assertEqual(drv.configuration.hitachi_lock_timeout, + drv.configuration.nec_v_lock_timeout) + self.assertEqual(drv.configuration.hitachi_rest_timeout, + drv.configuration.nec_v_rest_timeout) + self.assertEqual(drv.configuration.hitachi_extend_timeout, + drv.configuration.nec_v_extend_timeout) + self.assertEqual(drv.configuration.hitachi_exec_retry_interval, + drv.configuration.nec_v_exec_retry_interval) + self.assertEqual(drv.configuration.hitachi_rest_connect_timeout, + drv.configuration.nec_v_rest_connect_timeout) + self.assertEqual( + drv.configuration.hitachi_rest_job_api_response_timeout, + drv.configuration.nec_v_rest_job_api_response_timeout) + self.assertEqual( + drv.configuration.hitachi_rest_get_api_response_timeout, + drv.configuration.nec_v_rest_get_api_response_timeout) + self.assertEqual(drv.configuration.hitachi_rest_server_busy_timeout, + drv.configuration.nec_v_rest_server_busy_timeout) + self.assertEqual( + drv.configuration.hitachi_rest_keep_session_loop_interval, + drv.configuration.nec_v_rest_keep_session_loop_interval) + self.assertEqual( + drv.configuration.hitachi_rest_another_ldev_mapped_retry_timeout, + drv.configuration.nec_v_rest_another_ldev_mapped_retry_timeout) + self.assertEqual(drv.configuration.hitachi_rest_tcp_keepidle, + drv.configuration.nec_v_rest_tcp_keepidle) + self.assertEqual(drv.configuration.hitachi_rest_tcp_keepintvl, + drv.configuration.nec_v_rest_tcp_keepintvl) + self.assertEqual(drv.configuration.hitachi_rest_tcp_keepcnt, + drv.configuration.nec_v_rest_tcp_keepcnt) + self.assertEqual(drv.configuration.hitachi_host_mode_options, + drv.configuration.nec_v_host_mode_options) + self.assertEqual(drv.configuration.hitachi_zoning_request, + drv.configuration.nec_v_zoning_request) + + def test_driverinfo(self): + drv = nec_v_fc.VStorageFCDriver( + configuration=self.configuration, db=db) + self.assertEqual(drv.common.driver_info['version'], + "1.0.0") + self.assertEqual(drv.common.driver_info['proto'], + "FC") + self.assertEqual(drv.common.driver_info['hba_id'], + "wwpns") + self.assertEqual(drv.common.driver_info['hba_id_type'], + "World Wide Name") + self.assertEqual(drv.common.driver_info['msg_id']['target'].msg_id, + 308) + self.assertEqual(drv.common.driver_info['volume_backend_name'], + "NECFC") + self.assertEqual(drv.common.driver_info['volume_type'], + "fibre_channel") + self.assertEqual(drv.common.driver_info['param_prefix'], + "nec_v") + self.assertEqual(drv.common.driver_info['vendor_name'], + "NEC") + self.assertEqual(drv.common.driver_info['driver_prefix'], + "NEC") + self.assertEqual(drv.common.driver_info['driver_file_prefix'], + "nec") + self.assertEqual(drv.common.driver_info['target_prefix'], + "NEC-") + self.assertEqual(drv.common.driver_info['hdp_vol_attr'], + "DP") + self.assertEqual(drv.common.driver_info['hdt_vol_attr'], + "DT") + self.assertEqual(drv.common.driver_info['nvol_ldev_type'], + "DP-VOL") + self.assertEqual(drv.common.driver_info['target_iqn_suffix'], + ".nec-target") + self.assertEqual(drv.common.driver_info['pair_attr'], + "SS") + + @mock.patch.object(requests.Session, "request") + def test_create_volume(self, request): + request.return_value = FakeResponse(202, COMPLETED_SUCCEEDED_RESULT) + ret = self.driver.create_volume(fake_volume.fake_volume_obj(self.ctxt)) + self.assertEqual('1', ret['provider_location']) + self.assertEqual(2, request.call_count) diff --git a/cinder/tests/unit/volume/drivers/nec/v/test_nec_rest_iscsi.py b/cinder/tests/unit/volume/drivers/nec/v/test_nec_rest_iscsi.py new file mode 100644 index 00000000000..c456bcf8136 --- /dev/null +++ b/cinder/tests/unit/volume/drivers/nec/v/test_nec_rest_iscsi.py @@ -0,0 +1,403 @@ +# Copyright (C) 2021 NEC corporation +# +# +# 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. +# +"""Unit tests for NEC Driver.""" + +from unittest import mock + +from oslo_config import cfg +import requests + +from cinder import context as cinder_context +from cinder import db +from cinder.tests.unit import fake_volume +from cinder.tests.unit import test +from cinder.volume import configuration as conf +from cinder.volume.drivers.hitachi import hbsd_rest +from cinder.volume.drivers.hitachi import hbsd_rest_api +from cinder.volume.drivers.nec.v import nec_v_iscsi +from cinder.volume.drivers.nec.v import nec_v_rest +from cinder.volume import volume_utils + +# Configuration parameter values +CONFIG_MAP = { + 'serial': '886000123456', + 'my_ip': '127.0.0.1', + 'rest_server_ip_addr': '172.16.18.108', + 'rest_server_ip_port': '23451', + 'port_id': 'CL1-A', + 'host_grp_name': 'NEC-127.0.0.1', + 'host_mode': 'LINUX/IRIX', + 'host_iscsi_name': 'iqn.nec-test-host', + 'target_iscsi_name': 'iqn.nec-test-target', + 'user_id': 'user', + 'user_pass': 'password', + 'ipv4Address': '111.22.333.44', + 'tcpPort': '5555', + 'auth_user': 'auth_user', + 'auth_password': 'auth_password', +} + +DEFAULT_CONNECTOR = { + 'host': 'host', + 'ip': CONFIG_MAP['my_ip'], + 'initiator': CONFIG_MAP['host_iscsi_name'], + 'multipath': False, +} + +# Dummy response for REST API +POST_SESSIONS_RESULT = { + "token": "b74777a3-f9f0-4ea8-bd8f-09847fac48d3", + "sessionId": 0, +} + +GET_PORTS_RESULT = { + "data": [ + { + "portId": CONFIG_MAP['port_id'], + "portType": "ISCSI", + "portAttributes": [ + "TAR", + "MCU", + "RCU", + "ELUN" + ], + "portSpeed": "AUT", + "loopId": "00", + "fabricMode": False, + "lunSecuritySetting": True, + }, + ], +} + +GET_PORT_RESULT = { + "ipv4Address": CONFIG_MAP['ipv4Address'], + "tcpPort": CONFIG_MAP['tcpPort'], +} + +GET_HOST_ISCSIS_RESULT = { + "data": [ + { + "hostGroupNumber": 0, + "iscsiName": CONFIG_MAP['host_iscsi_name'], + }, + ], +} + +GET_HOST_GROUP_RESULT = { + "hostGroupName": CONFIG_MAP['host_grp_name'], + "iscsiName": CONFIG_MAP['target_iscsi_name'], +} + +GET_HOST_GROUPS_RESULT = { + "data": [ + { + "hostGroupNumber": 0, + "portId": CONFIG_MAP['port_id'], + "hostGroupName": "NEC-test", + "iscsiName": CONFIG_MAP['target_iscsi_name'], + }, + ], +} + +COMPLETED_SUCCEEDED_RESULT = { + "status": "Completed", + "state": "Succeeded", + "affectedResources": ('a/b/c/1',), +} + + +def _brick_get_connector_properties(multipath=False, enforce_multipath=False): + """Return a predefined connector object.""" + return DEFAULT_CONNECTOR + + +class FakeResponse(): + + def __init__(self, status_code, data=None, headers=None): + self.status_code = status_code + self.data = data + self.text = data + self.content = data + self.headers = {'Content-Type': 'json'} if headers is None else headers + + def json(self): + return self.data + + +class VStorageRESTISCSIDriverTest(test.TestCase): + """Unit test class for NEC REST interface iSCSI module.""" + + test_existing_ref = {'source-id': '1'} + test_existing_ref_name = { + 'source-name': '15960cc7-38c9-4c5b-b4f1-365be5eeed45'} + + def setUp(self): + """Set up the test environment.""" + def _set_required(opts, required): + for opt in opts: + opt.required = required + + # Initialize Cinder and avoid checking driver options. + rest_required_opts = [ + opt for opt in nec_v_rest.REST_VOLUME_OPTS if opt.required] + common_required_opts = [ + opt for opt in nec_v_rest.COMMON_VOLUME_OPTS if opt.required] + _set_required(rest_required_opts, False) + _set_required(common_required_opts, False) + super(VStorageRESTISCSIDriverTest, self).setUp() + _set_required(rest_required_opts, True) + _set_required(common_required_opts, True) + + self.configuration = mock.Mock(conf.Configuration) + self.ctxt = cinder_context.get_admin_context() + self._setup_config() + self._setup_driver() + + def _setup_config(self): + """Set configuration parameter values.""" + self.configuration.config_group = "REST" + + self.configuration.volume_backend_name = "RESTISCSI" + self.configuration.volume_driver = ( + "cinder.volume.drivers.nec.v.nec_v_iscsi.VStorageISCSIDriver") + self.configuration.reserved_percentage = "0" + self.configuration.use_multipath_for_image_xfer = False + self.configuration.enforce_multipath_for_image_xfer = False + self.configuration.max_over_subscription_ratio = 500.0 + self.configuration.driver_ssl_cert_verify = False + + self.configuration.nec_v_storage_id = CONFIG_MAP['serial'] + self.configuration.nec_v_pool = "30" + self.configuration.nec_v_snap_pool = None + self.configuration.nec_v_ldev_range = "0-1" + self.configuration.nec_v_target_ports = [CONFIG_MAP['port_id']] + self.configuration.nec_v_compute_target_ports = [ + CONFIG_MAP['port_id']] + self.configuration.nec_v_group_create = True + self.configuration.nec_v_group_delete = True + self.configuration.nec_v_copy_speed = 3 + self.configuration.nec_v_copy_check_interval = 3 + self.configuration.nec_v_async_copy_check_interval = 10 + + self.configuration.san_login = CONFIG_MAP['user_id'] + self.configuration.san_password = CONFIG_MAP['user_pass'] + self.configuration.san_ip = CONFIG_MAP[ + 'rest_server_ip_addr'] + self.configuration.san_api_port = CONFIG_MAP[ + 'rest_server_ip_port'] + self.configuration.nec_v_rest_disable_io_wait = True + self.configuration.nec_v_rest_tcp_keepalive = True + self.configuration.nec_v_discard_zero_page = True + self.configuration.nec_v_rest_number = "0" + self.configuration.nec_v_lun_timeout = hbsd_rest._LUN_TIMEOUT + self.configuration.nec_v_lun_retry_interval = ( + hbsd_rest._LUN_RETRY_INTERVAL) + self.configuration.nec_v_restore_timeout = hbsd_rest._RESTORE_TIMEOUT + self.configuration.nec_v_state_transition_timeout = ( + hbsd_rest._STATE_TRANSITION_TIMEOUT) + self.configuration.nec_v_lock_timeout = hbsd_rest_api._LOCK_TIMEOUT + self.configuration.nec_v_rest_timeout = hbsd_rest_api._REST_TIMEOUT + self.configuration.nec_v_extend_timeout = ( + hbsd_rest_api._EXTEND_TIMEOUT) + self.configuration.nec_v_exec_retry_interval = ( + hbsd_rest_api._EXEC_RETRY_INTERVAL) + self.configuration.nec_v_rest_connect_timeout = ( + hbsd_rest_api._DEFAULT_CONNECT_TIMEOUT) + self.configuration.nec_v_rest_job_api_response_timeout = ( + hbsd_rest_api._JOB_API_RESPONSE_TIMEOUT) + self.configuration.nec_v_rest_get_api_response_timeout = ( + hbsd_rest_api._GET_API_RESPONSE_TIMEOUT) + self.configuration.nec_v_rest_server_busy_timeout = ( + hbsd_rest_api._REST_SERVER_BUSY_TIMEOUT) + self.configuration.nec_v_rest_keep_session_loop_interval = ( + hbsd_rest_api._KEEP_SESSION_LOOP_INTERVAL) + self.configuration.nec_v_rest_another_ldev_mapped_retry_timeout = ( + hbsd_rest_api._ANOTHER_LDEV_MAPPED_RETRY_TIMEOUT) + self.configuration.nec_v_rest_tcp_keepidle = ( + hbsd_rest_api._TCP_KEEPIDLE) + self.configuration.nec_v_rest_tcp_keepintvl = ( + hbsd_rest_api._TCP_KEEPINTVL) + self.configuration.nec_v_rest_tcp_keepcnt = ( + hbsd_rest_api._TCP_KEEPCNT) + self.configuration.nec_v_host_mode_options = [] + + self.configuration.use_chap_auth = True + self.configuration.chap_username = CONFIG_MAP['auth_user'] + self.configuration.chap_password = CONFIG_MAP['auth_password'] + + self.configuration.san_thin_provision = True + self.configuration.san_private_key = '' + self.configuration.san_clustername = '' + self.configuration.san_ssh_port = '22' + self.configuration.san_is_local = False + self.configuration.ssh_conn_timeout = '30' + self.configuration.ssh_min_pool_conn = '1' + self.configuration.ssh_max_pool_conn = '5' + + self.configuration.safe_get = self._fake_safe_get + + CONF = cfg.CONF + CONF.my_ip = CONFIG_MAP['my_ip'] + + def _fake_safe_get(self, value): + """Retrieve a configuration value avoiding throwing an exception.""" + try: + val = getattr(self.configuration, value) + except AttributeError: + val = None + return val + + @mock.patch.object(requests.Session, "request") + @mock.patch.object( + volume_utils, 'brick_get_connector_properties', + side_effect=_brick_get_connector_properties) + def _setup_driver( + self, brick_get_connector_properties=None, request=None): + """Set up the driver environment.""" + self.driver = nec_v_iscsi.VStorageISCSIDriver( + configuration=self.configuration, db=db) + request.side_effect = [FakeResponse(200, POST_SESSIONS_RESULT), + FakeResponse(200, GET_PORTS_RESULT), + FakeResponse(200, GET_PORT_RESULT), + FakeResponse(200, GET_HOST_ISCSIS_RESULT), + FakeResponse(200, GET_HOST_GROUP_RESULT)] + self.driver.do_setup(None) + self.driver.check_for_setup_error() + self.driver.local_path(None) + # stop the Loopingcall within the do_setup treatment + self.driver.common.client.keep_session_loop.stop() + + def tearDown(self): + self.client = None + super(VStorageRESTISCSIDriverTest, self).tearDown() + + # API test cases + def test_configuration(self): + drv = nec_v_iscsi.VStorageISCSIDriver( + configuration=self.configuration, db=db) + self.assertEqual(drv.configuration.hitachi_storage_id, + drv.configuration.nec_v_storage_id) + self.assertEqual(drv.configuration.hitachi_pool, + drv.configuration.nec_v_pool) + self.assertEqual(drv.configuration.hitachi_snap_pool, + drv.configuration.nec_v_snap_pool) + self.assertEqual(drv.configuration.hitachi_ldev_range, + drv.configuration.nec_v_ldev_range) + self.assertEqual(drv.configuration.hitachi_target_ports, + drv.configuration.nec_v_target_ports) + self.assertEqual(drv.configuration.hitachi_compute_target_ports, + drv.configuration.nec_v_compute_target_ports) + self.assertEqual(drv.configuration.hitachi_group_create, + drv.configuration.nec_v_group_create) + self.assertEqual(drv.configuration.hitachi_group_delete, + drv.configuration.nec_v_group_delete) + self.assertEqual(drv.configuration.hitachi_copy_speed, + drv.configuration.nec_v_copy_speed) + self.assertEqual(drv.configuration.hitachi_copy_check_interval, + drv.configuration.nec_v_copy_check_interval) + self.assertEqual(drv.configuration.hitachi_async_copy_check_interval, + drv.configuration.nec_v_async_copy_check_interval) + self.assertEqual(drv.configuration.hitachi_rest_disable_io_wait, + drv.configuration.nec_v_rest_disable_io_wait) + self.assertEqual(drv.configuration.hitachi_rest_tcp_keepalive, + drv.configuration.nec_v_rest_tcp_keepalive) + self.assertEqual(drv.configuration.hitachi_discard_zero_page, + drv.configuration.nec_v_discard_zero_page) + self.assertEqual(drv.configuration.hitachi_lun_timeout, + drv.configuration.nec_v_lun_timeout) + self.assertEqual(drv.configuration.hitachi_lun_retry_interval, + drv.configuration.nec_v_lun_retry_interval) + self.assertEqual(drv.configuration.hitachi_restore_timeout, + drv.configuration.nec_v_restore_timeout) + self.assertEqual(drv.configuration.hitachi_state_transition_timeout, + drv.configuration.nec_v_state_transition_timeout) + self.assertEqual(drv.configuration.hitachi_lock_timeout, + drv.configuration.nec_v_lock_timeout) + self.assertEqual(drv.configuration.hitachi_rest_timeout, + drv.configuration.nec_v_rest_timeout) + self.assertEqual(drv.configuration.hitachi_extend_timeout, + drv.configuration.nec_v_extend_timeout) + self.assertEqual(drv.configuration.hitachi_exec_retry_interval, + drv.configuration.nec_v_exec_retry_interval) + self.assertEqual(drv.configuration.hitachi_rest_connect_timeout, + drv.configuration.nec_v_rest_connect_timeout) + self.assertEqual( + drv.configuration.hitachi_rest_job_api_response_timeout, + drv.configuration.nec_v_rest_job_api_response_timeout) + self.assertEqual( + drv.configuration.hitachi_rest_get_api_response_timeout, + drv.configuration.nec_v_rest_get_api_response_timeout) + self.assertEqual(drv.configuration.hitachi_rest_server_busy_timeout, + drv.configuration.nec_v_rest_server_busy_timeout) + self.assertEqual( + drv.configuration.hitachi_rest_keep_session_loop_interval, + drv.configuration.nec_v_rest_keep_session_loop_interval) + self.assertEqual( + drv.configuration.hitachi_rest_another_ldev_mapped_retry_timeout, + drv.configuration.nec_v_rest_another_ldev_mapped_retry_timeout) + self.assertEqual(drv.configuration.hitachi_rest_tcp_keepidle, + drv.configuration.nec_v_rest_tcp_keepidle) + self.assertEqual(drv.configuration.hitachi_rest_tcp_keepintvl, + drv.configuration.nec_v_rest_tcp_keepintvl) + self.assertEqual(drv.configuration.hitachi_rest_tcp_keepcnt, + drv.configuration.nec_v_rest_tcp_keepcnt) + self.assertEqual(drv.configuration.hitachi_host_mode_options, + drv.configuration.nec_v_host_mode_options) + + def test_driverinfo(self): + drv = nec_v_iscsi.VStorageISCSIDriver( + configuration=self.configuration, db=db) + self.assertEqual(drv.common.driver_info['version'], + "1.0.0") + self.assertEqual(drv.common.driver_info['proto'], + "iSCSI") + self.assertEqual(drv.common.driver_info['hba_id'], + "initiator") + self.assertEqual(drv.common.driver_info['hba_id_type'], + "iSCSI initiator IQN") + self.assertEqual(drv.common.driver_info['msg_id']['target'].msg_id, + 309) + self.assertEqual(drv.common.driver_info['volume_backend_name'], + "NECiSCSI") + self.assertEqual(drv.common.driver_info['volume_type'], + "iscsi") + self.assertEqual(drv.common.driver_info['param_prefix'], + "nec_v") + self.assertEqual(drv.common.driver_info['vendor_name'], + "NEC") + self.assertEqual(drv.common.driver_info['driver_prefix'], + "NEC") + self.assertEqual(drv.common.driver_info['driver_file_prefix'], + "nec") + self.assertEqual(drv.common.driver_info['target_prefix'], + "NEC-") + self.assertEqual(drv.common.driver_info['hdp_vol_attr'], + "DP") + self.assertEqual(drv.common.driver_info['hdt_vol_attr'], + "DT") + self.assertEqual(drv.common.driver_info['nvol_ldev_type'], + "DP-VOL") + self.assertEqual(drv.common.driver_info['target_iqn_suffix'], + ".nec-target") + self.assertEqual(drv.common.driver_info['pair_attr'], + "SS") + + @mock.patch.object(requests.Session, "request") + def test_create_volume(self, request): + request.return_value = FakeResponse(202, COMPLETED_SUCCEEDED_RESULT) + ret = self.driver.create_volume(fake_volume.fake_volume_obj(self.ctxt)) + self.assertEqual('1', ret['provider_location']) + self.assertEqual(2, request.call_count) diff --git a/cinder/volume/drivers/nec/v/__init__.py b/cinder/volume/drivers/nec/v/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/cinder/volume/drivers/nec/v/nec_v_fc.py b/cinder/volume/drivers/nec/v/nec_v_fc.py new file mode 100644 index 00000000000..7a7affd267e --- /dev/null +++ b/cinder/volume/drivers/nec/v/nec_v_fc.py @@ -0,0 +1,72 @@ +# Copyright (C) 2021 NEC corporation +# +# 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. +# +"""Fibre channel module for NEC Driver.""" + +from cinder import interface +from cinder.volume import driver +from cinder.volume.drivers.hitachi import hbsd_common +from cinder.volume.drivers.hitachi import hbsd_fc +from cinder.volume.drivers.hitachi import hbsd_rest +from cinder.volume.drivers.hitachi import hbsd_utils +from cinder.volume.drivers.nec.v import nec_v_rest as rest +from cinder.volume.drivers.nec.v import nec_v_utils as utils + +MSG = hbsd_utils.HBSDMsg + + +@interface.volumedriver +class VStorageFCDriver(hbsd_fc.HBSDFCDriver): + """Fibre channel class for NEC Driver. + + Version history: + + .. code-block:: none + + 1.0.0 - Initial driver. + + """ + + VERSION = utils.VERSION + + # ThirdPartySystems wiki page + CI_WIKI_NAME = utils.CI_WIKI_NAME + + def __init__(self, *args, **kwargs): + """Initialize instance variables.""" + super(VStorageFCDriver, self).__init__(*args, **kwargs) + self.configuration.append_config_values(rest.COMMON_VOLUME_OPTS) + self.configuration.append_config_values(rest.FC_VOLUME_OPTS) + + def _init_common(self, conf, db): + utils.DRIVER_INFO['proto'] = 'FC' + utils.DRIVER_INFO['hba_id'] = 'wwpns' + utils.DRIVER_INFO['hba_id_type'] = 'World Wide Name' + utils.DRIVER_INFO['msg_id'] = { + 'target': MSG.CREATE_HOST_GROUP_FAILED} + utils.DRIVER_INFO['volume_backend_name'] = '%(prefix)sFC' % { + 'prefix': utils.DRIVER_PREFIX} + utils.DRIVER_INFO['volume_type'] = 'fibre_channel' + + return rest.VStorageRESTFC(conf, utils.DRIVER_INFO, db) + + @staticmethod + def get_driver_options(): + additional_opts = driver.BaseVD._get_oslo_driver_opts( + *(hbsd_common._INHERITED_VOLUME_OPTS + + hbsd_rest._REQUIRED_REST_OPTS + + ['driver_ssl_cert_verify', 'driver_ssl_cert_path', + 'san_api_port'])) + return (rest.COMMON_VOLUME_OPTS + rest.REST_VOLUME_OPTS + + rest.FC_VOLUME_OPTS + additional_opts) diff --git a/cinder/volume/drivers/nec/v/nec_v_iscsi.py b/cinder/volume/drivers/nec/v/nec_v_iscsi.py new file mode 100644 index 00000000000..9a9a2e36cc3 --- /dev/null +++ b/cinder/volume/drivers/nec/v/nec_v_iscsi.py @@ -0,0 +1,71 @@ +# Copyright (C) 2021 NEC corporation +# +# 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. +# +"""iSCSI channel module for NEC Driver.""" + +from cinder import interface +from cinder.volume import driver +from cinder.volume.drivers.hitachi import hbsd_common +from cinder.volume.drivers.hitachi import hbsd_iscsi +from cinder.volume.drivers.hitachi import hbsd_rest +from cinder.volume.drivers.hitachi import hbsd_utils +from cinder.volume.drivers.nec.v import nec_v_rest as rest +from cinder.volume.drivers.nec.v import nec_v_utils as utils + +MSG = hbsd_utils.HBSDMsg + + +@interface.volumedriver +class VStorageISCSIDriver(hbsd_iscsi.HBSDISCSIDriver): + """iSCSI class for NEC Driver. + + Version history: + + .. code-block:: none + + 1.0.0 - Initial driver. + + """ + + VERSION = utils.VERSION + + # ThirdPartySystems wiki page + CI_WIKI_NAME = utils.CI_WIKI_NAME + + def __init__(self, *args, **kwargs): + """Initialize instance variables.""" + super(VStorageISCSIDriver, self).__init__(*args, **kwargs) + self.configuration.append_config_values(rest.COMMON_VOLUME_OPTS) + + def _init_common(self, conf, db): + utils.DRIVER_INFO['proto'] = 'iSCSI' + utils.DRIVER_INFO['hba_id'] = 'initiator' + utils.DRIVER_INFO['hba_id_type'] = 'iSCSI initiator IQN' + utils.DRIVER_INFO['msg_id'] = { + 'target': MSG.CREATE_ISCSI_TARGET_FAILED} + utils.DRIVER_INFO['volume_backend_name'] = '%(prefix)siSCSI' % { + 'prefix': utils.DRIVER_PREFIX} + utils.DRIVER_INFO['volume_type'] = 'iscsi' + + return rest.VStorageRESTISCSI(conf, utils.DRIVER_INFO, db) + + @staticmethod + def get_driver_options(): + additional_opts = driver.BaseVD._get_oslo_driver_opts( + *(hbsd_common._INHERITED_VOLUME_OPTS + + hbsd_rest._REQUIRED_REST_OPTS + + ['driver_ssl_cert_verify', 'driver_ssl_cert_path', + 'san_api_port'])) + return (rest.COMMON_VOLUME_OPTS + rest.REST_VOLUME_OPTS + + additional_opts) diff --git a/cinder/volume/drivers/nec/v/nec_v_rest.py b/cinder/volume/drivers/nec/v/nec_v_rest.py new file mode 100644 index 00000000000..2fd317bb462 --- /dev/null +++ b/cinder/volume/drivers/nec/v/nec_v_rest.py @@ -0,0 +1,279 @@ +# Copyright (C) 2021 NEC corporation +# +# 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. +# +"""REST interface for NEC Driver.""" + +from oslo_config import cfg + +from cinder.volume import configuration +from cinder.volume.drivers.hitachi import hbsd_rest +from cinder.volume.drivers.hitachi import hbsd_rest_api +from cinder.volume.drivers.hitachi import hbsd_rest_fc +from cinder.volume.drivers.hitachi import hbsd_rest_iscsi + +COMMON_VOLUME_OPTS = [ + cfg.StrOpt( + 'nec_v_storage_id', + default=None, + help='Product number of the storage system.'), + cfg.StrOpt( + 'nec_v_pool', + default=None, + help='Pool number or pool name of the DP pool.'), + cfg.StrOpt( + 'nec_v_snap_pool', + default=None, + help='Pool number or pool name of the snapshot pool.'), + cfg.StrOpt( + 'nec_v_ldev_range', + default=None, + help='Range of the LDEV numbers in the format of \'xxxx-yyyy\' that ' + 'can be used by the driver. Values can be in decimal format ' + '(e.g. 1000) or in colon-separated hexadecimal format ' + '(e.g. 00:03:E8).'), + cfg.ListOpt( + 'nec_v_target_ports', + default=[], + help='IDs of the storage ports used to attach volumes to the ' + 'controller node. To specify multiple ports, connect them by ' + 'commas (e.g. CL1-A,CL2-A).'), + cfg.ListOpt( + 'nec_v_compute_target_ports', + default=[], + help='IDs of the storage ports used to attach volumes to compute ' + 'nodes. To specify multiple ports, connect them by commas ' + '(e.g. CL1-A,CL2-A).'), + cfg.BoolOpt( + 'nec_v_group_create', + default=False, + help='If True, the driver will create host groups or iSCSI targets on ' + 'storage ports as needed.'), + cfg.BoolOpt( + 'nec_v_group_delete', + default=False, + help='If True, the driver will delete host groups or iSCSI targets on ' + 'storage ports as needed.'), + cfg.IntOpt( + 'nec_v_copy_speed', + default=3, + min=1, max=15, + help='Copy speed of storage system. 1 or 2 indicates ' + 'low speed, 3 indicates middle speed, and a value between 4 and ' + '15 indicates high speed.'), + cfg.IntOpt( + 'nec_v_copy_check_interval', + default=3, + min=1, max=600, + help='Interval in seconds to check copying status during a volume ' + 'copy.'), + cfg.IntOpt( + 'nec_v_async_copy_check_interval', + default=10, + min=1, max=600, + help='Interval in seconds to check asynchronous copying status during ' + 'a copy pair deletion or data restoration.'), +] + +REST_VOLUME_OPTS = [ + cfg.BoolOpt( + 'nec_v_rest_disable_io_wait', + default=True, + help='It may take some time to detach volume after I/O. ' + 'This option will allow detaching volume to complete ' + 'immediately.'), + cfg.BoolOpt( + 'nec_v_rest_tcp_keepalive', + default=True, + help='Enables or disables use of REST API tcp keepalive'), + cfg.BoolOpt( + 'nec_v_discard_zero_page', + default=True, + help='Enable or disable zero page reclamation in a DP-VOL.'), + cfg.IntOpt( + 'nec_v_lun_timeout', + default=hbsd_rest._LUN_TIMEOUT, + help='Maximum wait time in seconds for adding a LUN to complete.'), + cfg.IntOpt( + 'nec_v_lun_retry_interval', + default=hbsd_rest._LUN_RETRY_INTERVAL, + help='Retry interval in seconds for REST API adding a LUN.'), + cfg.IntOpt( + 'nec_v_restore_timeout', + default=hbsd_rest._RESTORE_TIMEOUT, + help='Maximum wait time in seconds for the restore operation to ' + 'complete.'), + cfg.IntOpt( + 'nec_v_state_transition_timeout', + default=hbsd_rest._STATE_TRANSITION_TIMEOUT, + help='Maximum wait time in seconds for a volume transition to ' + 'complete.'), + cfg.IntOpt( + 'nec_v_lock_timeout', + default=hbsd_rest_api._LOCK_TIMEOUT, + help='Maximum wait time in seconds for storage to be unlocked.'), + cfg.IntOpt( + 'nec_v_rest_timeout', + default=hbsd_rest_api._REST_TIMEOUT, + help='Maximum wait time in seconds for REST API execution to ' + 'complete.'), + cfg.IntOpt( + 'nec_v_extend_timeout', + default=hbsd_rest_api._EXTEND_TIMEOUT, + help='Maximum wait time in seconds for a volume extention to ' + 'complete.'), + cfg.IntOpt( + 'nec_v_exec_retry_interval', + default=hbsd_rest_api._EXEC_RETRY_INTERVAL, + help='Retry interval in seconds for REST API execution.'), + cfg.IntOpt( + 'nec_v_rest_connect_timeout', + default=hbsd_rest_api._DEFAULT_CONNECT_TIMEOUT, + help='Maximum wait time in seconds for REST API connection to ' + 'complete.'), + cfg.IntOpt( + 'nec_v_rest_job_api_response_timeout', + default=hbsd_rest_api._JOB_API_RESPONSE_TIMEOUT, + help='Maximum wait time in seconds for a response from REST API.'), + cfg.IntOpt( + 'nec_v_rest_get_api_response_timeout', + default=hbsd_rest_api._GET_API_RESPONSE_TIMEOUT, + help='Maximum wait time in seconds for a response against GET method ' + 'of REST API.'), + cfg.IntOpt( + 'nec_v_rest_server_busy_timeout', + default=hbsd_rest_api._REST_SERVER_BUSY_TIMEOUT, + help='Maximum wait time in seconds when REST API returns busy.'), + cfg.IntOpt( + 'nec_v_rest_keep_session_loop_interval', + default=hbsd_rest_api._KEEP_SESSION_LOOP_INTERVAL, + help='Loop interval in seconds for keeping REST API session.'), + cfg.IntOpt( + 'nec_v_rest_another_ldev_mapped_retry_timeout', + default=hbsd_rest_api._ANOTHER_LDEV_MAPPED_RETRY_TIMEOUT, + help='Retry time in seconds when new LUN allocation request fails.'), + cfg.IntOpt( + 'nec_v_rest_tcp_keepidle', + default=hbsd_rest_api._TCP_KEEPIDLE, + help='Wait time in seconds for sending a first TCP keepalive packet.'), + cfg.IntOpt( + 'nec_v_rest_tcp_keepintvl', + default=hbsd_rest_api._TCP_KEEPINTVL, + help='Interval of transmissions in seconds for TCP keepalive packet.'), + cfg.IntOpt( + 'nec_v_rest_tcp_keepcnt', + default=hbsd_rest_api._TCP_KEEPCNT, + help='Maximum number of transmissions for TCP keepalive packet.'), + cfg.ListOpt( + 'nec_v_host_mode_options', + default=[], + help='Host mode option for host group or iSCSI target'), +] + +FC_VOLUME_OPTS = [ + cfg.BoolOpt( + 'nec_v_zoning_request', + default=False, + help='If True, the driver will configure FC zoning between the server ' + 'and the storage system provided that FC zoning manager is ' + 'enabled.'), +] + +CONF = cfg.CONF +CONF.register_opts(COMMON_VOLUME_OPTS, group=configuration.SHARED_CONF_GROUP) +CONF.register_opts(REST_VOLUME_OPTS, group=configuration.SHARED_CONF_GROUP) +CONF.register_opts(FC_VOLUME_OPTS, group=configuration.SHARED_CONF_GROUP) + + +def update_conf(conf): + # COMMON_VOLUME_OPTS + conf.hitachi_storage_id = conf.nec_v_storage_id + conf.hitachi_pool = conf.nec_v_pool + conf.hitachi_snap_pool = conf.nec_v_snap_pool + conf.hitachi_ldev_range = conf.nec_v_ldev_range + conf.hitachi_target_ports = conf.nec_v_target_ports + conf.hitachi_compute_target_ports = ( + conf.nec_v_compute_target_ports) + conf.hitachi_group_create = conf.nec_v_group_create + conf.hitachi_group_delete = conf.nec_v_group_delete + conf.hitachi_copy_speed = conf.nec_v_copy_speed + conf.hitachi_copy_check_interval = ( + conf.nec_v_copy_check_interval) + conf.hitachi_async_copy_check_interval = ( + conf.nec_v_async_copy_check_interval) + + # REST_VOLUME_OPTS + conf.hitachi_rest_disable_io_wait = ( + conf.nec_v_rest_disable_io_wait) + conf.hitachi_rest_tcp_keepalive = ( + conf.nec_v_rest_tcp_keepalive) + conf.hitachi_discard_zero_page = ( + conf.nec_v_discard_zero_page) + conf.hitachi_lun_timeout = conf.nec_v_lun_timeout + conf.hitachi_lun_retry_interval = ( + conf.nec_v_lun_retry_interval) + conf.hitachi_restore_timeout = conf.nec_v_restore_timeout + conf.hitachi_state_transition_timeout = ( + conf.nec_v_state_transition_timeout) + conf.hitachi_lock_timeout = conf.nec_v_lock_timeout + conf.hitachi_rest_timeout = conf.nec_v_rest_timeout + conf.hitachi_extend_timeout = conf.nec_v_extend_timeout + conf.hitachi_exec_retry_interval = ( + conf.nec_v_exec_retry_interval) + conf.hitachi_rest_connect_timeout = ( + conf.nec_v_rest_connect_timeout) + conf.hitachi_rest_job_api_response_timeout = ( + conf.nec_v_rest_job_api_response_timeout) + conf.hitachi_rest_get_api_response_timeout = ( + conf.nec_v_rest_get_api_response_timeout) + conf.hitachi_rest_server_busy_timeout = ( + conf.nec_v_rest_server_busy_timeout) + conf.hitachi_rest_keep_session_loop_interval = ( + conf.nec_v_rest_keep_session_loop_interval) + conf.hitachi_rest_another_ldev_mapped_retry_timeout = ( + conf.nec_v_rest_another_ldev_mapped_retry_timeout) + conf.hitachi_rest_tcp_keepidle = ( + conf.nec_v_rest_tcp_keepidle) + conf.hitachi_rest_tcp_keepintvl = ( + conf.nec_v_rest_tcp_keepintvl) + conf.hitachi_rest_tcp_keepcnt = ( + conf.nec_v_rest_tcp_keepcnt) + conf.hitachi_host_mode_options = ( + conf.nec_v_host_mode_options) + + return conf + + +class VStorageRESTFC(hbsd_rest_fc.HBSDRESTFC): + """REST interface fibre channel class.""" + + def __init__(self, conf, storage_protocol, db): + """Initialize instance variables.""" + conf.append_config_values(COMMON_VOLUME_OPTS) + conf.append_config_values(REST_VOLUME_OPTS) + conf.append_config_values(FC_VOLUME_OPTS) + super(VStorageRESTFC, self).__init__(conf, storage_protocol, db) + self.conf = update_conf(self.conf) + # FC_VOLUME_OPTS + self.conf.hitachi_zoning_request = self.conf.nec_v_zoning_request + + +class VStorageRESTISCSI(hbsd_rest_iscsi.HBSDRESTISCSI): + """REST interface iSCSI channel class.""" + + def __init__(self, conf, storage_protocol, db): + """Initialize instance variables.""" + conf.append_config_values(COMMON_VOLUME_OPTS) + conf.append_config_values(REST_VOLUME_OPTS) + super(VStorageRESTISCSI, self).__init__(conf, storage_protocol, db) + self.conf = update_conf(self.conf) diff --git a/cinder/volume/drivers/nec/v/nec_v_utils.py b/cinder/volume/drivers/nec/v/nec_v_utils.py new file mode 100644 index 00000000000..f12e2a20ad8 --- /dev/null +++ b/cinder/volume/drivers/nec/v/nec_v_utils.py @@ -0,0 +1,50 @@ +# Copyright (C) 2021 NEC corporation +# +# 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. +# +"""Utility module for NEC Driver.""" + +VERSION = '1.0.0' +CI_WIKI_NAME = 'NEC_V_Cinder_CI' +PARAM_PREFIX = 'nec_v' +VENDOR_NAME = 'NEC' +DRIVER_PREFIX = 'NEC' +DRIVER_FILE_PREFIX = 'nec' +TARGET_PREFIX = 'NEC-' +HDP_VOL_ATTR = 'DP' +HDT_VOL_ATTR = 'DT' +NVOL_LDEV_TYPE = 'DP-VOL' +TARGET_IQN_SUFFIX = '.nec-target' +PAIR_ATTR = 'SS' + +DRIVER_INFO = { + 'version': VERSION, + 'proto': '', + 'hba_id': '', + 'hba_id_type': '', + 'msg_id': { + 'target': '', + }, + 'volume_backend_name': '', + 'volume_type': '', + 'param_prefix': PARAM_PREFIX, + 'vendor_name': VENDOR_NAME, + 'driver_prefix': DRIVER_PREFIX, + 'driver_file_prefix': DRIVER_FILE_PREFIX, + 'target_prefix': TARGET_PREFIX, + 'hdp_vol_attr': HDP_VOL_ATTR, + 'hdt_vol_attr': HDT_VOL_ATTR, + 'nvol_ldev_type': NVOL_LDEV_TYPE, + 'target_iqn_suffix': TARGET_IQN_SUFFIX, + 'pair_attr': PAIR_ATTR, +} diff --git a/doc/source/configuration/block-storage/drivers/nec-storage-v-series-driver.rst b/doc/source/configuration/block-storage/drivers/nec-storage-v-series-driver.rst new file mode 100644 index 00000000000..72c514e3c6f --- /dev/null +++ b/doc/source/configuration/block-storage/drivers/nec-storage-v-series-driver.rst @@ -0,0 +1,139 @@ +=========================== +NEC Storage V series driver +=========================== + +NEC Storage V series driver provides Fibre Channel and iSCSI support for +NEC V series storages. + +System requirements +~~~~~~~~~~~~~~~~~~~ +Supported models: + ++-----------------+------------------------+ +| Storage model | Firmware version | ++=================+========================+ +| V100, | 93-04-21 or later | +| V300 | | ++-----------------+------------------------+ + +Required storage licenses: + +* iStorage Local Replication + Local Replication Software + + +Supported operations +~~~~~~~~~~~~~~~~~~~~ + +* Create, delete, attach, and detach volumes. +* Create, list, and delete volume snapshots. +* Create a volume from a snapshot. +* Create, list, update, and delete consistency groups. +* Create, list, and delete consistency group snapshots. +* Copy a volume to an image. +* Copy an image to a volume. +* Clone a volume. +* Extend a volume. +* Migrate a volume. +* Get volume statistics. +* Efficient non-disruptive volume backup. +* Manage and unmanage a volume. +* Attach a volume to multiple instances at once (multi-attach). +* Revert a volume to a snapshot. + +.. note:: + + A volume with snapshots cannot be extended in this driver. + +Configuration +~~~~~~~~~~~~~ +Set up NEC V series storage +--------------------------- + +You need to specify settings as described below for storage systems. For +details about each setting, see the user's guide of the storage systems. + +Common resources: + +- ``All resources`` + All storage resources, such as DP pools and host groups, can not have a + name including blank space in order for the driver to use them. + +- ``User accounts`` + Create a storage device account belonging to the Administrator User Group. + +- ``DP Pool`` + Create a DP pool that is used by the driver. + +- ``Resource group`` + If using a new resource group for exclusive use by an OpenStack system, + create a new resource group, and assign the necessary resources, such as + LDEVs, port, and host group (iSCSI target) to the created resource. + +- ``Ports`` + Enable Port Security for the ports used by the driver. + +If you use iSCSI: + +- ``Ports`` + Assign an IP address and a TCP port number to the port. + +Set up NEC V series storage volume driver +----------------------------------------- + +Set the volume driver to NEC V series storage driver by setting the +volume_driver option in the cinder.conf file as follows: + +If you use Fibre Channel: + +.. code-block:: ini + + [Storage1] + volume_driver = cinder.volume.drivers.nec.v.nec_v_fc.VStorageFCDriver + volume_backend_name = Storage1 + san_ip = 1.2.3.4 + san_api_port = 23451 + san_login = userid + san_password = password + nec_v_storage_id = 123456789012 + nec_v_pool = pool0 + +If you use iSCSI: + +.. code-block:: ini + + [Storage1] + volume_driver = cinder.volume.drivers.nec.v.nec_v_iscsi.VStorageISCSIDriver + volume_backend_name = Storage1 + san_ip = 1.2.3.4 + san_api_port = 23451 + san_login = userid + san_password = password + nec_v_storage_id = 123456789012 + nec_v_pool = pool0 + +This table shows configuration options for NEC V series storage driver. + +.. config-table:: + :config-target: NEC V series storage driver + + cinder.volume.drivers.nec.v.nec_v_rest + +Required options +---------------- + +- ``san_ip`` + IP address of SAN controller + +- ``san_login`` + Username for SAN controller + +- ``san_password`` + Password for SAN controller + +- ``nec_v_storage_id`` + Product number of the storage system. + +- ``nec_v_pool`` + Pool number or pool name of the DP pool. + diff --git a/doc/source/reference/support-matrix.ini b/doc/source/reference/support-matrix.ini index cb7c5d08218..27497a05ab7 100644 --- a/doc/source/reference/support-matrix.ini +++ b/doc/source/reference/support-matrix.ini @@ -135,6 +135,9 @@ title=MacroSAN Storage Driver (iSCSI, FC) [driver.nec] title=NEC Storage M Series Driver (iSCSI, FC) +[driver.nec_v] +title=NEC Storage V Series Driver (iSCSI, FC) + [driver.netapp_ontap] title=NetApp Data ONTAP Driver (iSCSI, NFS, FC) @@ -257,6 +260,7 @@ driver.linbit_linstor=complete driver.lvm=complete driver.macrosan=complete driver.nec=complete +driver.nec_v=complete driver.netapp_ontap=complete driver.netapp_solidfire=complete driver.nexenta=complete @@ -327,6 +331,7 @@ driver.linbit_linstor=complete driver.lvm=complete driver.macrosan=complete driver.nec=complete +driver.nec_v=complete driver.netapp_ontap=complete driver.netapp_solidfire=complete driver.nexenta=complete @@ -400,6 +405,7 @@ driver.linbit_linstor=missing driver.lvm=missing driver.macrosan=complete driver.nec=complete +driver.nec_v=missing driver.netapp_ontap=complete driver.netapp_solidfire=complete driver.nexenta=missing @@ -472,6 +478,7 @@ driver.linbit_linstor=missing driver.lvm=missing driver.macrosan=complete driver.nec=missing +driver.nec_v=missing driver.netapp_ontap=complete driver.netapp_solidfire=complete driver.nexenta=missing @@ -545,6 +552,7 @@ driver.linbit_linstor=missing driver.lvm=missing driver.macrosan=missing driver.nec=missing +driver.nec_v=complete driver.netapp_ontap=complete driver.netapp_solidfire=complete driver.nexenta=missing @@ -617,6 +625,7 @@ driver.linbit_linstor=missing driver.lvm=complete driver.macrosan=complete driver.nec=complete +driver.nec_v=complete driver.netapp_ontap=complete driver.netapp_solidfire=complete driver.nexenta=missing @@ -690,6 +699,7 @@ driver.linbit_linstor=missing driver.lvm=missing driver.macrosan=complete driver.nec=complete +driver.nec_v=missing driver.netapp_ontap=complete driver.netapp_solidfire=complete driver.nexenta=missing @@ -763,6 +773,7 @@ driver.linbit_linstor=missing driver.lvm=complete driver.macrosan=missing driver.nec=complete +driver.nec_v=complete driver.netapp_ontap=complete driver.netapp_solidfire=complete driver.nexenta=missing @@ -833,6 +844,7 @@ driver.linbit_linstor=missing driver.lvm=complete driver.macrosan=missing driver.nec=complete +driver.nec_v=complete driver.netapp_ontap=complete driver.netapp_solidfire=complete driver.nexenta=missing @@ -907,6 +919,7 @@ driver.linbit_linstor=missing driver.lvm=missing driver.macrosan=complete driver.nec=missing +driver.nec_v=missing driver.netapp_ontap=missing driver.netapp_solidfire=complete driver.nexenta=missing diff --git a/releasenotes/notes/nec_v_storage_volume_driver-e3cb7e3c496ab066.yaml b/releasenotes/notes/nec_v_storage_volume_driver-e3cb7e3c496ab066.yaml new file mode 100644 index 00000000000..a0951e5fb07 --- /dev/null +++ b/releasenotes/notes/nec_v_storage_volume_driver-e3cb7e3c496ab066.yaml @@ -0,0 +1,4 @@ +--- +features: + - | + Added backend FC and iSCSI drivers for NEC V series Storage.