From e18f05e735900acc12a7beac2ac8eca9a425e55a Mon Sep 17 00:00:00 2001 From: Chris M Date: Wed, 17 Jul 2019 05:45:48 +0000 Subject: [PATCH] Create Seagate driver from dothill driver This patch creates a new 'supported' driver for Seagate (STX) FC and iSCSI arrays by renaming and re-enabling the old 'unsupported' dothill driver. Other than marking the driver as 'supported', this patch contains no changes in functionality except for multiattach fixes from change I47f02729437cabab92ccc553a4c60d0c0a796952 needed to pass CI and deprecation of vendor-specific options requested by the core team. Other drivers which referenced the dothill driver are modified to use the Seagate class names, so users of those drivers will not be affected except for option-deprecation warnings. Change-Id: I3115ae296ae6b5702c7a8fa39249b8735542e17e --- cinder/opts.py | 4 + .../{test_dothill.py => test_seagate.py} | 266 +++++++++--------- cinder/volume/drivers/lenovo/lenovo_client.py | 4 +- cinder/volume/drivers/lenovo/lenovo_common.py | 31 +- cinder/volume/drivers/lenovo/lenovo_fc.py | 12 +- cinder/volume/drivers/lenovo/lenovo_iscsi.py | 11 +- cinder/volume/drivers/san/hp/hpmsa_client.py | 4 +- cinder/volume/drivers/san/hp/hpmsa_common.py | 31 +- cinder/volume/drivers/san/hp/hpmsa_fc.py | 14 +- cinder/volume/drivers/san/hp/hpmsa_iscsi.py | 14 +- .../drivers/{dothill => stx}/__init__.py | 0 .../dothill_client.py => stx/client.py} | 67 +++-- .../dothill_common.py => stx/common.py} | 130 +++++---- .../drivers/{dothill => stx}/exception.py | 16 +- .../{dothill/dothill_fc.py => stx/fc.py} | 35 +-- .../dothill_iscsi.py => stx/iscsi.py} | 41 +-- .../block-storage/drivers/hp-msa-driver.rst | 66 +++-- .../block-storage/drivers/lenovo-driver.rst | 46 +-- .../block-storage/drivers/seagate-driver.rst | 181 ++++++++++++ doc/source/reference/support-matrix.ini | 14 + ...driver-updates-train-4fcbe71f3e2bb2da.yaml | 29 ++ ...driver-updates-train-f2ff96ca4a2885db.yaml | 29 ++ .../seagate-new-driver-d420fad549e9045f.yaml | 3 + 23 files changed, 696 insertions(+), 352 deletions(-) rename cinder/tests/unit/volume/drivers/{test_dothill.py => test_seagate.py} (80%) rename cinder/volume/drivers/{dothill => stx}/__init__.py (100%) rename cinder/volume/drivers/{dothill/dothill_client.py => stx/client.py} (92%) rename cinder/volume/drivers/{dothill/dothill_common.py => stx/common.py} (83%) rename cinder/volume/drivers/{dothill => stx}/exception.py (64%) rename cinder/volume/drivers/{dothill/dothill_fc.py => stx/fc.py} (87%) rename cinder/volume/drivers/{dothill/dothill_iscsi.py => stx/iscsi.py} (85%) create mode 100644 doc/source/configuration/block-storage/drivers/seagate-driver.rst create mode 100644 releasenotes/notes/hpmsa-driver-updates-train-4fcbe71f3e2bb2da.yaml create mode 100644 releasenotes/notes/lenovo-driver-updates-train-f2ff96ca4a2885db.yaml create mode 100644 releasenotes/notes/seagate-new-driver-d420fad549e9045f.yaml diff --git a/cinder/opts.py b/cinder/opts.py index f2b4bc552bb..6fbc39cf9a4 100644 --- a/cinder/opts.py +++ b/cinder/opts.py @@ -149,6 +149,8 @@ from cinder.volume.drivers.san import san as cinder_volume_drivers_san_san from cinder.volume.drivers import sheepdog as cinder_volume_drivers_sheepdog from cinder.volume.drivers import solidfire as cinder_volume_drivers_solidfire from cinder.volume.drivers import storpool as cinder_volume_drivers_storpool +from cinder.volume.drivers.stx import common as \ + cinder_volume_drivers_stx_common from cinder.volume.drivers.synology import synology_common as \ cinder_volume_drivers_synology_synologycommon from cinder.volume.drivers.veritas_access import veritas_iscsi as \ @@ -357,6 +359,8 @@ def list_opts(): cinder_volume_drivers_san_san.san_opts, cinder_volume_drivers_sheepdog.sheepdog_opts, cinder_volume_drivers_solidfire.sf_opts, + cinder_volume_drivers_stx_common.common_opts, + cinder_volume_drivers_stx_common.iscsi_opts, cinder_volume_drivers_synology_synologycommon.cinder_opts, cinder_volume_drivers_vmware_vmdk.vmdk_opts, cinder_volume_drivers_vzstorage.vzstorage_opts, diff --git a/cinder/tests/unit/volume/drivers/test_dothill.py b/cinder/tests/unit/volume/drivers/test_seagate.py similarity index 80% rename from cinder/tests/unit/volume/drivers/test_dothill.py rename to cinder/tests/unit/volume/drivers/test_seagate.py index 02cabe12887..726f88d9e3d 100644 --- a/cinder/tests/unit/volume/drivers/test_dothill.py +++ b/cinder/tests/unit/volume/drivers/test_seagate.py @@ -1,6 +1,6 @@ # Copyright 2014 Objectif Libre # Copyright 2015 DotHill Systems -# Copyright 2016 Seagate Technology or one of its affiliates +# Copyright 2016-19 Seagate Technology or one of its affiliates # # 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 @@ -14,22 +14,32 @@ # License for the specific language governing permissions and limitations # under the License. # -"""Unit tests for OpenStack Cinder DotHill driver.""" - -from defusedxml import lxml as etree -import mock -import requests +"""Unit tests for OpenStack Cinder Seagate driver.""" from cinder import exception -from cinder.objects import fields from cinder import test -from cinder.volume.drivers.dothill import dothill_client as dothill -from cinder.volume.drivers.dothill import dothill_common -from cinder.volume.drivers.dothill import dothill_fc -from cinder.volume.drivers.dothill import dothill_iscsi -from cinder.volume.drivers.dothill import exception as dh_exception + +from cinder.objects import fields + +import cinder.volume.drivers.stx.client +import cinder.volume.drivers.stx.common +import cinder.volume.drivers.stx.exception as stx_exception +import cinder.volume.drivers.stx.fc +import cinder.volume.drivers.stx.iscsi + from cinder.zonemanager import utils as fczm_utils +from defusedxml import lxml as etree + +import mock + +import requests + +STXClient = cinder.volume.drivers.stx.client.STXClient +STXCommon = cinder.volume.drivers.stx.common.STXCommon +STXFCDriver = cinder.volume.drivers.stx.fc.STXFCDriver +STXISCSIDriver = cinder.volume.drivers.stx.iscsi.STXISCSIDriver + session_key = '12a1626754554a21d85040760c81b' resp_login = ''' success @@ -119,7 +129,7 @@ test_retype_volume = {'attach_status': fields.VolumeAttachStatus.DETACHED, 'display_name': 'test volume', 'name': 'volume', 'size': 10} test_host = {'capabilities': {'location_info': - 'DotHillVolumeDriver:xxxxx:dg02:A'}} + 'SeagateVolumeDriver:xxxxx:dg02:A'}} test_snap = {'id': 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 'volume': {'name_id': None}, 'volume_id': vol_id, 'display_name': 'test volume', @@ -159,16 +169,16 @@ invalid_connector = {'ip': '10.0.0.2', 'host': 'fakehost'} -class TestDotHillClient(test.TestCase): +class TestSeagateClient(test.TestCase): def setUp(self): - super(TestDotHillClient, self).setUp() + super(TestSeagateClient, self).setUp() self.login = 'manage' self.passwd = '!manage' self.ip = '10.0.0.1' self.protocol = 'http' self.ssl_verify = False - self.client = dothill.DotHillClient(self.ip, self.login, self.passwd, - self.protocol, self.ssl_verify) + self.client = STXClient(self.ip, self.login, self.passwd, + self.protocol, self.ssl_verify) @mock.patch('requests.get') def test_login(self, mock_requests_get): @@ -176,7 +186,7 @@ class TestDotHillClient(test.TestCase): mock_requests_get.return_value = m m.text.encode.side_effect = [resp_badlogin, resp_badlogin] - self.assertRaises(dh_exception.DotHillAuthenticationError, + self.assertRaises(stx_exception.AuthenticationError, self.client.login) m.text.encode.side_effect = [resp_login, resp_fw, resp_system] @@ -209,10 +219,10 @@ class TestDotHillClient(test.TestCase): mock_requests_get.return_value = m ret = self.client._api_request('/path') self.assertTrue(type(ret) == etree.RestrictedElement) - self.assertRaises(dh_exception.DotHillConnectionError, + self.assertRaises(stx_exception.ConnectionError, self.client._api_request, '/path') - self.assertRaises(dh_exception.DotHillConnectionError, + self.assertRaises(stx_exception.ConnectionError, self.client._api_request, '/path') @@ -222,22 +232,22 @@ class TestDotHillClient(test.TestCase): invalid_tree = etree.XML(invalid_xml) ret = self.client._assert_response_ok(ok_tree) self.assertIsNone(ret) - self.assertRaises(dh_exception.DotHillRequestError, + self.assertRaises(stx_exception.RequestError, self.client._assert_response_ok, not_ok_tree) - self.assertRaises(dh_exception.DotHillRequestError, + self.assertRaises(stx_exception.RequestError, self.client._assert_response_ok, invalid_tree) - @mock.patch.object(dothill.DotHillClient, '_request') + @mock.patch.object(STXClient, '_request') def test_backend_exists(self, mock_request): - mock_request.side_effect = [dh_exception.DotHillRequestError, + mock_request.side_effect = [stx_exception.RequestError, fake_xml] self.assertFalse(self.client.backend_exists('backend_name', 'linear')) self.assertTrue(self.client.backend_exists('backend_name', 'linear')) - @mock.patch.object(dothill.DotHillClient, '_request') + @mock.patch.object(STXClient, '_request') def test_backend_stats(self, mock_request): stats = {'free_capacity_gb': 1979, 'total_capacity_gb': 1979} @@ -250,7 +260,7 @@ class TestDotHillClient(test.TestCase): self.assertEqual(stats, self.client.backend_stats('A', 'virtual')) - @mock.patch.object(dothill.DotHillClient, '_request') + @mock.patch.object(STXClient, '_request') def test_get_lun(self, mock_request): mock_request.side_effect = [etree.XML(response_no_lun), etree.XML(response_lun)] @@ -259,7 +269,7 @@ class TestDotHillClient(test.TestCase): ret = self.client._get_first_available_lun_for_host("fakehost") self.assertEqual(2, ret) - @mock.patch.object(dothill.DotHillClient, '_request') + @mock.patch.object(STXClient, '_request') def test_get_ports(self, mock_request): mock_request.side_effect = [etree.XML(response_ports)] ret = self.client.get_active_target_ports() @@ -273,19 +283,19 @@ class TestDotHillClient(test.TestCase): 'target-id': 'id5', 'status': 'Up'}], ret) - @mock.patch.object(dothill.DotHillClient, '_request') + @mock.patch.object(STXClient, '_request') def test_get_fc_ports(self, mock_request): mock_request.side_effect = [etree.XML(response_ports)] ret = self.client.get_active_fc_target_ports() self.assertEqual(['id2'], ret) - @mock.patch.object(dothill.DotHillClient, '_request') + @mock.patch.object(STXClient, '_request') def test_get_iscsi_iqns(self, mock_request): mock_request.side_effect = [etree.XML(response_ports)] ret = self.client.get_active_iscsi_target_iqns() self.assertEqual(['id4', 'id5'], ret) - @mock.patch.object(dothill.DotHillClient, '_request') + @mock.patch.object(STXClient, '_request') def test_get_iscsi_portals(self, mock_request): portals = {'10.0.0.12': 'Up', '10.0.0.11': 'Up'} mock_request.side_effect = [etree.XML(response_ports_linear), @@ -295,7 +305,7 @@ class TestDotHillClient(test.TestCase): ret = self.client.get_active_iscsi_target_portals() self.assertEqual(portals, ret) - @mock.patch.object(dothill.DotHillClient, '_request') + @mock.patch.object(STXClient, '_request') def test_delete_snapshot(self, mock_request): mock_request.side_effect = [None, None] self.client.delete_snapshot('dummy', 'linear') @@ -303,7 +313,7 @@ class TestDotHillClient(test.TestCase): self.client.delete_snapshot('dummy', 'paged') mock_request.assert_called_with('/delete/snapshot', 'dummy') - @mock.patch.object(dothill.DotHillClient, '_request') + @mock.patch.object(STXClient, '_request') def test_list_luns_for_host(self, mock_request): mock_request.side_effect = [etree.XML(response_no_lun), etree.XML(response_lun)] @@ -316,42 +326,44 @@ class TestDotHillClient(test.TestCase): class FakeConfiguration1(object): - dothill_backend_name = 'OpenStack' - dothill_backend_type = 'linear' + seagate_pool_name = 'OpenStack' + seagate_pool_type = 'linear' san_ip = '10.0.0.1' san_login = 'manage' san_password = '!manage' - dothill_api_protocol = 'http' + seagate_api_protocol = 'http' + driver_use_ssl = True + driver_ssl_cert_verify = False def safe_get(self, key): return 'fakevalue' class FakeConfiguration2(FakeConfiguration1): - dothill_iscsi_ips = ['10.0.0.11'] + seagate_iscsi_ips = ['10.0.0.11'] use_chap_auth = None -class TestFCDotHillCommon(test.TestCase): +class TestFCSeagateCommon(test.TestCase): def setUp(self): - super(TestFCDotHillCommon, self).setUp() + super(TestFCSeagateCommon, self).setUp() self.config = FakeConfiguration1() - self.common = dothill_common.DotHillCommon(self.config) + self.common = STXCommon(self.config) self.common.client_login = mock.MagicMock() self.common.client_logout = mock.MagicMock() self.common.serialNumber = "xxxxx" self.common.owner = "A" self.connector_element = "wwpns" - @mock.patch.object(dothill.DotHillClient, 'get_serial_number') - @mock.patch.object(dothill.DotHillClient, 'get_owner_info') - @mock.patch.object(dothill.DotHillClient, 'backend_exists') + @mock.patch.object(STXClient, 'get_serial_number') + @mock.patch.object(STXClient, 'get_owner_info') + @mock.patch.object(STXClient, 'backend_exists') def test_do_setup(self, mock_backend_exists, mock_owner_info, mock_serial_number): mock_backend_exists.side_effect = [False, True] mock_owner_info.return_value = "A" mock_serial_number.return_value = "xxxxx" - self.assertRaises(dh_exception.DotHillInvalidBackend, + self.assertRaises(stx_exception.InvalidBackend, self.common.do_setup, None) self.assertIsNone(self.common.do_setup(None)) mock_backend_exists.assert_called_with(self.common.backend_name, @@ -387,9 +399,9 @@ class TestFCDotHillCommon(test.TestCase): connector, self.connector_element)) - @mock.patch.object(dothill.DotHillClient, 'backend_stats') + @mock.patch.object(STXClient, 'backend_stats') def test_update_volume_stats(self, mock_stats): - mock_stats.side_effect = [dh_exception.DotHillRequestError, + mock_stats.side_effect = [stx_exception.RequestError, stats_large_space] self.assertRaises(exception.Invalid, self.common._update_volume_stats) @@ -403,16 +415,16 @@ class TestFCDotHillCommon(test.TestCase): 'multiattach': True, 'free_capacity_gb': 90, 'location_info': - 'DotHillVolumeDriver:xxxxx:OpenStack:A', + 'SeagateVolumeDriver:xxxxx:OpenStack:A', 'pool_name': 'OpenStack', 'total_capacity_gb': 100}], 'storage_protocol': None, - 'vendor_name': 'DotHill', + 'vendor_name': 'Seagate', 'volume_backend_name': None}, self.common.stats) - @mock.patch.object(dothill.DotHillClient, 'create_volume') + @mock.patch.object(STXClient, 'create_volume') def test_create_volume(self, mock_create): - mock_create.side_effect = [dh_exception.DotHillRequestError, None] + mock_create.side_effect = [stx_exception.RequestError, None] self.assertRaises(exception.Invalid, self.common.create_volume, test_volume) @@ -423,12 +435,12 @@ class TestFCDotHillCommon(test.TestCase): self.common.backend_name, self.common.backend_type) - @mock.patch.object(dothill.DotHillClient, 'delete_volume') + @mock.patch.object(STXClient, 'delete_volume') def test_delete_volume(self, mock_delete): - not_found_e = dh_exception.DotHillRequestError( + not_found_e = stx_exception.RequestError( 'The volume was not found on this system.') mock_delete.side_effect = [not_found_e, - dh_exception.DotHillRequestError, + stx_exception.RequestError, None] self.assertIsNone(self.common.delete_volume(test_volume)) self.assertRaises(exception.Invalid, self.common.delete_volume, @@ -436,19 +448,19 @@ class TestFCDotHillCommon(test.TestCase): self.assertIsNone(self.common.delete_volume(test_volume)) mock_delete.assert_called_with(encoded_volid) - @mock.patch.object(dothill.DotHillClient, 'copy_volume') - @mock.patch.object(dothill.DotHillClient, 'backend_stats') + @mock.patch.object(STXClient, 'copy_volume') + @mock.patch.object(STXClient, 'backend_stats') def test_create_cloned_volume(self, mock_stats, mock_copy): mock_stats.side_effect = [stats_low_space, stats_large_space, stats_large_space] self.assertRaises( - dh_exception.DotHillNotEnoughSpace, + stx_exception.NotEnoughSpace, self.common.create_cloned_volume, dest_volume, detached_volume) self.assertFalse(mock_copy.called) - mock_copy.side_effect = [dh_exception.DotHillRequestError, None] + mock_copy.side_effect = [stx_exception.RequestError, None] self.assertRaises(exception.Invalid, self.common.create_cloned_volume, dest_volume, detached_volume) @@ -461,20 +473,20 @@ class TestFCDotHillCommon(test.TestCase): self.common.backend_name, self.common.backend_type) - @mock.patch.object(dothill.DotHillClient, 'copy_volume') - @mock.patch.object(dothill.DotHillClient, 'backend_stats') - @mock.patch.object(dothill_common.DotHillCommon, 'extend_volume') + @mock.patch.object(STXClient, 'copy_volume') + @mock.patch.object(STXClient, 'backend_stats') + @mock.patch.object(STXCommon, 'extend_volume') def test_create_cloned_volume_larger(self, mock_extend, mock_stats, mock_copy): mock_stats.side_effect = [stats_low_space, stats_large_space, stats_large_space] - self.assertRaises(dh_exception.DotHillNotEnoughSpace, + self.assertRaises(stx_exception.NotEnoughSpace, self.common.create_cloned_volume, dest_volume_larger, detached_volume) self.assertFalse(mock_copy.called) - mock_copy.side_effect = [dh_exception.DotHillRequestError, None] + mock_copy.side_effect = [stx_exception.RequestError, None] self.assertRaises(exception.Invalid, self.common.create_cloned_volume, dest_volume_larger, detached_volume) @@ -489,20 +501,20 @@ class TestFCDotHillCommon(test.TestCase): mock_extend.assert_called_once_with(dest_volume_larger, dest_volume_larger['size']) - @mock.patch.object(dothill.DotHillClient, 'get_volume_size') - @mock.patch.object(dothill.DotHillClient, 'extend_volume') - @mock.patch.object(dothill.DotHillClient, 'copy_volume') - @mock.patch.object(dothill.DotHillClient, 'backend_stats') + @mock.patch.object(STXClient, 'get_volume_size') + @mock.patch.object(STXClient, 'extend_volume') + @mock.patch.object(STXClient, 'copy_volume') + @mock.patch.object(STXClient, 'backend_stats') def test_create_volume_from_snapshot(self, mock_stats, mock_copy, mock_extend, mock_get_size): mock_stats.side_effect = [stats_low_space, stats_large_space, stats_large_space] - self.assertRaises(dh_exception.DotHillNotEnoughSpace, + self.assertRaises(stx_exception.NotEnoughSpace, self.common.create_volume_from_snapshot, dest_volume, test_snap) - mock_copy.side_effect = [dh_exception.DotHillRequestError, None] + mock_copy.side_effect = [stx_exception.RequestError, None] mock_get_size.return_value = test_snap['volume_size'] self.assertRaises(exception.Invalid, self.common.create_volume_from_snapshot, @@ -517,10 +529,10 @@ class TestFCDotHillCommon(test.TestCase): self.common.backend_type) mock_extend.assert_called_with('vqqqqqqqqqqqqqqqqqqq', '10GiB') - @mock.patch.object(dothill.DotHillClient, 'get_volume_size') - @mock.patch.object(dothill.DotHillClient, 'extend_volume') + @mock.patch.object(STXClient, 'get_volume_size') + @mock.patch.object(STXClient, 'extend_volume') def test_extend_volume(self, mock_extend, mock_size): - mock_extend.side_effect = [dh_exception.DotHillRequestError, None] + mock_extend.side_effect = [stx_exception.RequestError, None] mock_size.side_effect = [10, 10] self.assertRaises(exception.Invalid, self.common.extend_volume, test_volume, 20) @@ -528,9 +540,9 @@ class TestFCDotHillCommon(test.TestCase): self.assertIsNone(ret) mock_extend.assert_called_with(encoded_volid, '10GiB') - @mock.patch.object(dothill.DotHillClient, 'create_snapshot') + @mock.patch.object(STXClient, 'create_snapshot') def test_create_snapshot(self, mock_create): - mock_create.side_effect = [dh_exception.DotHillRequestError, None] + mock_create.side_effect = [stx_exception.RequestError, None] self.assertRaises(exception.Invalid, self.common.create_snapshot, test_snap) @@ -538,12 +550,12 @@ class TestFCDotHillCommon(test.TestCase): self.assertIsNone(ret) mock_create.assert_called_with(encoded_volid, 'sqqqqqqqqqqqqqqqqqqq') - @mock.patch.object(dothill.DotHillClient, 'delete_snapshot') + @mock.patch.object(STXClient, 'delete_snapshot') def test_delete_snapshot(self, mock_delete): - not_found_e = dh_exception.DotHillRequestError( + not_found_e = stx_exception.RequestError( 'The volume was not found on this system.') mock_delete.side_effect = [not_found_e, - dh_exception.DotHillRequestError, + stx_exception.RequestError, None] self.assertIsNone(self.common.delete_snapshot(test_snap)) @@ -553,9 +565,9 @@ class TestFCDotHillCommon(test.TestCase): mock_delete.assert_called_with('sqqqqqqqqqqqqqqqqqqq', self.common.backend_type) - @mock.patch.object(dothill.DotHillClient, 'map_volume') + @mock.patch.object(STXClient, 'map_volume') def test_map_volume(self, mock_map): - mock_map.side_effect = [dh_exception.DotHillRequestError, 10] + mock_map.side_effect = [stx_exception.RequestError, 10] self.assertRaises(exception.Invalid, self.common.map_volume, test_volume, connector, self.connector_element) @@ -565,9 +577,9 @@ class TestFCDotHillCommon(test.TestCase): mock_map.assert_called_with(encoded_volid, connector, self.connector_element) - @mock.patch.object(dothill.DotHillClient, 'unmap_volume') + @mock.patch.object(STXClient, 'unmap_volume') def test_unmap_volume(self, mock_unmap): - mock_unmap.side_effect = [dh_exception.DotHillRequestError, None] + mock_unmap.side_effect = [stx_exception.RequestError, None] self.assertRaises(exception.Invalid, self.common.unmap_volume, test_volume, connector, self.connector_element) @@ -577,11 +589,11 @@ class TestFCDotHillCommon(test.TestCase): mock_unmap.assert_called_with(encoded_volid, connector, self.connector_element) - @mock.patch.object(dothill.DotHillClient, 'copy_volume') - @mock.patch.object(dothill.DotHillClient, 'delete_volume') - @mock.patch.object(dothill.DotHillClient, 'modify_volume_name') + @mock.patch.object(STXClient, 'copy_volume') + @mock.patch.object(STXClient, 'delete_volume') + @mock.patch.object(STXClient, 'modify_volume_name') def test_retype(self, mock_modify, mock_delete, mock_copy): - mock_copy.side_effect = [dh_exception.DotHillRequestError, None] + mock_copy.side_effect = [stx_exception.RequestError, None] self.assertRaises(exception.Invalid, self.common.migrate_volume, test_retype_volume, test_host) ret = self.common.migrate_volume(test_retype_volume, test_host) @@ -590,20 +602,20 @@ class TestFCDotHillCommon(test.TestCase): {'capabilities': {}}) self.assertEqual((False, None), ret) - @mock.patch.object(dothill_common.DotHillCommon, '_get_vol_name') - @mock.patch.object(dothill.DotHillClient, 'modify_volume_name') + @mock.patch.object(STXCommon, '_get_vol_name') + @mock.patch.object(STXClient, 'modify_volume_name') def test_manage_existing(self, mock_modify, mock_volume): existing_ref = {'source-name': 'xxxx'} - mock_modify.side_effect = [dh_exception.DotHillRequestError, None] + mock_modify.side_effect = [stx_exception.RequestError, None] self.assertRaises(exception.Invalid, self.common.manage_existing, test_volume, existing_ref) ret = self.common.manage_existing(test_volume, existing_ref) self.assertIsNone(ret) - @mock.patch.object(dothill.DotHillClient, 'get_volume_size') + @mock.patch.object(STXClient, 'get_volume_size') def test_manage_existing_get_size(self, mock_volume): existing_ref = {'source-name': 'xxxx'} - mock_volume.side_effect = [dh_exception.DotHillRequestError, 1] + mock_volume.side_effect = [stx_exception.RequestError, 1] self.assertRaises(exception.Invalid, self.common.manage_existing_get_size, None, existing_ref) @@ -611,28 +623,28 @@ class TestFCDotHillCommon(test.TestCase): self.assertEqual(1, ret) -class TestISCSIDotHillCommon(TestFCDotHillCommon): +class TestISCSISeagateCommon(TestFCSeagateCommon): def setUp(self): - super(TestISCSIDotHillCommon, self).setUp() + super(TestISCSISeagateCommon, self).setUp() self.connector_element = 'initiator' -class TestDotHillFC(test.TestCase): - @mock.patch.object(dothill_common.DotHillCommon, 'do_setup') +class TestSeagateFC(test.TestCase): + @mock.patch.object(STXCommon, 'do_setup') def setUp(self, mock_setup): - super(TestDotHillFC, self).setUp() - self.vendor_name = 'DotHill' + super(TestSeagateFC, self).setUp() + self.vendor_name = 'Seagate' mock_setup.return_value = True def fake_init(self, *args, **kwargs): - super(dothill_fc.DotHillFCDriver, self).__init__() + super(STXFCDriver, self).__init__() self.common = None self.configuration = FakeConfiguration1() self.lookup_service = fczm_utils.create_lookup_service() - dothill_fc.DotHillFCDriver.__init__ = fake_init - self.driver = dothill_fc.DotHillFCDriver() + STXFCDriver.__init__ = fake_init + self.driver = STXFCDriver() self.driver.do_setup(None) def _test_with_mock(self, mock, method, args, expected=None): @@ -641,42 +653,42 @@ class TestDotHillFC(test.TestCase): self.assertRaises(exception.Invalid, func, *args) self.assertEqual(expected, func(*args)) - @mock.patch.object(dothill_common.DotHillCommon, 'create_volume') + @mock.patch.object(STXCommon, 'create_volume') def test_create_volume(self, mock_create): self._test_with_mock(mock_create, 'create_volume', [None]) - @mock.patch.object(dothill_common.DotHillCommon, + @mock.patch.object(STXCommon, 'create_cloned_volume') def test_create_cloned_volume(self, mock_create): self._test_with_mock(mock_create, 'create_cloned_volume', [None, None]) - @mock.patch.object(dothill_common.DotHillCommon, + @mock.patch.object(STXCommon, 'create_volume_from_snapshot') def test_create_volume_from_snapshot(self, mock_create): self._test_with_mock(mock_create, 'create_volume_from_snapshot', [None, None]) - @mock.patch.object(dothill_common.DotHillCommon, 'delete_volume') + @mock.patch.object(STXCommon, 'delete_volume') def test_delete_volume(self, mock_delete): self._test_with_mock(mock_delete, 'delete_volume', [None]) - @mock.patch.object(dothill_common.DotHillCommon, 'create_snapshot') + @mock.patch.object(STXCommon, 'create_snapshot') def test_create_snapshot(self, mock_create): self._test_with_mock(mock_create, 'create_snapshot', [None]) - @mock.patch.object(dothill_common.DotHillCommon, 'delete_snapshot') + @mock.patch.object(STXCommon, 'delete_snapshot') def test_delete_snapshot(self, mock_delete): self._test_with_mock(mock_delete, 'delete_snapshot', [None]) - @mock.patch.object(dothill_common.DotHillCommon, 'extend_volume') + @mock.patch.object(STXCommon, 'extend_volume') def test_extend_volume(self, mock_extend): self._test_with_mock(mock_extend, 'extend_volume', [None, 10]) - @mock.patch.object(dothill_common.DotHillCommon, 'client_logout') - @mock.patch.object(dothill_common.DotHillCommon, + @mock.patch.object(STXCommon, 'client_logout') + @mock.patch.object(STXCommon, 'get_active_fc_target_ports') - @mock.patch.object(dothill_common.DotHillCommon, 'map_volume') - @mock.patch.object(dothill_common.DotHillCommon, 'client_login') + @mock.patch.object(STXCommon, 'map_volume') + @mock.patch.object(STXCommon, 'client_login') def test_initialize_connection(self, mock_login, mock_map, mock_ports, mock_logout): mock_login.return_value = None @@ -698,8 +710,8 @@ class TestDotHillFC(test.TestCase): 'target_lun': 1, 'target_discovered': True}}, ret) - @mock.patch.object(dothill_common.DotHillCommon, 'unmap_volume') - @mock.patch.object(dothill.DotHillClient, 'list_luns_for_host') + @mock.patch.object(STXCommon, 'unmap_volume') + @mock.patch.object(STXClient, 'list_luns_for_host') def test_terminate_connection(self, mock_list, mock_unmap): mock_unmap.side_effect = [1] mock_list.side_effect = ['yes'] @@ -710,7 +722,7 @@ class TestDotHillFC(test.TestCase): ret = self.driver.terminate_connection(test_volume, connector) self.assertEqual(actual, ret) - @mock.patch.object(dothill_common.DotHillCommon, 'get_volume_stats') + @mock.patch.object(STXCommon, 'get_volume_stats') def test_get_volume_stats(self, mock_stats): stats = {'storage_protocol': None, 'driver_version': self.driver.VERSION, @@ -734,7 +746,7 @@ class TestDotHillFC(test.TestCase): self.assertEqual(stats, ret) mock_stats.assert_called_with(True) - @mock.patch.object(dothill_common.DotHillCommon, 'retype') + @mock.patch.object(STXCommon, 'retype') def test_retype(self, mock_retype): mock_retype.side_effect = [exception.Invalid, True, False] args = [None, None, None, None, None] @@ -742,12 +754,12 @@ class TestDotHillFC(test.TestCase): self.assertTrue(self.driver.retype(*args)) self.assertFalse(self.driver.retype(*args)) - @mock.patch.object(dothill_common.DotHillCommon, 'manage_existing') + @mock.patch.object(STXCommon, 'manage_existing') def test_manage_existing(self, mock_manage_existing): self._test_with_mock(mock_manage_existing, 'manage_existing', [None, None]) - @mock.patch.object(dothill_common.DotHillCommon, + @mock.patch.object(STXCommon, 'manage_existing_get_size') def test_manage_size(self, mock_manage_size): mock_manage_size.side_effect = [exception.Invalid, 1] @@ -757,30 +769,30 @@ class TestDotHillFC(test.TestCase): self.assertEqual(1, self.driver.manage_existing_get_size(None, None)) -class TestDotHillISCSI(TestDotHillFC): - @mock.patch.object(dothill_common.DotHillCommon, 'do_setup') +class TestSeagateISCSI(TestSeagateFC): + @mock.patch.object(STXCommon, 'do_setup') def setUp(self, mock_setup): - super(TestDotHillISCSI, self).setUp() - self.vendor_name = 'DotHill' + super(TestSeagateISCSI, self).setUp() + self.vendor_name = 'Seagate' mock_setup.return_value = True def fake_init(self, *args, **kwargs): - super(dothill_iscsi.DotHillISCSIDriver, self).__init__() + super(STXISCSIDriver, self).__init__() self.common = None self.configuration = FakeConfiguration2() self.iscsi_ips = ['10.0.0.11'] - dothill_iscsi.DotHillISCSIDriver.__init__ = fake_init - self.driver = dothill_iscsi.DotHillISCSIDriver() + STXISCSIDriver.__init__ = fake_init + self.driver = STXISCSIDriver() self.driver.do_setup(None) - @mock.patch.object(dothill_common.DotHillCommon, 'client_logout') - @mock.patch.object(dothill_common.DotHillCommon, + @mock.patch.object(STXCommon, 'client_logout') + @mock.patch.object(STXCommon, 'get_active_iscsi_target_portals') - @mock.patch.object(dothill_common.DotHillCommon, + @mock.patch.object(STXCommon, 'get_active_iscsi_target_iqns') - @mock.patch.object(dothill_common.DotHillCommon, 'map_volume') - @mock.patch.object(dothill_common.DotHillCommon, 'client_login') + @mock.patch.object(STXCommon, 'map_volume') + @mock.patch.object(STXCommon, 'client_login') def test_initialize_connection(self, mock_login, mock_map, mock_iqns, mock_portals, mock_logout): mock_login.return_value = None @@ -803,7 +815,7 @@ class TestDotHillISCSI(TestDotHillFC): 'target_discovered': True, 'target_portal': '10.0.0.11:3260'}}, ret) - @mock.patch.object(dothill_common.DotHillCommon, 'unmap_volume') + @mock.patch.object(STXCommon, 'unmap_volume') def test_terminate_connection(self, mock_unmap): mock_unmap.side_effect = [exception.Invalid, 1] diff --git a/cinder/volume/drivers/lenovo/lenovo_client.py b/cinder/volume/drivers/lenovo/lenovo_client.py index 07e807cdbf1..f5b66e9c782 100644 --- a/cinder/volume/drivers/lenovo/lenovo_client.py +++ b/cinder/volume/drivers/lenovo/lenovo_client.py @@ -14,10 +14,10 @@ # under the License. # -from cinder.volume.drivers.dothill import dothill_client +import cinder.volume.drivers.stx.client as client -class LenovoClient(dothill_client.DotHillClient): +class LenovoClient(client.STXClient): def __init__(self, host, login, password, protocol, ssl_verify): super(LenovoClient, self).__init__(host, login, password, protocol, diff --git a/cinder/volume/drivers/lenovo/lenovo_common.py b/cinder/volume/drivers/lenovo/lenovo_common.py index 7e92296abb4..e4a2c43efd1 100644 --- a/cinder/volume/drivers/lenovo/lenovo_common.py +++ b/cinder/volume/drivers/lenovo/lenovo_common.py @@ -17,25 +17,33 @@ from oslo_config import cfg from cinder.volume import configuration -from cinder.volume.drivers.dothill import dothill_common -from cinder.volume.drivers.lenovo import lenovo_client +import cinder.volume.drivers.lenovo.lenovo_client as lenovo_client +import cinder.volume.drivers.stx.common as common common_opts = [ - cfg.StrOpt('lenovo_backend_name', + cfg.StrOpt('lenovo_pool_name', + deprecated_name='lenovo_backend_name', default='A', help="Pool or Vdisk name to use for volume creation."), - cfg.StrOpt('lenovo_backend_type', + cfg.StrOpt('lenovo_pool_type', + deprecated_name='lenovo_backend_type', choices=['linear', 'virtual'], default='virtual', help="linear (for VDisk) or virtual (for Pool)."), cfg.StrOpt('lenovo_api_protocol', + deprecated_for_removal=True, + deprecated_reason='driver_use_ssl should be used instead.', choices=['http', 'https'], default='https', help="Lenovo api interface protocol."), cfg.BoolOpt('lenovo_verify_certificate', + deprecated_for_removal=True, + deprecated_reason='Use driver_ssl_cert_verify instead.', default=False, help="Whether to verify Lenovo array SSL certificate."), cfg.StrOpt('lenovo_verify_certificate_path', + deprecated_for_removal=True, + deprecated_reason='Use driver_ssl_cert_path instead.', help="Lenovo array SSL certificate path.") ] @@ -50,19 +58,26 @@ CONF.register_opts(common_opts, group=configuration.SHARED_CONF_GROUP) CONF.register_opts(iscsi_opts, group=configuration.SHARED_CONF_GROUP) -class LenovoCommon(dothill_common.DotHillCommon): - VERSION = "1.6" +class LenovoCommon(common.STXCommon): + VERSION = "2.0" def __init__(self, config): self.config = config self.vendor_name = "Lenovo" - self.backend_name = self.config.lenovo_backend_name - self.backend_type = self.config.lenovo_backend_type + self.backend_name = self.config.lenovo_pool_name + self.backend_type = self.config.lenovo_pool_type self.api_protocol = self.config.lenovo_api_protocol ssl_verify = False + # check for deprecated options... if (self.api_protocol == 'https' and self.config.lenovo_verify_certificate): ssl_verify = self.config.lenovo_verify_certificate_path or True + # ...then check common options + if self.config.driver_use_ssl: + self.api_protocol = 'https' + if self.config.driver_ssl_cert_verify: + ssl_verify = self.config.driver_ssl_cert_path or True + self.client = lenovo_client.LenovoClient(self.config.san_ip, self.config.san_login, self.config.san_password, diff --git a/cinder/volume/drivers/lenovo/lenovo_fc.py b/cinder/volume/drivers/lenovo/lenovo_fc.py index 3df296d84c3..58438ae0350 100644 --- a/cinder/volume/drivers/lenovo/lenovo_fc.py +++ b/cinder/volume/drivers/lenovo/lenovo_fc.py @@ -1,6 +1,6 @@ # Copyright 2014 Objectif Libre # Copyright 2015 Dot Hill Systems Corp. -# Copyright 2016 Seagate Technology or one of its affiliates +# Copyright 2016-2019 Seagate Technology or one of its affiliates # # 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 @@ -16,12 +16,12 @@ # from cinder import interface -from cinder.volume.drivers.dothill import dothill_fc -from cinder.volume.drivers.lenovo import lenovo_common +import cinder.volume.drivers.lenovo.lenovo_common as lenovo_common +import cinder.volume.drivers.stx.fc as fc @interface.volumedriver -class LenovoFCDriver(dothill_fc.DotHillFCDriver): +class LenovoFCDriver(fc.STXFCDriver): """OpenStack Fibre Channel cinder drivers for Lenovo Storage arrays. .. code-block:: default @@ -30,10 +30,10 @@ class LenovoFCDriver(dothill_fc.DotHillFCDriver): 1.0 - Inheriting from DotHill cinder drivers. 1.6 - Add management path redundancy and reduce load placed on management controller. - + 2.0 - DotHill driver renamed to Seagate (STX) """ - VERSION = "1.6" + VERSION = "2.0" SUPPORTED = True diff --git a/cinder/volume/drivers/lenovo/lenovo_iscsi.py b/cinder/volume/drivers/lenovo/lenovo_iscsi.py index cc2d1de646f..3d3cc053c7c 100644 --- a/cinder/volume/drivers/lenovo/lenovo_iscsi.py +++ b/cinder/volume/drivers/lenovo/lenovo_iscsi.py @@ -1,6 +1,6 @@ # Copyright 2014 Objectif Libre # Copyright 2015 Dot Hill Systems Corp. -# Copyright 2016 Seagate Technology or one of its affiliates +# Copyright 2016-2019 Seagate Technology or one of its affiliates # # 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 @@ -16,12 +16,12 @@ # from cinder import interface -from cinder.volume.drivers.dothill import dothill_iscsi -from cinder.volume.drivers.lenovo import lenovo_common +import cinder.volume.drivers.lenovo.lenovo_common as lenovo_common +import cinder.volume.drivers.stx.iscsi as iscsi @interface.volumedriver -class LenovoISCSIDriver(dothill_iscsi.DotHillISCSIDriver): +class LenovoISCSIDriver(iscsi.STXISCSIDriver): """OpenStack iSCSI cinder drivers for Lenovo Storage arrays. .. code-block:: default @@ -30,9 +30,10 @@ class LenovoISCSIDriver(dothill_iscsi.DotHillISCSIDriver): 1.0 - Inheriting from DotHill cinder drivers. 1.6 - Add management path redundancy and reduce load placed on management controller. + 2.0 - DotHill driver renamed to Seagate (STX) """ - VERSION = "1.6" + VERSION = "2.0" SUPPORTED = True diff --git a/cinder/volume/drivers/san/hp/hpmsa_client.py b/cinder/volume/drivers/san/hp/hpmsa_client.py index bec7bfd4441..813e196143a 100644 --- a/cinder/volume/drivers/san/hp/hpmsa_client.py +++ b/cinder/volume/drivers/san/hp/hpmsa_client.py @@ -14,10 +14,10 @@ # under the License. # -from cinder.volume.drivers.dothill import dothill_client +import cinder.volume.drivers.stx.client as client -class HPMSAClient(dothill_client.DotHillClient): +class HPMSAClient(client.STXClient): def __init__(self, host, login, password, protocol, ssl_verify): super(HPMSAClient, self).__init__(host, login, password, diff --git a/cinder/volume/drivers/san/hp/hpmsa_common.py b/cinder/volume/drivers/san/hp/hpmsa_common.py index 7bc10094499..5ece79ff3e5 100644 --- a/cinder/volume/drivers/san/hp/hpmsa_common.py +++ b/cinder/volume/drivers/san/hp/hpmsa_common.py @@ -17,27 +17,34 @@ from oslo_config import cfg from cinder.volume import configuration -from cinder.volume.drivers.dothill import dothill_common -from cinder.volume.drivers.san.hp import hpmsa_client +import cinder.volume.drivers.san.hp.hpmsa_client as hpmsa_client +import cinder.volume.drivers.stx.common as common common_opts = [ - cfg.StrOpt('hpmsa_backend_name', + cfg.StrOpt('hpmsa_pool_name', + deprecated_name='hpmsa_backend_name', default='A', help="Pool or Vdisk name to use for volume creation."), - cfg.StrOpt('hpmsa_backend_type', + cfg.StrOpt('hpmsa_pool_type', + deprecated_name='hpmsa_backend_type', choices=['linear', 'virtual'], default='virtual', help="linear (for Vdisk) or virtual (for Pool)."), cfg.StrOpt('hpmsa_api_protocol', + deprecated_for_removal=True, + deprecated_reason='driver_use_ssl should be used instead.', choices=['http', 'https'], default='https', help="HPMSA API interface protocol."), cfg.BoolOpt('hpmsa_verify_certificate', + deprecated_for_removal=True, + deprecated_reason='Use driver_ssl_cert_verify instead.', default=False, help="Whether to verify HPMSA array SSL certificate."), cfg.StrOpt('hpmsa_verify_certificate_path', + deprecated_for_removal=True, + deprecated_reason='Use driver_ssl_cert_path instead.', help="HPMSA array SSL certificate path."), - ] iscsi_opts = [ @@ -51,19 +58,25 @@ CONF.register_opts(common_opts, group=configuration.SHARED_CONF_GROUP) CONF.register_opts(iscsi_opts, group=configuration.SHARED_CONF_GROUP) -class HPMSACommon(dothill_common.DotHillCommon): - VERSION = "1.6" +class HPMSACommon(common.STXCommon): + VERSION = "2.0" def __init__(self, config): self.config = config self.vendor_name = "HPMSA" - self.backend_name = self.config.hpmsa_backend_name - self.backend_type = self.config.hpmsa_backend_type + self.backend_name = self.config.hpmsa_pool_name + self.backend_type = self.config.hpmsa_pool_type self.api_protocol = self.config.hpmsa_api_protocol ssl_verify = False + # check deprecated vendor-specific options ... if (self.api_protocol == 'https' and self.config.hpmsa_verify_certificate): ssl_verify = self.config.hpmsa_verify_certificate_path or True + # ... before newer common options + if self.config.driver_use_ssl: + self.api_protocol = 'https' + if self.config.driver_ssl_cert_verify: + ssl_verify = self.config.driver_ssl_cert_path or True self.client = hpmsa_client.HPMSAClient(self.config.san_ip, self.config.san_login, diff --git a/cinder/volume/drivers/san/hp/hpmsa_fc.py b/cinder/volume/drivers/san/hp/hpmsa_fc.py index 0ac0cb3d36b..d6377aba8b9 100644 --- a/cinder/volume/drivers/san/hp/hpmsa_fc.py +++ b/cinder/volume/drivers/san/hp/hpmsa_fc.py @@ -1,6 +1,6 @@ # Copyright 2014 Objectif Libre # Copyright 2015 Dot Hill Systems Corp. -# Copyright 2016 Seagate Technology or one of its affiliates +# Copyright 2016-2019 Seagate Technology or one of its affiliates # # 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 @@ -16,12 +16,12 @@ # from cinder import interface -from cinder.volume.drivers.dothill import dothill_fc -from cinder.volume.drivers.san.hp import hpmsa_common +import cinder.volume.drivers.san.hp.hpmsa_common as hpmsa_common +import cinder.volume.drivers.stx.fc as fc @interface.volumedriver -class HPMSAFCDriver(dothill_fc.DotHillFCDriver): +class HPMSAFCDriver(fc.STXFCDriver): """OpenStack Fibre Channel cinder drivers for HPMSA arrays. .. code-block:: default @@ -30,12 +30,12 @@ class HPMSAFCDriver(dothill_fc.DotHillFCDriver): 1.0 - Inheriting from DotHill cinder drivers. 1.6 - Add management path redundancy and reduce load placed on management controller. - + 2.0 - DotHill driver renamed to Seagate (STX) """ - VERSION = "1.6" + VERSION = "2.0" - CI_WIKI_NAME = "Vedams-HPMSA_FCISCSIDriver_CI" + CI_WIKI_NAME = "HPMSA_CI" SUPPORTED = True diff --git a/cinder/volume/drivers/san/hp/hpmsa_iscsi.py b/cinder/volume/drivers/san/hp/hpmsa_iscsi.py index 7db1fc401b0..03a7c42226e 100644 --- a/cinder/volume/drivers/san/hp/hpmsa_iscsi.py +++ b/cinder/volume/drivers/san/hp/hpmsa_iscsi.py @@ -1,6 +1,6 @@ # Copyright 2014 Objectif Libre # Copyright 2015 Dot Hill Systems Corp. -# Copyright 2016 Seagate Technology or one of its affiliates +# Copyright 2016-2019 Seagate Technology or one of its affiliates # # 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 @@ -16,12 +16,12 @@ # from cinder import interface -from cinder.volume.drivers.dothill import dothill_iscsi -from cinder.volume.drivers.san.hp import hpmsa_common +import cinder.volume.drivers.san.hp.hpmsa_common as hpmsa_common +import cinder.volume.drivers.stx.iscsi as iscsi @interface.volumedriver -class HPMSAISCSIDriver(dothill_iscsi.DotHillISCSIDriver): +class HPMSAISCSIDriver(iscsi.STXISCSIDriver): """OpenStack iSCSI cinder drivers for HPMSA arrays. .. code-block:: default @@ -30,12 +30,12 @@ class HPMSAISCSIDriver(dothill_iscsi.DotHillISCSIDriver): 1.0 - Inheriting from DotHill cinder drivers. 1.6 - Add management path redundancy and reduce load placed on management controller. - + 2.0 - DotHill driver renamed to Seagate (STX) """ - VERSION = "1.6" + VERSION = "2.0" - CI_WIKI_NAME = "Vedams-HPMSA_FCISCSIDriver_CI" + CI_WIKI_NAME = "HPMSA_CI" SUPPORTED = True diff --git a/cinder/volume/drivers/dothill/__init__.py b/cinder/volume/drivers/stx/__init__.py similarity index 100% rename from cinder/volume/drivers/dothill/__init__.py rename to cinder/volume/drivers/stx/__init__.py diff --git a/cinder/volume/drivers/dothill/dothill_client.py b/cinder/volume/drivers/stx/client.py similarity index 92% rename from cinder/volume/drivers/dothill/dothill_client.py rename to cinder/volume/drivers/stx/client.py index 7a14fc1bd9b..e43496ce21e 100644 --- a/cinder/volume/drivers/dothill/dothill_client.py +++ b/cinder/volume/drivers/stx/client.py @@ -1,6 +1,6 @@ # Copyright 2014 Objectif Libre # Copyright 2015 Dot Hill Systems Corp. -# Copyright 2016 Seagate Technology or one of its affiliates +# Copyright 2016-2019 Seagate Technology or one of its affiliates # # 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 @@ -19,22 +19,23 @@ import hashlib import math import time +from cinder import utils from defusedxml import lxml as etree from oslo_log import log as logging from oslo_utils import strutils from oslo_utils import units -import pprint import requests import six from cinder import coordination from cinder.i18n import _ -from cinder.volume.drivers.dothill import exception as dh_exception +import cinder.volume.drivers.stx.exception as stx_exception LOG = logging.getLogger(__name__) -class DotHillClient(object): +@six.add_metaclass(utils.TraceWrapperMetaclass) +class STXClient(object): def __init__(self, host, login, password, protocol, ssl_verify): self._mgmt_ip_addrs = list(map(str.strip, host.split(','))) self._login = login @@ -65,7 +66,7 @@ class DotHillClient(object): self._session_key = session_key except Exception as e: msg = _("Cannot parse session key: %s") % e.msg - raise dh_exception.DotHillConnectionError(message=msg) + raise stx_exception.ConnectionError(message=msg) def login(self): if self._session_key is None: @@ -86,7 +87,7 @@ class DotHillClient(object): LOG.debug("Logged in to array %s at %s (session %s)", self._array_name, self._base_url, self._session_key) return - except dh_exception.DotHillConnectionError: + except stx_exception.ConnectionError: not_responding = self._curr_ip_addr LOG.exception('session_login failed to connect to %s', self._curr_ip_addr) @@ -99,11 +100,11 @@ class DotHillClient(object): try: self._get_session_key() return - except dh_exception.DotHillConnectionError: + except stx_exception.ConnectionError: LOG.error('Failed to connect to %s', self._curr_ip_addr) continue - raise dh_exception.DotHillConnectionError( + raise stx_exception.ConnectionError( message=_("Failed to log in to management controller")) @coordination.synchronized('{self._driver_name}-{self._array_name}') @@ -114,7 +115,7 @@ class DotHillClient(object): hash_ = "%s_%s" % (self._login, self._password) if six.PY3: hash_ = hash_.encode('utf-8') - hash_ = hashlib.md5(hash_) + hash_ = hashlib.md5(hash_) # nosec digest = hash_.hexdigest() url = self._base_url + "/login/" + digest @@ -123,24 +124,24 @@ class DotHillClient(object): except requests.exceptions.RequestException: msg = _("Failed to obtain MC session key") LOG.exception(msg) - raise dh_exception.DotHillConnectionError(message=msg) + raise stx_exception.ConnectionError(message=msg) self._get_auth_token(xml.text.encode('utf8')) LOG.debug("session key = %s", self._session_key) if self._session_key is None: - raise dh_exception.DotHillAuthenticationError + raise stx_exception.AuthenticationError def _assert_response_ok(self, tree): """Parses the XML returned by the device to check the return code. - Raises a DotHillRequestError error if the return code is not 0 + Raises a RequestError error if the return code is not 0 or if the return code is None. """ # Get the return code for the operation, raising an exception # if it is not present. return_code = tree.findtext(".//PROPERTY[@name='return-code']") if not return_code: - raise dh_exception.DotHillRequestError(message="No status found") + raise stx_exception.RequestError(message="No status found") # If no error occurred, just return. if return_code == '0': @@ -150,7 +151,7 @@ class DotHillClient(object): msg = "%s (%s)" % (tree.findtext(".//PROPERTY[@name='response']"), return_code) - raise dh_exception.DotHillRequestError(message=msg) + raise stx_exception.RequestError(message=msg) def _build_request_url(self, path, *args, **kargs): url = self._base_url + path @@ -165,10 +166,10 @@ class DotHillClient(object): def _request(self, path, *args, **kargs): """Performs an API request on the array, with retry. - Propagates a DotHillConnectionError if no valid response is + Propagates a ConnectionError if no valid response is received from the array, e.g. if the network is down. - Propagates a DotHillRequestError if the device returned a response + Propagates a RequestError if the device returned a response but the status is not 0. The device error message will be used in the exception message. @@ -178,14 +179,14 @@ class DotHillClient(object): while tries_left > 0: try: return self._api_request(path, *args, **kargs) - except dh_exception.DotHillConnectionError as e: + except stx_exception.ConnectionError as e: if tries_left < 1: LOG.error("Array Connection error: " "%s (no more retries)", e.msg) raise # Retry on any network connection errors, SSL errors, etc LOG.error("Array Connection error: %s (retrying)", e.msg) - except dh_exception.DotHillRequestError as e: + except stx_exception.RequestError as e: if tries_left < 1: LOG.error("Array Request error: %s (no more retries)", e.msg) @@ -204,7 +205,7 @@ class DotHillClient(object): def _api_request(self, path, *args, **kargs): """Performs an HTTP request on the device, with locking. - Raises a DotHillRequestError if the device returned but the status is + Raises a RequestError if the device returned but the status is not 0. The device error message will be used in the exception message. If the status is OK, returns the XML data for further processing. @@ -221,7 +222,7 @@ class DotHillClient(object): except Exception as e: message = _("Exception handling URL %(url)s: %(msg)s") % { 'url': url, 'msg': e} - raise dh_exception.DotHillConnectionError(message=message) + raise stx_exception.ConnectionError(message=message) if path == "/show/volumecopy-status": return tree @@ -253,7 +254,7 @@ class DotHillClient(object): try: self._request("/create/volume", name, **path_dict) - except dh_exception.DotHillRequestError as e: + except stx_exception.RequestError as e: # -10186 => The specified name is already in use. # This can occur during controller failover. if '(-10186)' in e.msg: @@ -266,7 +267,7 @@ class DotHillClient(object): def delete_volume(self, name): try: self._request("/delete/volumes", name) - except dh_exception.DotHillRequestError as e: + except stx_exception.RequestError as e: # -10075 => The specified volume was not found. # This can occur during controller failover. if '(-10075)' in e.msg: @@ -282,7 +283,7 @@ class DotHillClient(object): def create_snapshot(self, volume_name, snap_name): try: self._request("/create/snapshots", snap_name, volumes=volume_name) - except dh_exception.DotHillRequestError as e: + except stx_exception.RequestError as e: # -10186 => The specified name is already in use. # This can occur during controller failover. if '(-10186)' in e.msg: @@ -296,7 +297,7 @@ class DotHillClient(object): self._request("/delete/snapshot", "cleanup", snap_name) else: self._request("/delete/snapshot", snap_name) - except dh_exception.DotHillRequestError as e: + except stx_exception.RequestError as e: # -10050 => The volume was not found on this system. # This can occur during controller failover. if '(-10050)' in e.msg: @@ -312,7 +313,7 @@ class DotHillClient(object): path = "/show/pools" self._request(path, backend_name) return True - except dh_exception.DotHillRequestError: + except stx_exception.RequestError: return False def _get_size(self, size): @@ -378,7 +379,7 @@ class DotHillClient(object): firsthost, lun) return lun lun += 1 - raise dh_exception.DotHillRequestError( + raise stx_exception.RequestError( message=_("No LUNs available for mapping to host %s.") % host) def _is_mapped(self, volume_name, ids): @@ -393,7 +394,7 @@ class DotHillClient(object): if iid in ids: LOG.debug("volume '{}' is already mapped to {} at lun {}". format(volume_name, iid, lun)) - return lun + return int(lun) except Exception as e: LOG.exception("failed to look up mappings for volume '%s'", volume_name) @@ -403,8 +404,6 @@ class DotHillClient(object): @coordination.synchronized('{self._driver_name}-{self._array_name}-map') def map_volume(self, volume_name, connector, connector_element): # If multiattach enabled, its possible the volume is already mapped - LOG.debug("map_volume(%s, %s, %s)", volume_name, - pprint.pformat(connector), connector_element) lun = self._is_mapped(volume_name, connector[connector_element]) if lun: return lun @@ -418,7 +417,7 @@ class DotHillClient(object): hostname = self._safe_hostname(connector['host']) try: self._request("/create/host", hostname, id=host) - except dh_exception.DotHillRequestError as e: + except stx_exception.RequestError as e: # -10058: The host identifier or nickname is already in use if '(-10058)' in e.msg: LOG.error("While trying to create host nickname" @@ -437,7 +436,7 @@ class DotHillClient(object): host=host, access="rw") return lun - except dh_exception.DotHillRequestError as e: + except stx_exception.RequestError as e: # -3177 => "The specified LUN overlaps a previously defined LUN if '(-3177)' in e.msg: LOG.info("Unable to map volume" @@ -456,7 +455,7 @@ class DotHillClient(object): e) raise - raise dh_exception.DotHillRequestError( + raise stx_exception.RequestError( message=_("Failed to find a free LUN for host %s") % host) def unmap_volume(self, volume_name, connector, connector_element): @@ -466,7 +465,7 @@ class DotHillClient(object): host = connector['initiator'] try: self._request("/unmap/volume", volume_name, host=host) - except dh_exception.DotHillRequestError as e: + except stx_exception.RequestError as e: # -10050 => The volume was not found on this system. # This can occur during controller failover. if '(-10050)' in e.msg: @@ -522,7 +521,7 @@ class DotHillClient(object): else: if count >= 5: LOG.error('Error in copying volume: %s', src_name) - raise dh_exception.DotHillRequestError + raise stx_exception.RequestError time.sleep(1) count += 1 diff --git a/cinder/volume/drivers/dothill/dothill_common.py b/cinder/volume/drivers/stx/common.py similarity index 83% rename from cinder/volume/drivers/dothill/dothill_common.py rename to cinder/volume/drivers/stx/common.py index 5d83e113775..dc8845c4542 100644 --- a/cinder/volume/drivers/dothill/dothill_common.py +++ b/cinder/volume/drivers/stx/common.py @@ -1,6 +1,6 @@ # Copyright 2014 Objectif Libre # Copyright 2015 Dot Hill Systems Corp. -# Copyright 2016 Seagate Technology or one of its affiliates +# Copyright 2016-2019 Seagate Technology or one of its affiliates # # 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 @@ -15,7 +15,7 @@ # under the License. # """ -Volume driver common utilities for DotHill Storage array +Volume driver common utilities for Seagate storage arrays """ import base64 @@ -28,34 +28,56 @@ from oslo_log import log as logging from cinder import exception from cinder.i18n import _ from cinder.objects import fields -from cinder.volume.drivers.dothill import dothill_client as dothill -from cinder.volume.drivers.dothill import exception as dh_exception +from cinder import utils +from cinder.volume import configuration +import cinder.volume.drivers.stx.client as client +import cinder.volume.drivers.stx.exception as stx_exception LOG = logging.getLogger(__name__) +common_opts = [ + cfg.StrOpt('seagate_pool_name', + default='A', + help="Pool or vdisk name to use for volume creation."), + cfg.StrOpt('seagate_pool_type', + choices=['linear', 'virtual'], + default='virtual', + help="linear (for vdisk) or virtual (for virtual pool)."), +] + +iscsi_opts = [ + cfg.ListOpt('seagate_iscsi_ips', + default=[], + help="List of comma-separated target iSCSI IP addresses."), +] + CONF = cfg.CONF +CONF.register_opts(common_opts, group=configuration.SHARED_CONF_GROUP) +CONF.register_opts(iscsi_opts, group=configuration.SHARED_CONF_GROUP) -class DotHillCommon(object): - VERSION = "1.6" +@six.add_metaclass(utils.TraceWrapperMetaclass) +class STXCommon(object): + VERSION = "2.0" stats = {} def __init__(self, config): self.config = config - self.vendor_name = "DotHill" - self.backend_name = self.config.dothill_backend_name - self.backend_type = self.config.dothill_backend_type - self.api_protocol = self.config.dothill_api_protocol - ssl_verify = False - if (self.api_protocol == 'https' and - self.config.dothill_verify_certificate): - ssl_verify = self.config.dothill_verify_certificate_path or True - self.client = dothill.DotHillClient(self.config.san_ip, - self.config.san_login, - self.config.san_password, - self.api_protocol, - ssl_verify) + self.vendor_name = "Seagate" + self.backend_name = self.config.seagate_pool_name + self.backend_type = self.config.seagate_pool_type + self.api_protocol = 'http' + if self.config.driver_use_ssl: + self.api_protocol = 'https' + ssl_verify = self.config.driver_ssl_cert_verify + if ssl_verify and self.config.driver_ssl_cert_path: + ssl_verify = self.config.driver_ssl_cert_path + self.client = client.STXClient(self.config.san_ip, + self.config.san_login, + self.config.san_password, + self.api_protocol, + ssl_verify) def get_version(self): return self.VERSION @@ -70,18 +92,18 @@ class DotHillCommon(object): def client_login(self): try: self.client.login() - except dh_exception.DotHillConnectionError as ex: + except stx_exception.ConnectionError as ex: msg = _("Failed to connect to %(vendor_name)s Array %(host)s: " "%(err)s") % {'vendor_name': self.vendor_name, 'host': self.config.san_ip, 'err': six.text_type(ex)} LOG.error(msg) - raise dh_exception.DotHillConnectionError(message=msg) - except dh_exception.DotHillAuthenticationError: + raise stx_exception.ConnectionError(message=msg) + except stx_exception.AuthenticationError: msg = _("Failed to log on %s Array " "(invalid login?).") % self.vendor_name LOG.error(msg) - raise dh_exception.DotHillAuthenticationError(message=msg) + raise stx_exception.AuthenticationError(message=msg) def _get_serial_number(self): self.serialNumber = self.client.get_serial_number() @@ -94,7 +116,7 @@ class DotHillCommon(object): if not self.client.backend_exists(self.backend_name, self.backend_type): self.client_logout() - raise dh_exception.DotHillInvalidBackend(backend=self.backend_name) + raise stx_exception.InvalidBackend(backend=self.backend_name) def client_logout(self): self.client.logout() @@ -108,7 +130,7 @@ class DotHillCommon(object): return "s%s" % snapshot_name def _encode_name(self, name): - """Get converted DotHill volume name. + """Get converted array volume name. Converts the openstack volume id from fceec30e-98bc-4ce5-85ff-d7309cc17cc2 @@ -135,7 +157,7 @@ class DotHillCommon(object): def create_volume(self, volume): self.client_login() - # Use base64 to encode the volume name (UUID is too long for DotHill) + # Use base64 to encode the volume name (UUID is too long) volume_name = self._get_vol_name(volume['id']) volume_size = "%dGiB" % volume['size'] LOG.debug("Create Volume having display_name: %(display_name)s " @@ -149,7 +171,7 @@ class DotHillCommon(object): volume_size, self.backend_name, self.backend_type) - except dh_exception.DotHillRequestError as ex: + except stx_exception.RequestError as ex: LOG.exception("Creation of volume %s failed.", volume['id']) raise exception.Invalid(ex) @@ -157,22 +179,19 @@ class DotHillCommon(object): self.client_logout() def _assert_enough_space_for_copy(self, volume_size): - """The DotHill creates a snap pool before trying to copy the volume. + """The array creates a snap pool before trying to copy the volume. The pool is 5.27GB or 20% of the volume size, whichever is larger. - Verify that we have enough space for the pool and then copy + Verify that we have enough space for the pool and then copy. """ pool_size = max(volume_size * 0.2, 5.27) required_size = pool_size + volume_size if required_size > self.stats['pools'][0]['free_capacity_gb']: - raise dh_exception.DotHillNotEnoughSpace(backend=self.backend_name) + raise stx_exception.NotEnoughSpace(backend=self.backend_name) def _assert_source_detached(self, volume): - """The DotHill requires a volume to be dettached to clone it. - - Make sure that the volume is not in use when trying to copy it. - """ + """The array requires volume to be detached before cloning.""" if (volume['status'] != "available" or volume['attach_status'] == fields.VolumeAttachStatus.ATTACHED): LOG.error("Volume must be detached for clone operation.") @@ -196,7 +215,7 @@ class DotHillCommon(object): try: self.client.copy_volume(orig_name, dest_name, self.backend_name, self.backend_type) - except dh_exception.DotHillRequestError as ex: + except stx_exception.RequestError as ex: LOG.exception("Cloning of volume %s failed.", src_vref['id']) raise exception.Invalid(ex) @@ -219,7 +238,7 @@ class DotHillCommon(object): try: self.client.copy_volume(orig_name, dest_name, self.backend_name, self.backend_type) - except dh_exception.DotHillRequestError as ex: + except stx_exception.RequestError as ex: LOG.exception("Create volume failed from snapshot: %s", snapshot['id']) raise exception.Invalid(ex) @@ -239,7 +258,7 @@ class DotHillCommon(object): self.client_login() try: self.client.delete_volume(volume_name) - except dh_exception.DotHillRequestError as ex: + except stx_exception.RequestError as ex: # if the volume wasn't found, ignore the error if 'The volume was not found on this system.' in ex.args: return @@ -278,7 +297,7 @@ class DotHillCommon(object): self.backend_name, self.owner)) pool['pool_name'] = self.backend_name - except dh_exception.DotHillRequestError: + except stx_exception.RequestError: err = (_("Unable to get stats for backend_name: %s") % self.backend_name) LOG.exception(err) @@ -304,7 +323,7 @@ class DotHillCommon(object): connector, connector_element) return data - except dh_exception.DotHillRequestError as ex: + except stx_exception.RequestError as ex: LOG.exception("Error mapping volume: %s", volume_name) raise exception.Invalid(ex) @@ -320,7 +339,7 @@ class DotHillCommon(object): self.client.unmap_volume(volume_name, connector, connector_element) - except dh_exception.DotHillRequestError as ex: + except stx_exception.RequestError as ex: LOG.exception("Error unmapping volume: %s", volume_name) raise exception.Invalid(ex) finally: @@ -329,21 +348,21 @@ class DotHillCommon(object): def get_active_fc_target_ports(self): try: return self.client.get_active_fc_target_ports() - except dh_exception.DotHillRequestError as ex: + except stx_exception.RequestError as ex: LOG.exception("Error getting active FC target ports.") raise exception.Invalid(ex) def get_active_iscsi_target_iqns(self): try: return self.client.get_active_iscsi_target_iqns() - except dh_exception.DotHillRequestError as ex: + except stx_exception.RequestError as ex: LOG.exception("Error getting active ISCSI target iqns.") raise exception.Invalid(ex) def get_active_iscsi_target_portals(self): try: return self.client.get_active_iscsi_target_portals() - except dh_exception.DotHillRequestError as ex: + except stx_exception.RequestError as ex: LOG.exception("Error getting active ISCSI target portals.") raise exception.Invalid(ex) @@ -360,7 +379,7 @@ class DotHillCommon(object): self.client_login() try: self.client.create_snapshot(vol_name, snap_name) - except dh_exception.DotHillRequestError as ex: + except stx_exception.RequestError as ex: LOG.exception("Creation of snapshot failed for volume: %s", snapshot['volume_id']) raise exception.Invalid(ex) @@ -374,7 +393,7 @@ class DotHillCommon(object): self.client_login() try: self.client.delete_snapshot(snap_name, self.backend_type) - except dh_exception.DotHillRequestError as ex: + except stx_exception.RequestError as ex: # if the volume wasn't found, ignore the error if 'The volume was not found on this system.' in ex.args: return @@ -401,7 +420,7 @@ class DotHillCommon(object): self.client_login() try: self.client.extend_volume(volume_name, "%dGiB" % growth_size) - except dh_exception.DotHillRequestError as ex: + except stx_exception.RequestError as ex: LOG.exception("Extension of volume %s failed.", volume['id']) raise exception.Invalid(ex) finally: @@ -410,14 +429,14 @@ class DotHillCommon(object): def get_chap_record(self, initiator_name): try: return self.client.get_chap_record(initiator_name) - except dh_exception.DotHillRequestError as ex: + except stx_exception.RequestError as ex: LOG.exception("Error getting chap record.") raise exception.Invalid(ex) def create_chap_record(self, initiator_name, chap_secret): try: self.client.create_chap_record(initiator_name, chap_secret) - except dh_exception.DotHillRequestError as ex: + except stx_exception.RequestError as ex: LOG.exception("Error creating chap record.") raise exception.Invalid(ex) @@ -444,7 +463,8 @@ class DotHillCommon(object): except ValueError: return false_ret - if not (dest_type == 'DotHillVolumeDriver' and + reqd_dest_type = '%sVolumeDriver' % self.vendor_name + if not (dest_type == reqd_dest_type and dest_id == self.serialNumber and dest_owner == self.owner): return false_ret @@ -452,7 +472,7 @@ class DotHillCommon(object): source_name = self._get_vol_name(volume['name_id']) else: source_name = self._get_vol_name(volume['id']) - # DotHill Array does not support duplicate names + # the array does not support duplicate names dest_name = "m%s" % source_name[1:] self.client_login() @@ -462,7 +482,7 @@ class DotHillCommon(object): self.client.delete_volume(source_name) self.client.modify_volume_name(dest_name, source_name) return (True, None) - except dh_exception.DotHillRequestError as ex: + except stx_exception.RequestError as ex: LOG.exception("Error migrating volume: %s", source_name) raise exception.Invalid(ex) finally: @@ -473,10 +493,10 @@ class DotHillCommon(object): return ret[0] def manage_existing(self, volume, existing_ref): - """Manage an existing non-openstack DotHill volume + """Manage an existing non-openstack array volume existing_ref is a dictionary of the form: - {'source-name': } + {'source-name': } """ target_vol_name = existing_ref['source-name'] modify_target_vol_name = self._get_vol_name(volume['id']) @@ -485,7 +505,7 @@ class DotHillCommon(object): try: self.client.modify_volume_name(target_vol_name, modify_target_vol_name) - except dh_exception.DotHillRequestError as ex: + except stx_exception.RequestError as ex: LOG.exception("Error manage existing volume.") raise exception.Invalid(ex) finally: @@ -503,7 +523,7 @@ class DotHillCommon(object): try: size = self.client.get_volume_size(target_vol_name) return size - except dh_exception.DotHillRequestError as ex: + except stx_exception.RequestError as ex: LOG.exception("Error manage existing get volume size.") raise exception.Invalid(ex) finally: diff --git a/cinder/volume/drivers/dothill/exception.py b/cinder/volume/drivers/stx/exception.py similarity index 64% rename from cinder/volume/drivers/dothill/exception.py rename to cinder/volume/drivers/stx/exception.py index b351b0086f7..2f7f30f76d0 100644 --- a/cinder/volume/drivers/dothill/exception.py +++ b/cinder/volume/drivers/stx/exception.py @@ -15,29 +15,25 @@ from cinder import exception from cinder.i18n import _ -class DotHillInvalidBackend(exception.VolumeDriverException): +class InvalidBackend(exception.VolumeDriverException): message = _("Backend doesn't exist (%(backend)s)") -class DotHillConnectionError(exception.VolumeDriverException): +class ConnectionError(exception.VolumeDriverException): message = "%(message)s" -class DotHillAuthenticationError(exception.VolumeDriverException): +class AuthenticationError(exception.VolumeDriverException): message = "%(message)s" -class DotHillNotEnoughSpace(exception.VolumeDriverException): +class NotEnoughSpace(exception.VolumeDriverException): message = _("Not enough space on backend (%(backend)s)") -class DotHillRequestError(exception.VolumeDriverException): +class RequestError(exception.VolumeDriverException): message = "%(message)s" -class DotHillNotTargetPortal(exception.VolumeDriverException): +class NotTargetPortal(exception.VolumeDriverException): message = _("No active iSCSI portals with supplied iSCSI IPs") - - -class DotHillDriverNotSupported(exception.VolumeDriverException): - message = _("The Dot Hill driver is no longer supported.") diff --git a/cinder/volume/drivers/dothill/dothill_fc.py b/cinder/volume/drivers/stx/fc.py similarity index 87% rename from cinder/volume/drivers/dothill/dothill_fc.py rename to cinder/volume/drivers/stx/fc.py index 6b69e8c53e5..b94c53c2166 100644 --- a/cinder/volume/drivers/dothill/dothill_fc.py +++ b/cinder/volume/drivers/stx/fc.py @@ -1,6 +1,6 @@ # Copyright 2014 Objectif Libre # Copyright 2015 Dot Hill Systems Corp. -# Copyright 2016 Seagate Technology or one of its affiliates +# Copyright 2016-2019 Seagate Technology or one of its affiliates # # 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 @@ -16,17 +16,13 @@ # import cinder.volume.driver -from cinder.volume.drivers.dothill import dothill_common -from cinder.volume.drivers.dothill import exception as dh_exception -from cinder.volume.drivers.san import san +import cinder.volume.drivers.san.san as san +import cinder.volume.drivers.stx.common as common from cinder.zonemanager import utils as fczm_utils -# As of Pike, the DotHill driver is no longer considered supported, -# but the code remains as it is still subclassed by other drivers. -# The __init__() function prevents any direct instantiation. -class DotHillFCDriver(cinder.volume.driver.FibreChannelDriver): - """OpenStack Fibre Channel cinder drivers for DotHill Arrays. +class STXFCDriver(cinder.volume.driver.FibreChannelDriver): + """OpenStack Fibre Channel cinder drivers for Seagate arrays. .. code:: text @@ -44,20 +40,24 @@ class DotHillFCDriver(cinder.volume.driver.FibreChannelDriver): 1.6 - Add management path redundancy and reduce load placed on management controller. 1.7 - Modified so it can't be invoked except as a superclass - + 2.0 - Reworked to create a new Seagate (STX) array driver. """ + VERSION = "2.0" + + CI_WIKI_NAME = 'Seagate_CI' + def __init__(self, *args, **kwargs): - # Make sure we're not invoked directly - if type(self) == DotHillFCDriver: - raise dh_exception.DotHillDriverNotSupported - super(DotHillFCDriver, self).__init__(*args, **kwargs) + super(STXFCDriver, self).__init__(*args, **kwargs) self.common = None self.configuration.append_config_values(san.san_opts) self.lookup_service = fczm_utils.create_lookup_service() + if type(self) != STXFCDriver: + return + self.configuration.append_config_values(common.common_opts) def _init_common(self): - return dothill_common.DotHillCommon(self.configuration) + return common.STXCommon(self.configuration) def _check_flags(self): required_flags = ['san_ip', 'san_login', 'san_password'] @@ -105,12 +105,15 @@ class DotHillFCDriver(cinder.volume.driver.FibreChannelDriver): def terminate_connection(self, volume, connector, **kwargs): info = {'driver_volume_type': 'fibre_channel', 'data': {}} try: - self.common.unmap_volume(volume, connector, 'wwpns') if not self.common.client.list_luns_for_host( connector['wwpns'][0]): ports, init_targ_map = self.get_init_targ_map(connector) info['data'] = {'target_wwn': ports, 'initiator_target_map': init_targ_map} + # multiattach volumes cannot be unmapped here, but will + # be implicity unmapped when the volume is deleted. + if not volume.get('multiattach'): + self.common.unmap_volume(volume, connector, 'wwpns') fczm_utils.remove_fc_zone(info) finally: return info diff --git a/cinder/volume/drivers/dothill/dothill_iscsi.py b/cinder/volume/drivers/stx/iscsi.py similarity index 85% rename from cinder/volume/drivers/dothill/dothill_iscsi.py rename to cinder/volume/drivers/stx/iscsi.py index bed349e9821..7dada536104 100644 --- a/cinder/volume/drivers/dothill/dothill_iscsi.py +++ b/cinder/volume/drivers/stx/iscsi.py @@ -1,6 +1,6 @@ # Copyright 2014 Objectif Libre # Copyright 2015 Dot Hill Systems Corp. -# Copyright 2016 Seagate Technology or one of its affiliates +# Copyright 2016-2019 Seagate Technology or one of its affiliates # # 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 @@ -20,20 +20,17 @@ from oslo_log import log as logging from cinder import exception from cinder.i18n import _ import cinder.volume.driver -from cinder.volume.drivers.dothill import dothill_common as dothillcommon -from cinder.volume.drivers.dothill import exception as dh_exception -from cinder.volume.drivers.san import san +import cinder.volume.drivers.san.san as san +import cinder.volume.drivers.stx.common as common +import cinder.volume.drivers.stx.exception as stx_exception DEFAULT_ISCSI_PORT = "3260" LOG = logging.getLogger(__name__) -# As of Pike, the DotHill driver is no longer considered supported, -# but the code remains as it is still subclassed by other drivers. -# The __init__() function prevents any direct instantiation. -class DotHillISCSIDriver(cinder.volume.driver.ISCSIDriver): - """OpenStack iSCSI cinder drivers for DotHill Arrays. +class STXISCSIDriver(cinder.volume.driver.ISCSIDriver): + """OpenStack iSCSI Cinder driver for Seagate storage arrays. .. code:: text @@ -53,20 +50,25 @@ class DotHillISCSIDriver(cinder.volume.driver.ISCSIDriver): 1.6 - Add management path redundancy and reduce load placed on management controller. 1.7 - Modified so it can't be invoked except as a superclass - + 2.0 - Reworked to create a new Seagate (STX) array driver. """ + VERSION = "2.0" + + CI_WIKI_NAME = 'Seagate_CI' + def __init__(self, *args, **kwargs): - # Make sure we're not invoked directly - if type(self) == DotHillISCSIDriver: - raise dh_exception.DotHillDriverNotSupported - super(DotHillISCSIDriver, self).__init__(*args, **kwargs) + super(STXISCSIDriver, self).__init__(*args, **kwargs) self.common = None self.configuration.append_config_values(san.san_opts) - self.iscsi_ips = None + if type(self) != STXISCSIDriver: + return + self.configuration.append_config_values(common.common_opts) + self.configuration.append_config_values(common.iscsi_opts) + self.iscsi_ips = self.configuration.seagate_iscsi_ips def _init_common(self): - return dothillcommon.DotHillCommon(self.configuration) + return common.STXCommon(self.configuration) def _check_flags(self): required_flags = ['san_ip', 'san_login', 'san_password'] @@ -130,7 +132,7 @@ class DotHillISCSIDriver(cinder.volume.driver.ISCSIDriver): break if 'target_portal' not in data: - raise dh_exception.DotHillNotTargetPortal() + raise stx_exception.NotTargetPortal() if self.configuration.use_chap_auth: chap_secret = self.common.get_chap_record( @@ -152,7 +154,10 @@ class DotHillISCSIDriver(cinder.volume.driver.ISCSIDriver): def terminate_connection(self, volume, connector, **kwargs): if type(connector) == dict and 'initiator' in connector: - self.common.unmap_volume(volume, connector, 'initiator') + # multiattach volumes cannot be unmapped here, but will + # be implicity unmapped when the volume is deleted. + if not volume.get('multiattach'): + self.common.unmap_volume(volume, connector, 'initiator') def get_volume_stats(self, refresh=False): stats = self.common.get_volume_stats(refresh) diff --git a/doc/source/configuration/block-storage/drivers/hp-msa-driver.rst b/doc/source/configuration/block-storage/drivers/hp-msa-driver.rst index 1dc54990e93..76256dca69b 100644 --- a/doc/source/configuration/block-storage/drivers/hp-msa-driver.rst +++ b/doc/source/configuration/block-storage/drivers/hp-msa-driver.rst @@ -38,9 +38,10 @@ Supported operations Configuring the array ~~~~~~~~~~~~~~~~~~~~~ -#. Verify that the array can be managed via an HTTPS connection. HTTP can also - be used if ``hpmsa_api_protocol=http`` is placed into the appropriate - sections of the ``cinder.conf`` file. +#. Verify that the array can be managed using an HTTPS connection. HTTP + can also be used if ``hpmsa_api_protocol=http`` is placed into the + appropriate sections of the ``cinder.conf`` file, but this option is + deprecated and will be removed in a future release. Confirm that virtual pools A and B are present if you plan to use virtual pools for OpenStack storage. @@ -50,12 +51,12 @@ Configuring the array creating or setting aside one disk group for each of the A and B controllers. -#. Edit the ``cinder.conf`` file to define a storage back end entry for each +#. Edit the ``cinder.conf`` file to define a storage back-end entry for each storage pool on the array that will be managed by OpenStack. Each entry consists of a unique section name, surrounded by square brackets, followed - by options specified in a ``key=value`` format. + by options specified in ``key=value`` format. - * The ``hpmsa_backend_name`` value specifies the name of the storage pool + * The ``hpmsa_pool_name`` value specifies the name of the storage pool or vdisk on the array. * The ``volume_backend_name`` option value can be a unique value, if you @@ -64,92 +65,101 @@ Configuring the array volume scheduler choose where new volumes are allocated. * The rest of the options will be repeated for each storage pool in a - given array: ``volume_driver`` specifies the Cinder driver name; - ``san_ip`` specifies the IP addresses or host names of the array's - management controllers; ``san_login`` and ``san_password`` specify - the username and password of an array user account with ``manage`` - privileges; and ``hpmsa_iscsi_ips`` specfies the iSCSI IP addresses - for the array if using the iSCSI transport protocol. + given array: + + * ``volume_driver`` specifies the Cinder driver name. + * ``san_ip`` specifies the IP addresses or host names of the array's + management controllers. + * ``san_login`` and ``san_password`` specify the username and password + of an array user account with ``manage`` privileges. + * ``driver_use_ssl`` should be set to ``true`` to enable use of the + HTTPS protocol. + * ``hpmsa_iscsi_ips`` specfies the iSCSI IP addresses for the array + if using the iSCSI transport protocol. In the examples below, two back ends are defined, one for pool A and one for pool B, and a common ``volume_backend_name`` is used so that a single volume type definition can be used to allocate volumes from both pools. - **iSCSI example back-end entries** + **Example: iSCSI example back-end entries** .. code-block:: ini [pool-a] - hpmsa_backend_name = A + hpmsa_pool_name = A volume_backend_name = hpmsa-array volume_driver = cinder.volume.drivers.san.hp.hpmsa_iscsi.HPMSAISCSIDriver san_ip = 10.1.2.3,10.1.2.4 san_login = manage san_password = !manage hpmsa_iscsi_ips = 10.2.3.4,10.2.3.5 + driver_use_ssl = true [pool-b] - hpmsa_backend_name = B + hpmsa_pool_name = B volume_backend_name = hpmsa-array volume_driver = cinder.volume.drivers.san.hp.hpmsa_iscsi.HPMSAISCSIDriver san_ip = 10.1.2.3,10.1.2.4 san_login = manage san_password = !manage hpmsa_iscsi_ips = 10.2.3.4,10.2.3.5 + driver_use_ssl = true - **Fibre Channel example back-end entries** + **Example: Fibre Channel example back-end entries** .. code-block:: ini [pool-a] - hpmsa_backend_name = A + hpmsa_pool_name = A volume_backend_name = hpmsa-array volume_driver = cinder.volume.drivers.san.hp.hpmsa_fc.HPMSAFCDriver san_ip = 10.1.2.3,10.1.2.4 san_login = manage san_password = !manage + driver_use_ssl = true [pool-b] - hpmsa_backend_name = B + hpmsa_pool_name = B volume_backend_name = hpmsa-array volume_driver = cinder.volume.drivers.san.hp.hpmsa_fc.HPMSAFCDriver san_ip = 10.1.2.3,10.1.2.4 san_login = manage san_password = !manage + driver_use_ssl = true #. If any ``volume_backend_name`` value refers to a vdisk rather than a - virtual pool, add an additional statement ``hpmsa_backend_type = linear`` + virtual pool, add an additional statement ``hpmsa_pool_type = linear`` to that back end entry. #. If HTTPS is not enabled in the array, include ``hpmsa_api_protocol = http`` in each of the back-end definitions. -#. If HTTPS is enabled, you can enable certificate verification with the option - ``hpmsa_verify_certificate=True``. You may also use the - ``hpmsa_verify_certificate_path`` parameter to specify the path to a - CA\_BUNDLE file containing CAs other than those in the default list. +#. If HTTPS is enabled, you can enable certificate verification with the + option ``driver_ssl_cert_verify = True``. You may also use the + ``driver_ssl_cert_path`` option to specify the path to a + CA_BUNDLE file containing CAs other than those in the default list. #. Modify the ``[DEFAULT]`` section of the ``cinder.conf`` file to add an - ``enabled_back-ends`` parameter specifying the backend entries you added, + ``enabled_backends`` parameter specifying the back-end entries you added, and a ``default_volume_type`` parameter specifying the name of a volume type that you will create in the next step. - **Example of [DEFAULT] section changes** + **Example: [DEFAULT] section changes** .. code-block:: ini [DEFAULT] + # ... enabled_backends = pool-a,pool-b default_volume_type = hpmsa - #. Create a new volume type for each distinct ``volume_backend_name`` value - that you added in the ``cinder.conf`` file. The example below assumes that + that you added to the ``cinder.conf`` file. The example below assumes that the same ``volume_backend_name=hpmsa-array`` option was specified in all of the entries, and specifies that the volume type ``hpmsa`` can be used to allocate volumes from any of them. - **Example of creating a volume type** + **Example: Creating a volume type** .. code-block:: console diff --git a/doc/source/configuration/block-storage/drivers/lenovo-driver.rst b/doc/source/configuration/block-storage/drivers/lenovo-driver.rst index 5e591eba592..bba6a86225d 100644 --- a/doc/source/configuration/block-storage/drivers/lenovo-driver.rst +++ b/doc/source/configuration/block-storage/drivers/lenovo-driver.rst @@ -44,9 +44,10 @@ Supported operations Configuring the array ~~~~~~~~~~~~~~~~~~~~~ -#. Verify that the array can be managed using an HTTPS connection. HTTP can - also be used if ``lenovo_api_protocol=http`` is placed into the - appropriate sections of the ``cinder.conf`` file. +#. Verify that the array can be managed using an HTTPS connection. HTTP + can also be used if ``hpmsa_api_protocol=http`` is placed into the + appropriate sections of the ``cinder.conf`` file, but this option is + deprecated and will be removed in a future release. Confirm that virtual pools A and B are present if you plan to use virtual pools for OpenStack storage. @@ -56,21 +57,26 @@ Configuring the array entry consists of a unique section name, surrounded by square brackets, followed by options specified in ``key=value`` format. - - The ``lenovo_backend_name`` value specifies the name of the storage + - The ``lenovo_pool_name`` value specifies the name of the storage pool on the array. - The ``volume_backend_name`` option value can be a unique value, if you wish to be able to assign volumes to a specific storage pool on - the array, or a name that's shared among multiple storage pools to + the array, or a name that is shared among multiple storage pools to let the volume scheduler choose where new volumes are allocated. - The rest of the options will be repeated for each storage pool in a - given array: ``volume_driver`` specifies the Cinder driver name; - ``san_ip`` specifies the IP addresses or host names of the array's - management controllers; ``san_login`` and ``san_password`` specify - the username and password of an array user account with ``manage`` - privileges; and ``lenovo_iscsi_ips`` specfies the iSCSI IP - addresses for the array if using the iSCSI transport protocol. + given array: + + * ``volume_driver`` specifies the Cinder driver name. + * ``san_ip`` specifies the IP addresses or host names of the array's + management controllers. + * ``san_login`` and ``san_password`` specify the username and password + of an array user account with ``manage`` privileges. + * ``driver_use_ssl`` should be set to ``true`` to enable use of the + HTTPS protocol. + * ``lenovo_iscsi_ips`` specfies the iSCSI IP addresses for the array + if using the iSCSI transport protocol. In the examples below, two back ends are defined, one for pool A and one for pool B, and a common ``volume_backend_name`` is used so that a @@ -82,49 +88,53 @@ Configuring the array .. code-block:: ini [pool-a] - lenovo_backend_name = A + lenovo_pool_name = A volume_backend_name = lenovo-array volume_driver = cinder.volume.drivers.lenovo.lenovo_iscsi.LenovoISCSIDriver san_ip = 10.1.2.3 san_login = manage san_password = !manage lenovo_iscsi_ips = 10.2.3.4,10.2.3.5 + driver_use_ssl = true [pool-b] - lenovo_backend_name = B + lenovo_pool_name = B volume_backend_name = lenovo-array volume_driver = cinder.volume.drivers.lenovo.lenovo_iscsi.LenovoISCSIDriver san_ip = 10.1.2.3 san_login = manage san_password = !manage lenovo_iscsi_ips = 10.2.3.4,10.2.3.5 + driver_use_ssl = true **Example: Fibre Channel example back-end entries** .. code-block:: ini [pool-a] - lenovo_backend_name = A + lenovo_pool_name = A volume_backend_name = lenovo-array volume_driver = cinder.volume.drivers.lenovo.lenovo_fc.LenovoFCDriver san_ip = 10.1.2.3 san_login = manage san_password = !manage + driver_use_ssl = true [pool-b] - lenovo_backend_name = B + lenovo_pool_name = B volume_backend_name = lenovo-array volume_driver = cinder.volume.drivers.lenovo.lenovo_fc.LenovoFCDriver san_ip = 10.1.2.3 san_login = manage san_password = !manage + driver_use_ssl = true -#. If HTTPS is not enabled in the array, include +#. If HTTPS is not enabled in the array, add ``lenovo_api_protocol = http`` in each of the back-end definitions. #. If HTTPS is enabled, you can enable certificate verification with the - option ``lenovo_verify_certificate=True``. You may also use the - ``lenovo_verify_certificate_path`` parameter to specify the path to a + option ``driver_ssl_cert_verify = True``. You may also use the + ``driver_ssl_cert_path`` option to specify the path to a CA_BUNDLE file containing CAs other than those in the default list. #. Modify the ``[DEFAULT]`` section of the ``cinder.conf`` file to add an diff --git a/doc/source/configuration/block-storage/drivers/seagate-driver.rst b/doc/source/configuration/block-storage/drivers/seagate-driver.rst new file mode 100644 index 00000000000..7134607b189 --- /dev/null +++ b/doc/source/configuration/block-storage/drivers/seagate-driver.rst @@ -0,0 +1,181 @@ +============================================= +Seagate Array Fibre Channel and iSCSI drivers +============================================= + +The ``STXFCDriver`` and ``STXISCSIDriver`` Cinder drivers allow the +Seagate Technology (STX) storage arrays to be used for Block Storage in +OpenStack deployments. + +System requirements +~~~~~~~~~~~~~~~~~~~ + +To use the Seagate drivers, the following are required: + +- Seagate storage array with: + + - iSCSI or FC host interfaces + - G28x firmware or later + +- Network connectivity between the OpenStack host and the array management + interfaces + +- The HTTPS or HTTP protocol must be enabled on the array + +Supported operations +~~~~~~~~~~~~~~~~~~~~ + +- Create, delete, attach, and detach volumes. +- Create, list, and delete volume snapshots. +- Create a volume from a snapshot. +- Copy an image to a volume. +- Copy a volume to an image. +- Clone a volume. +- Extend a volume. +- Migrate a volume with back-end assistance. +- Retype a volume. +- Manage and unmanage a volume. + +Configuring the array +~~~~~~~~~~~~~~~~~~~~~ + +#. Verify that the array can be managed via an HTTPS connection. HTTP can also + be used if ``driver_use_ssl`` is set to (or defaults to) False + in the ``cinder.conf`` file. + + Confirm that virtual pools A and B are present if you plan to use virtual + pools for OpenStack storage. + + If you plan to use vdisks instead of virtual pools, create or identify one + or more vdisks to be used for OpenStack storage; typically this will mean + creating or setting aside one disk group for each of the A and B + controllers. + +#. Edit the ``cinder.conf`` file to define a storage back-end entry for each + storage pool on the array that will be managed by OpenStack. Each entry + consists of a unique section name, surrounded by square brackets, followed + by options specified in a ``key=value`` format. + + * The ``seagate_pool_name`` value specifies the name of the storage pool + or vdisk on the array. + + * The ``volume_backend_name`` option value can be a unique value, if you + wish to be able to assign volumes to a specific storage pool on the + array, or a name that is shared among multiple storage pools to let the + volume scheduler choose where new volumes are allocated. + +#. The following ``cinder.conf`` options generally have identical values + for each backend section on the array: + + * ``volume_driver`` specifies the Cinder driver name. + + * ``san_ip`` specifies the IP addresses or host names of the array's + management controllers. + + * ``san_login`` and ``san_password`` specify the username and password + of an array user account with ``manage`` privileges + + * ``driver_use_ssl`` must be set to True to enable use of the HTTPS + protocol. + + * ``seagate_iscsi_ips`` specfies the iSCSI IP addresses + for the array if using the iSCSI transport protocol + + In the examples below, two back ends are defined, one for pool A and one for + pool B, and a common ``volume_backend_name`` is used so that a single + volume type definition can be used to allocate volumes from both pools. + + **iSCSI example back-end entries** + + .. code-block:: ini + + [pool-a] + seagate_pool_name = A + volume_backend_name = seagate-array + volume_driver = cinder.volume.drivers.stx.iscsi.STXISCSIDriver + san_ip = 10.1.2.3,10.1.2.4 + san_login = manage + san_password = !manage + seagate_iscsi_ips = 10.2.3.4,10.2.3.5 + driver_use_ssl = true + + [pool-b] + seagate_backend_name = B + volume_backend_name = seagate-array + volume_driver = cinder.volume.drivers.stx.iscsi.STXISCSIDriver + san_ip = 10.1.2.3,10.1.2.4 + san_login = manage + san_password = !manage + seagate_iscsi_ips = 10.2.3.4,10.2.3.5 + driver_use_ssl = true + + **Fibre Channel example back-end entries** + + .. code-block:: ini + + [pool-a] + seagate_backend_name = A + volume_backend_name = seagate-array + volume_driver = cinder.volume.drivers.stx.fc.STXFCDriver + san_ip = 10.1.2.3,10.1.2.4 + san_login = manage + san_password = !manage + driver_use_ssl = true + + [pool-b] + seagate_backend_name = B + volume_backend_name = seagate-array + volume_driver = cinder.volume.drivers.stx.fc.STXFCDriver + san_ip = 10.1.2.3,10.1.2.4 + san_login = manage + san_password = !manage + driver_use_ssl = true + +#. If any ``volume_backend_name`` value refers to a vdisk rather than a + virtual pool, add an additional statement ``seagate_backend_type = linear`` + to that back-end entry. + +#. If HTTPS is enabled, you can enable certificate verification with the option + ``driver_ssl_cert_verify = True``. You may also use the + ``driver_ssl_cert_path`` parameter to specify the path to a + CA\_BUNDLE file containing CAs other than those in the default list. + +#. Modify the ``[DEFAULT]`` section of the ``cinder.conf`` file to add an + ``enabled_backends`` parameter specifying the backend entries you added, + and a ``default_volume_type`` parameter specifying the name of a volume type + that you will create in the next step. + + **Example of [DEFAULT] section changes** + + .. code-block:: ini + + [DEFAULT] + enabled_backends = pool-a,pool-b + default_volume_type = seagate + + +#. Create a new volume type for each distinct ``volume_backend_name`` value + that you added in the ``cinder.conf`` file. The example below assumes that + the same ``volume_backend_name=seagate-array`` option was specified in all + of the entries, and specifies that the volume type ``seagate`` can be used + to allocate volumes from any of them. + + **Example of creating a volume type** + + .. code-block:: console + + $ openstack volume type create seagate + $ openstack volume type set --property volume_backend_name=seagate-array seagate + +#. After modifying the ``cinder.conf`` file, restart the ``cinder-volume`` + service. + +Driver-specific options +~~~~~~~~~~~~~~~~~~~~~~~ + +The following table contains the configuration options that are specific to +the Seagate drivers. + +.. config-table:: + :config-target: Seagate + + cinder.volume.drivers.stx.common diff --git a/doc/source/reference/support-matrix.ini b/doc/source/reference/support-matrix.ini index 857769d488a..ac1d9218beb 100644 --- a/doc/source/reference/support-matrix.ini +++ b/doc/source/reference/support-matrix.ini @@ -162,6 +162,9 @@ title=Quobyte Storage Driver (quobyte) [driver.rbd] title=RBD (Ceph) Storage Driver (RBD) +[driver.seagate] +title=Seagate Driver (iSCSI, FC) + [driver.sheepdog] title=Sheepdog Storage Driver (sheepdog) @@ -251,6 +254,7 @@ driver.pure=complete driver.qnap=complete driver.quobyte=complete driver.rbd=complete +driver.seagate=complete driver.sheepdog=missing driver.storpool=missing driver.synology=complete @@ -316,6 +320,7 @@ driver.pure=complete driver.qnap=complete driver.quobyte=complete driver.rbd=complete +driver.seagate=complete driver.sheepdog=complete driver.storpool=complete driver.synology=complete @@ -381,6 +386,7 @@ driver.pure=missing driver.qnap=missing driver.quobyte=missing driver.rbd=missing +driver.seagate=missing driver.sheepdog=missing driver.storpool=missing driver.synology=missing @@ -449,6 +455,7 @@ driver.pure=missing driver.qnap=missing driver.quobyte=missing driver.rbd=missing +driver.seagate=missing driver.sheepdog=missing driver.storpool=missing driver.synology=missing @@ -516,6 +523,7 @@ driver.pure=complete driver.qnap=missing driver.quobyte=missing driver.rbd=complete +driver.seagate=missing driver.sheepdog=missing driver.storpool=complete driver.synology=missing @@ -584,6 +592,7 @@ driver.pure=complete driver.qnap=missing driver.quobyte=missing driver.rbd=missing +driver.seagate=missing driver.sheepdog=missing driver.storpool=missing driver.synology=missing @@ -651,6 +660,7 @@ driver.pure=complete driver.qnap=missing driver.quobyte=missing driver.rbd=complete +driver.seagate=missing driver.sheepdog=missing driver.storpool=missing driver.synology=missing @@ -719,6 +729,7 @@ driver.pure=missing driver.qnap=missing driver.quobyte=missing driver.rbd=missing +driver.seagate=missing driver.sheepdog=missing driver.storpool=complete driver.synology=missing @@ -787,6 +798,7 @@ driver.pure=complete driver.qnap=missing driver.quobyte=missing driver.rbd=complete +driver.seagate=complete driver.sheepdog=missing driver.storpool=missing driver.synology=missing @@ -852,6 +864,7 @@ driver.pure=missing driver.qnap=missing driver.quobyte=missing driver.rbd=missing +driver.seagate=missing driver.sheepdog=missing driver.storpool=missing driver.synology=missing @@ -921,6 +934,7 @@ driver.pure=missing driver.qnap=missing driver.quobyte=missing driver.rbd=complete +driver.seagate=missing driver.sheepdog=missing driver.storpool=missing driver.synology=missing diff --git a/releasenotes/notes/hpmsa-driver-updates-train-4fcbe71f3e2bb2da.yaml b/releasenotes/notes/hpmsa-driver-updates-train-4fcbe71f3e2bb2da.yaml new file mode 100644 index 00000000000..2bfb21afaf7 --- /dev/null +++ b/releasenotes/notes/hpmsa-driver-updates-train-4fcbe71f3e2bb2da.yaml @@ -0,0 +1,29 @@ +--- +upgrade: + - | + The HPE MSA driver options ``hpmsa_backend_name`` and ``hpmsa_backend_type`` + options were deprecated in favor of ``hpmsa_pool_name`` and + ``hpmsa_pool_type`` to avoid confusion, and the + ``hpmsa_api_protocol``, ``hpmsa_verify_certificate``, and + ``hpmsa_verify_certificate_path`` options were deprecated in favor of + the standard ``driver_use_ssl``, ``driver_ssl_cert_verify``, and + ``driver_ssl_cert_path`` options. To retain the default behavior, add + ``driver_use_ssl = true`` to back-end entries in ``cinder.conf`` + before the deprecated options are removed in a future release. + +deprecations: + - | + The HPE MSA driver options ``hpmsa_backend_name`` and ``hpmsa_backend_type`` + options were deprecated in favor of ``hpmsa_pool_name`` and + ``hpmsa_pool_type`` to avoid confusion, and the + ``hpmsa_api_protocol``, ``hpmsa_verify_certificate``, and + ``hpmsa_verify_certificate_path`` options were deprecated in favor of + the standard ``driver_use_ssl``, ``driver_ssl_cert_verify``, and + ``driver_ssl_cert_path`` options. To retain the default behavior, add + ``driver_use_ssl = true`` to back-end entries in ``cinder.conf`` + before the deprecated options are removed in a future release. + +fixes: + - | + Fixed HPE MSA driver issue where a multi-attached volume could be + unmapped while still in use. diff --git a/releasenotes/notes/lenovo-driver-updates-train-f2ff96ca4a2885db.yaml b/releasenotes/notes/lenovo-driver-updates-train-f2ff96ca4a2885db.yaml new file mode 100644 index 00000000000..cf996627fd4 --- /dev/null +++ b/releasenotes/notes/lenovo-driver-updates-train-f2ff96ca4a2885db.yaml @@ -0,0 +1,29 @@ +--- +upgrade: + - | + The Lenovo driver options ``lenovo_backend_name`` and ``lenovo_backend_type`` + options were deprecated in favor of ``lenovo_pool_name`` and + ``lenovo_pool_type`` to avoid confusion, and the + ``lenovo_api_protocol``, ``lenovo_verify_certificate``, and + ``lenovo_verify_certificate_path`` options were deprecated in favor of + the standard ``driver_use_ssl``, ``driver_ssl_cert_verify``, and + ``driver_ssl_cert_path`` options. To retain the default behavior, add + ``driver_use_ssl = true`` to back-end entries in ``cinder.conf`` + before the deprecated options are removed in a future release. + +deprecations: + - | + The Lenovo driver options ``lenovo_backend_name`` and ``lenovo_backend_type`` + options were deprecated in favor of ``lenovo_pool_name`` and + ``lenovo_pool_type`` to avoid confusion, and the + ``lenovo_api_protocol``, ``lenovo_verify_certificate``, and + ``lenovo_verify_certificate_path`` options were deprecated in favor of + the standard ``driver_use_ssl``, ``driver_ssl_cert_verify``, and + ``driver_ssl_cert_path`` options. To retain the default behavior, add + ``driver_use_ssl = true`` to back-end entries in ``cinder.conf`` + before the deprecated options are removed in a future release. + +fixes: + - | + Fixed Lenovo driver issue where a multi-attached volume could be + unmapped while still in use. diff --git a/releasenotes/notes/seagate-new-driver-d420fad549e9045f.yaml b/releasenotes/notes/seagate-new-driver-d420fad549e9045f.yaml new file mode 100644 index 00000000000..02f9969d050 --- /dev/null +++ b/releasenotes/notes/seagate-new-driver-d420fad549e9045f.yaml @@ -0,0 +1,3 @@ +--- +features: + - New Cinder driver for Seagate FC and iSCSI storage arrays.