diff --git a/cinder/opts.py b/cinder/opts.py index faa026cc6a6..62e1bd1b37c 100644 --- a/cinder/opts.py +++ b/cinder/opts.py @@ -146,8 +146,6 @@ 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 \ - cinder_volume_drivers_veritas_access_veritasiscsi from cinder.volume.drivers.vmware import vmdk as \ cinder_volume_drivers_vmware_vmdk from cinder.volume.drivers.windows import iscsi as \ @@ -254,7 +252,6 @@ def list_opts(): instorage_mcs_opts, cinder_volume_drivers_inspur_instorage_instorageiscsi. instorage_mcs_iscsi_opts, - cinder_volume_drivers_veritas_access_veritasiscsi.VA_VOL_OPTS, cinder_volume_manager.volume_manager_opts, cinder_wsgi_eventletserver.socket_opts, )), diff --git a/cinder/tests/unit/volume/drivers/veritas_access/__init__.py b/cinder/tests/unit/volume/drivers/veritas_access/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/cinder/tests/unit/volume/drivers/veritas_access/test_veritas_iscsi.py b/cinder/tests/unit/volume/drivers/veritas_access/test_veritas_iscsi.py deleted file mode 100644 index 9945f42f0ec..00000000000 --- a/cinder/tests/unit/volume/drivers/veritas_access/test_veritas_iscsi.py +++ /dev/null @@ -1,659 +0,0 @@ -# Copyright 2017 Veritas Technologies LLC. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -""" -Unit tests for Veritas Access cinder driver. -""" -import hashlib -import json -import tempfile -from unittest import mock -from xml.dom.minidom import Document - -from oslo_config import cfg -import requests - -from cinder import context -from cinder import exception -from cinder import test -from cinder.volume import configuration as conf -from cinder.volume.drivers.veritas_access import veritas_iscsi - -CONF = cfg.CONF -FAKE_BACKEND = 'fake_backend' - - -class MockResponse(object): - def __init__(self): - self.status_code = 200 - - def json(self): - data = {'fake_key': 'fake_val'} - return json.dumps(data) - - -class FakeXML(object): - - def __init__(self): - self.tempdir = tempfile.mkdtemp() - - def create_vrts_fake_config_file(self): - - target = 'iqn.2017-02.com.veritas:faketarget' - portal = '1.1.1.1' - auth_detail = '0' - doc = Document() - - vrts_node = doc.createElement("VRTS") - doc.appendChild(vrts_node) - - vrts_target_node = doc.createElement("VrtsTargets") - vrts_node.appendChild(vrts_target_node) - - target_node = doc.createElement("Target") - - vrts_target_node.appendChild(target_node) - - name_ele = doc.createElement("Name") - portal_ele = doc.createElement("PortalIP") - auth_ele = doc.createElement("Authentication") - - name_ele.appendChild(doc.createTextNode(target)) - portal_ele.appendChild(doc.createTextNode(portal)) - auth_ele.appendChild(doc.createTextNode(auth_detail)) - - target_node.appendChild(name_ele) - target_node.appendChild(portal_ele) - target_node.appendChild(auth_ele) - - filename = 'vrts_config.xml' - config_file_path = self.tempdir + '/' + filename - - f = open(config_file_path, 'w') - doc.writexml(f) - f.close() - return config_file_path - - -class fake_volume(object): - def __init__(self): - self.id = 'fakeid' - self.name = 'fakename' - self.size = 1 - self.snapshot_id = False - self.metadata = {'dense': True} - - -class fake_volume2(object): - def __init__(self): - self.id = 'fakeid2' - self.name = 'fakename2' - self.size = 2 - self.snapshot_id = False - self.metadata = {'dense': True} - - -class fake_clone_volume(object): - def __init__(self): - self.id = 'fakecloneid' - self.name = 'fakeclonename' - self.size = 1 - self.snapshot_id = False - - -class fake_clone_volume2(object): - def __init__(self): - self.id = 'fakecloneid2' - self.name = 'fakeclonename' - self.size = 2 - self.snapshot_id = False - - -class fake_snapshot(object): - def __init__(self): - self.id = 'fakeid' - self.volume_id = 'fakevolumeid' - self.volume_size = 1 - - -class ACCESSIscsiDriverTestCase(test.TestCase): - """Tests ACCESSShareDriver.""" - - volume = fake_volume() - volume2 = fake_volume2() - snapshot = fake_snapshot() - clone_volume = fake_clone_volume() - clone_volume2 = fake_clone_volume2() - connector = { - 'initiator': 'iqn.1994-05.com.fakeinitiator' - } - - def setUp(self): - super(ACCESSIscsiDriverTestCase, self).setUp() - self._create_fake_config() - lcfg = self.configuration - self._context = context.get_admin_context() - self._driver = veritas_iscsi.ACCESSIscsiDriver(configuration=lcfg) - self._driver.do_setup(self._context) - - def _create_fake_config(self): - self.mock_object(veritas_iscsi.ACCESSIscsiDriver, - '_authenticate_access') - self.configuration = mock.Mock(spec=conf.Configuration) - self.configuration.safe_get = self.fake_safe_get - self.configuration.san_ip = '1.1.1.1' - self.configuration.san_login = 'user' - self.configuration.san_password = 'passwd' - self.configuration.san_api_port = 14161 - self.configuration.vrts_lun_sparse = True - self.configuration.vrts_target_config = ( - FakeXML().create_vrts_fake_config_file()) - self.configuration.target_port = 3260 - self.configuration.volume_backend_name = FAKE_BACKEND - - def fake_safe_get(self, value): - try: - val = getattr(self.configuration, value) - except AttributeError: - val = None - return val - - def test_create_volume(self): - self.mock_object(self._driver, '_vrts_get_suitable_target') - self.mock_object(self._driver, '_vrts_get_targets_store') - self.mock_object(self._driver, '_access_api') - - mylist = [] - target = {} - target['name'] = 'iqn.2017-02.com.veritas:faketarget' - target['portal_ip'] = '1.1.1.1' - target['auth'] = '0' - mylist.append(target) - - self._driver._vrts_get_suitable_target.return_value = ( - 'iqn.2017-02.com.veritas:faketarget') - self._driver._access_api.return_value = True - return_list = self._driver._vrts_parse_xml_file( - self.configuration.vrts_target_config) - - self._driver.create_volume(self.volume) - - self.assertEqual(mylist, return_list) - self.assertEqual(1, self._driver._access_api.call_count) - - def test_create_volume_negative(self): - self.mock_object(self._driver, '_vrts_get_suitable_target') - self.mock_object(self._driver, '_vrts_get_targets_store') - self.mock_object(self._driver, '_access_api') - - self._driver._vrts_get_suitable_target.return_value = ( - 'iqn.2017-02.com.veritas:faketarget') - self._driver._access_api.return_value = False - - self.assertRaises(exception.VolumeBackendAPIException, - self._driver.create_volume, - self.volume) - - def test_create_volume_negative_no_suitable_target_found(self): - self.mock_object(self._driver, '_vrts_get_suitable_target') - self.mock_object(self._driver, '_access_api') - - self._driver._vrts_get_suitable_target.return_value = False - - self.assertRaises(exception.VolumeBackendAPIException, - self._driver.create_volume, - self.volume) - self.assertEqual(0, self._driver._access_api.call_count) - - def test_delete_volume(self): - self.mock_object(self._driver, '_get_vrts_lun_list') - self.mock_object(self._driver, '_access_api') - - va_lun_name = self._driver._get_va_lun_name(self.volume.id) - - length = len(self.volume.id) - index = int(length / 2) - name1 = self.volume.id[:index] - name2 = self.volume.id[index:] - crc1 = hashlib.md5(name1.encode('utf-8')).hexdigest()[:5] - crc2 = hashlib.md5(name2.encode('utf-8')).hexdigest()[:5] - - volume_name_to_ret = 'cinder' + '-' + crc1 + '-' + crc2 - - lun = {} - lun['lun_name'] = va_lun_name - lun['target_name'] = 'iqn.2017-02.com.veritas:faketarget' - lun_list = {'output': {'output': {'luns': [lun]}}} - self._driver._get_vrts_lun_list.return_value = lun_list - - self._driver._access_api.return_value = True - - self._driver.delete_volume(self.volume) - self.assertEqual(volume_name_to_ret, va_lun_name) - self.assertEqual(1, self._driver._access_api.call_count) - - def test_delete_volume_negative(self): - self.mock_object(self._driver, '_get_vrts_lun_list') - self.mock_object(self._driver, '_access_api') - - self._driver._access_api.return_value = False - - self.assertRaises(exception.VolumeBackendAPIException, - self._driver.delete_volume, - self.volume) - - def test_create_snapshot(self): - self.mock_object(self._driver, '_access_api') - - self._driver._access_api.return_value = True - - self._driver.create_snapshot(self.snapshot) - self.assertEqual(1, self._driver._access_api.call_count) - - def test_create_snapshot_negative(self): - self.mock_object(self._driver, '_access_api') - - self._driver._access_api.return_value = False - - self.assertRaises(exception.VolumeBackendAPIException, - self._driver.create_snapshot, - self.snapshot) - - self.assertEqual(1, self._driver._access_api.call_count) - - def test_delete_snapshot(self): - self.mock_object(self._driver, '_access_api') - - self._driver._access_api.return_value = True - - self._driver.delete_snapshot(self.snapshot) - self.assertEqual(1, self._driver._access_api.call_count) - - def test_delete_snapshot_negative(self): - self.mock_object(self._driver, '_access_api') - - self._driver._access_api.return_value = False - - self.assertRaises(exception.VolumeBackendAPIException, - self._driver.delete_snapshot, - self.snapshot) - - self.assertEqual(1, self._driver._access_api.call_count) - - def test_create_cloned_volume(self): - self.mock_object(self._driver, '_access_api') - self.mock_object(self._driver, '_vrts_extend_lun') - self.mock_object(self._driver, '_get_vrts_lun_list') - self.mock_object(self._driver, '_vrts_get_fs_list') - self.mock_object(self._driver, '_vrts_is_space_available_in_store') - - va_lun_name = self._driver._get_va_lun_name(self.volume.id) - - lun = {} - lun['lun_name'] = va_lun_name - lun['fs_name'] = 'fake_fs' - lun['target_name'] = 'iqn.2017-02.com.veritas:faketarget' - lun_list = {'output': {'output': {'luns': [lun]}}} - - self._driver._get_vrts_lun_list.return_value = lun_list - - self._driver._vrts_is_space_available_in_store.return_value = True - - self._driver._access_api.return_value = True - - self._driver.create_cloned_volume(self.clone_volume, self.volume) - self.assertEqual(1, self._driver._access_api.call_count) - self.assertEqual(0, self._driver._vrts_extend_lun.call_count) - - def test_create_cloned_volume_of_greater_size(self): - self.mock_object(self._driver, '_access_api') - self.mock_object(self._driver, '_vrts_extend_lun') - self.mock_object(self._driver, '_get_vrts_lun_list') - self.mock_object(self._driver, '_vrts_get_fs_list') - self.mock_object(self._driver, '_vrts_is_space_available_in_store') - - va_lun_name = self._driver._get_va_lun_name(self.volume.id) - - lun = {} - lun['lun_name'] = va_lun_name - lun['fs_name'] = 'fake_fs' - lun['target_name'] = 'iqn.2017-02.com.veritas:faketarget' - lun_list = {'output': {'output': {'luns': [lun]}}} - - self._driver._get_vrts_lun_list.return_value = lun_list - - self._driver._vrts_is_space_available_in_store.return_value = True - - self._driver._access_api.return_value = True - - self._driver.create_cloned_volume(self.clone_volume2, self.volume) - self.assertEqual(1, self._driver._access_api.call_count) - self.assertEqual(1, self._driver._vrts_extend_lun.call_count) - - def test_create_cloned_volume_negative(self): - self.mock_object(self._driver, '_access_api') - self.mock_object(self._driver, '_get_vrts_lun_list') - self.mock_object(self._driver, '_vrts_get_fs_list') - self.mock_object(self._driver, '_vrts_is_space_available_in_store') - - va_lun_name = self._driver._get_va_lun_name(self.volume.id) - - lun = {} - lun['lun_name'] = va_lun_name - lun['fs_name'] = 'fake_fs' - lun['target_name'] = 'iqn.2017-02.com.veritas:faketarget' - lun_list = {'output': {'output': {'luns': [lun]}}} - - self._driver._get_vrts_lun_list.return_value = lun_list - - self._driver._vrts_is_space_available_in_store.return_value = True - - self._driver._access_api.return_value = False - - self.assertRaises(exception.VolumeBackendAPIException, - self._driver.create_cloned_volume, - self.clone_volume, self.volume) - - self.assertEqual(1, self._driver._access_api.call_count) - - def test_create_volume_from_snapshot(self): - self.mock_object(self._driver, '_access_api') - self.mock_object(self._driver, '_vrts_extend_lun') - self.mock_object(self._driver, '_vrts_get_targets_store') - self.mock_object(self._driver, '_vrts_get_assigned_store') - self.mock_object(self._driver, '_vrts_get_fs_list') - self.mock_object(self._driver, '_vrts_is_space_available_in_store') - - snap_name = self._driver._get_va_lun_name(self.snapshot.id) - - snap = {} - snap['snapshot_name'] = snap_name - snap['target_name'] = 'fake_target' - - snapshots = [] - snapshots.append(snap) - - snap_info = {} - snap_info['output'] = {'output': {'snapshots': snapshots}} - - self._driver._access_api.return_value = snap_info - - self._driver._vrts_is_space_available_in_store.return_value = True - - self._driver.create_volume_from_snapshot(self.volume, self.snapshot) - self.assertEqual(2, self._driver._access_api.call_count) - self.assertEqual(0, self._driver._vrts_extend_lun.call_count) - - def test_create_volume_from_snapshot_of_greater_size(self): - self.mock_object(self._driver, '_access_api') - self.mock_object(self._driver, '_vrts_extend_lun') - self.mock_object(self._driver, '_vrts_get_targets_store') - self.mock_object(self._driver, '_vrts_get_assigned_store') - self.mock_object(self._driver, '_vrts_get_fs_list') - self.mock_object(self._driver, '_vrts_is_space_available_in_store') - - snap_name = self._driver._get_va_lun_name(self.snapshot.id) - - snap = {} - snap['snapshot_name'] = snap_name - snap['target_name'] = 'fake_target' - - snapshots = [] - snapshots.append(snap) - - snap_info = {} - snap_info['output'] = {'output': {'snapshots': snapshots}} - - self._driver._access_api.return_value = snap_info - - self._driver._vrts_is_space_available_in_store.return_value = True - - self._driver.create_volume_from_snapshot(self.volume2, self.snapshot) - self.assertEqual(2, self._driver._access_api.call_count) - self.assertEqual(1, self._driver._vrts_extend_lun.call_count) - - def test_create_volume_from_snapshot_negative(self): - self.mock_object(self._driver, '_access_api') - self.mock_object(self._driver, '_vrts_get_targets_store') - - snap = {} - snap['snapshot_name'] = 'fake_snap_name' - snap['target_name'] = 'fake_target' - - snapshots = [] - snapshots.append(snap) - - snap_info = {} - snap_info['output'] = {'output': {'snapshots': snapshots}} - - self._driver._access_api.return_value = snap_info - - self.assertRaises(exception.VolumeBackendAPIException, - self._driver.create_volume_from_snapshot, - self.volume, self.snapshot) - - self.assertEqual(1, self._driver._access_api.call_count) - self.assertEqual(0, self._driver._vrts_get_targets_store.call_count) - - def test_extend_volume(self): - self.mock_object(self._driver, '_access_api') - self.mock_object(self._driver, '_get_vrts_lun_list') - self.mock_object(self._driver, '_vrts_get_fs_list') - self.mock_object(self._driver, '_vrts_is_space_available_in_store') - - va_lun_name = self._driver._get_va_lun_name(self.volume.id) - - lun = {} - lun['lun_name'] = va_lun_name - lun['fs_name'] = 'fake_fs' - lun['target_name'] = 'iqn.2017-02.com.veritas:faketarget' - lun_list = {'output': {'output': {'luns': [lun]}}} - - self._driver._get_vrts_lun_list.return_value = lun_list - self._driver._vrts_is_space_available_in_store.return_value = True - - self._driver._access_api.return_value = True - - self._driver.extend_volume(self.volume, 2) - self.assertEqual(1, self._driver._access_api.call_count) - - def test_extend_volume_negative(self): - self.mock_object(self._driver, '_access_api') - self.mock_object(self._driver, '_get_vrts_lun_list') - self.mock_object(self._driver, '_vrts_get_fs_list') - self.mock_object(self._driver, '_vrts_is_space_available_in_store') - - va_lun_name = self._driver._get_va_lun_name(self.volume.id) - - lun = {} - lun['lun_name'] = va_lun_name - lun['fs_name'] = 'fake_fs' - lun['target_name'] = 'iqn.2017-02.com.veritas:faketarget' - lun_list = {'output': {'output': {'luns': [lun]}}} - - self._driver._get_vrts_lun_list.return_value = lun_list - self._driver._vrts_is_space_available_in_store.return_value = True - - self._driver._access_api.return_value = False - - self.assertRaises(exception.VolumeBackendAPIException, - self._driver.extend_volume, self.volume, 2) - self.assertEqual(1, self._driver._vrts_get_fs_list.call_count) - self.assertEqual(1, self._driver._access_api.call_count) - - def test_extend_volume_negative_not_volume_found(self): - self.mock_object(self._driver, '_access_api') - self.mock_object(self._driver, '_get_vrts_lun_list') - self.mock_object(self._driver, '_vrts_get_fs_list') - - lun = {} - lun['lun_name'] = 'fake_lun' - lun['fs_name'] = 'fake_fs' - lun['target_name'] = 'iqn.2017-02.com.veritas:faketarget' - lun_list = {'output': {'output': {'luns': [lun]}}} - - self._driver._get_vrts_lun_list.return_value = lun_list - - self.assertRaises(exception.VolumeBackendAPIException, - self._driver.extend_volume, self.volume, 2) - - self.assertEqual(0, self._driver._vrts_get_fs_list.call_count) - self.assertEqual(0, self._driver._access_api.call_count) - - def test_initialize_connection(self): - self.mock_object(self._driver, '_access_api') - self.mock_object(self._driver, '_get_vrts_lun_list') - self.mock_object(self._driver, '_vrts_target_initiator_mapping') - self.mock_object(self._driver, '_vrts_get_iscsi_properties') - - va_lun_name = self._driver._get_va_lun_name(self.volume.id) - - lun = {} - lun['lun_name'] = va_lun_name - lun['target_name'] = 'iqn.2017-02.com.veritas:faketarget' - lun_list = {'output': {'output': {'luns': [lun]}}} - - self._driver._get_vrts_lun_list.return_value = lun_list - self._driver._access_api.return_value = True - self._driver.initialize_connection(self.volume, self.connector) - self.assertEqual(1, self._driver._vrts_get_iscsi_properties.call_count) - - def test_initialize_connection_negative(self): - self.mock_object(self._driver, '_access_api') - self.mock_object(self._driver, '_get_vrts_lun_list') - self.mock_object(self._driver, '_vrts_target_initiator_mapping') - self.mock_object(self._driver, '_vrts_get_iscsi_properties') - - lun = {} - lun['lun_name'] = 'fakelun' - lun['target_name'] = 'iqn.2017-02.com.veritas:faketarget' - lun_list = {'output': {'output': {'luns': [lun]}}} - self._driver.LUN_FOUND_INTERVAL = 5 - - self._driver._get_vrts_lun_list.return_value = lun_list - self._driver._access_api.return_value = True - - self.assertRaises(exception.VolumeBackendAPIException, - self._driver.initialize_connection, self.volume, - self.connector) - - self.assertEqual( - 0, self._driver._vrts_target_initiator_mapping.call_count) - self.assertEqual(0, self._driver._vrts_get_iscsi_properties.call_count) - - def test___vrts_get_iscsi_properties(self): - self.mock_object(self._driver, '_access_api') - - va_lun_name = self._driver._get_va_lun_name(self.volume.id) - storage_object = "'/fakestores/fakeio/" + va_lun_name + "'" - - lun_id_list = {} - lun_id_list['output'] = ("[{'storage_object': " + - storage_object + ", 'index': '1'}]") - - target_name = 'iqn.2017-02.com.veritas:faketarget' - - self._driver._access_api.return_value = lun_id_list - - iscsi_properties_ret_value = {} - iscsi_properties_ret_value['target_discovered'] = True - iscsi_properties_ret_value['target_iqn'] = target_name - iscsi_properties_ret_value['target_portal'] = '1.1.1.1:3260' - iscsi_properties_ret_value['target_lun'] = 1 - iscsi_properties_ret_value['volume_id'] = 'fakeid' - iscsi_properties = self._driver._vrts_get_iscsi_properties(self.volume, - target_name) - - self.assertEqual(iscsi_properties_ret_value, iscsi_properties) - - def test__access_api(self): - self.mock_object(requests, 'session') - - provider = '%s:%s' % (self._driver._va_ip, self._driver._port) - path = '/fake/path' - input_data = {} - mock_response = MockResponse() - session = requests.session - - data = {'fake_key': 'fake_val'} - json_data = json.dumps(data) - - session.request.return_value = mock_response - ret_value = self._driver._access_api(session, provider, path, - json.dumps(input_data), 'GET') - - self.assertEqual(json_data, ret_value) - - def test__access_api_negative(self): - session = self._driver.session - provider = '%s:%s' % (self._driver._va_ip, self._driver._port) - path = '/fake/path' - input_data = {} - ret_value = self._driver._access_api(session, provider, path, - json.dumps(input_data), 'GET') - self.assertEqual(False, ret_value) - - def test__get_api(self): - provider = '%s:%s' % (self._driver._va_ip, self._driver._port) - tail = '/fake/path' - ret = self._driver._get_api(provider, tail) - - api_root = 'https://%s/api/access' % (provider) - to_be_ret = api_root + tail - self.assertEqual(to_be_ret, ret) - - def test__vrts_target_initiator_mapping_negative(self): - self.mock_object(self._driver, '_access_api') - target_name = 'fake_target' - initiator_name = 'fake_initiator' - - self._driver._access_api.return_value = False - self.assertRaises(exception.VolumeBackendAPIException, - self._driver._vrts_target_initiator_mapping, - target_name, initiator_name) - - def test_get_volume_stats(self): - self.mock_object(self._driver, '_authenticate_access') - self.mock_object(self._driver, '_vrts_get_targets_store') - self.mock_object(self._driver, '_vrts_get_fs_list') - - target_list = [] - target_details = {} - target_details['fs_list'] = ['fs1'] - target_details['wwn'] = 'iqn.2017-02.com.veritas:faketarget' - target_list.append(target_details) - - self._driver._vrts_get_targets_store.return_value = target_list - - fs_list = [] - fs_dict = {} - fs_dict['name'] = 'fs1' - fs_dict['file_storage_capacity'] = 10737418240 - fs_dict['file_storage_used'] = 1073741824 - fs_list.append(fs_dict) - - self._driver._vrts_get_fs_list.return_value = fs_list - - self._driver.get_volume_stats() - data = { - 'volume_backend_name': FAKE_BACKEND, - 'vendor_name': 'Veritas', - 'driver_version': '1.0', - 'storage_protocol': 'iSCSI', - 'total_capacity_gb': 10, - 'free_capacity_gb': 9, - 'reserved_percentage': 0, - 'thin_provisioning_support': True - } - - self.assertEqual(data, self._driver._stats) diff --git a/cinder/volume/drivers/veritas_access/__init__.py b/cinder/volume/drivers/veritas_access/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/cinder/volume/drivers/veritas_access/veritas_iscsi.py b/cinder/volume/drivers/veritas_access/veritas_iscsi.py deleted file mode 100644 index a659e0f3757..00000000000 --- a/cinder/volume/drivers/veritas_access/veritas_iscsi.py +++ /dev/null @@ -1,898 +0,0 @@ -# Copyright 2017 Veritas Technologies LLC. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -""" -Veritas Access Driver for ISCSI. - -""" -import ast -import hashlib -import json -from random import randint - -from defusedxml import minidom -from oslo_config import cfg -from oslo_log import log as logging -from oslo_service import loopingcall -from oslo_utils import netutils -from oslo_utils import strutils -from oslo_utils import units -import requests -import requests.auth -from six.moves import http_client - -from cinder import exception -from cinder.i18n import _ -from cinder import interface -from cinder.volume import driver -from cinder.volume.drivers.san import san - -LOG = logging.getLogger(__name__) - - -VA_VOL_OPTS = [ - cfg.BoolOpt('vrts_lun_sparse', - default=True, - help='Create sparse Lun.'), - cfg.StrOpt('vrts_target_config', - default='/etc/cinder/vrts_target.xml', - help='VA config file.') -] - - -CONF = cfg.CONF -CONF.register_opts(VA_VOL_OPTS) - - -class NoAuth(requests.auth.AuthBase): - """This is a 'authentication' handler. - - It exists for use with custom authentication systems, such as the - one for the Access API, it simply passes the Authorization header as-is. - - The default authentication handler for requests will clobber the - Authorization header. - """ - - def __call__(self, r): - return r - - -@interface.volumedriver -class ACCESSIscsiDriver(driver.ISCSIDriver): - """ACCESS Share Driver. - - Executes commands relating to ACCESS ISCSI. - Supports creation of volumes on ACCESS. - - .. code-block:: none - - API version history: - - 1.0 - Initial version. - """ - - VERSION = "1.0" - # ThirdPartySytems wiki page - CI_WIKI_NAME = "Veritas_Access_CI" - DRIVER_VOLUME_TYPE = 'iSCSI' - LUN_FOUND_INTERVAL = 30 # seconds - - # TODO(jsbryant) Remove driver in the 'U' release if CI is not fixed. - SUPPORTED = False - - def __init__(self, *args, **kwargs): - # Parent sets db, host, _execute and base config - super(ACCESSIscsiDriver, self).__init__(*args, **kwargs) - - self._va_ip = None - self._port = None - self._user = None - self._pwd = None - self.iscsi_port = None - self._fs_list_str = '/fs' - self._target_list_str = '/iscsi/target/list' - self._target_status = '/iscsi/target/status' - self._lun_create_str = '/iscsi/lun/create' - self._lun_destroy_str = '/iscsi/lun/destroy' - self._lun_list_str = '/iscsi/lun/list' - self._lun_create_from_snap_str = '/iscsi/lun_from_snap/create' - self._snapshot_create_str = '/iscsi/lun/snapshot/create' - self._snapshot_destroy_str = '/iscsi/lun/snapshot/destroy' - self._snapshot_list_str = '/iscsi/lun/snapshot/list' - self._lun_clone_create_str = '/iscsi/lun/clone/create' - self._lun_extend_str = '/iscsi/lun/growto' - self._lun_shrink_str = '/iscsi/lun/shrinkto' - self._lun_getid_str = '/iscsi/lun/getlunid' - self._target_map_str = '/iscsi/target/map/add' - self._target_list_status = '/iscsi/target/full_list' - - self.configuration.append_config_values(VA_VOL_OPTS) - self.configuration.append_config_values(san.san_opts) - self.backend_name = (self.configuration.safe_get('volume_' - 'backend_name') or - 'ACCESS_ISCSI') - self.verify = (self.configuration. - safe_get('driver_ssl_cert_verify') or False) - - if self.verify: - verify_path = (self.configuration. - safe_get('driver_ssl_cert_path') or None) - if verify_path: - self.verify = verify_path - - @staticmethod - def get_driver_options(): - return VA_VOL_OPTS - - def do_setup(self, context): - """Any initialization the volume driver does while starting.""" - super(ACCESSIscsiDriver, self).do_setup(context) - - required_config = ['san_ip', - 'san_login', - 'san_password', - 'san_api_port'] - - for attr in required_config: - if not getattr(self.configuration, attr, None): - message = (_('config option %s is not set.') % attr) - raise exception.InvalidInput(message=message) - - self._va_ip = self.configuration.san_ip - self._user = self.configuration.san_login - self._pwd = self.configuration.san_password - self._port = self.configuration.san_api_port - self._sparse_lun_support = self.configuration.vrts_lun_sparse - self.target_info_file = self.configuration.vrts_target_config - self.iscsi_port = self.configuration.target_port - self.session = self._authenticate_access(self._va_ip, self._user, - self._pwd) - - def _get_va_lun_name(self, name): - length = len(name) - index = int(length / 2) - name1 = name[:index] - name2 = name[index:] - crc1 = hashlib.md5(name1.encode('utf-8')).hexdigest()[:5] - crc2 = hashlib.md5(name2.encode('utf-8')).hexdigest()[:5] - return 'cinder' + '-' + crc1 + '-' + crc2 - - def check_for_setup_error(self): - """Check if veritas access target is online.""" - target_list = self._vrts_parse_xml_file(self.target_info_file) - if not self._vrts_get_online_targets(target_list): - message = ('ACCESSIscsiDriver setup error as ' - 'no target is online') - raise exception.VolumeBackendAPIException(message=message) - - def create_export(self, context, volume, connector): - """Driver entry point to get the export info for a new volume.""" - pass - - def remove_export(self, context, volume): - """Driver entry point to remove an export for a volume.""" - pass - - def ensure_export(self, context, volume): - """Driver entry point to get the export info for an existing volume.""" - pass - - def _vrts_get_iscsi_properties(self, volume, target_name): - """Get target and LUN details.""" - lun_name = self._get_va_lun_name(volume.id) - - data = {} - path = self._lun_getid_str - provider = '%s:%s' % (self._va_ip, self._port) - - lun_id_list = self._access_api(self.session, provider, path, - json.dumps(data), 'GET') - - if not lun_id_list: - message = _('ACCESSIscsiDriver get LUN ID list ' - 'operation failed') - LOG.error(message) - raise exception.VolumeBackendAPIException(message=message) - - for lun in ast.literal_eval(lun_id_list['output']): - vrts_lun_name = lun['storage_object'].split('/')[3] - if vrts_lun_name == lun_name: - lun_id = int(lun['index']) - - target_list = self._vrts_parse_xml_file(self.target_info_file) - authentication = False - portal_ip = "" - - for target in target_list: - if target_name == target['name']: - portal_ip = target['portal_ip'] - if target['auth'] == '1': - auth_user = target['auth_user'] - auth_password = target['auth_password'] - authentication = True - break - - if portal_ip == "": - message = (_('ACCESSIscsiDriver initialize_connection ' - 'failed for %s as no portal ip was found') - % volume.id) - LOG.error(message) - raise exception.VolumeBackendAPIException(message=message) - - portal_list = portal_ip.split(',') - - target_portal_list = [] - for ip in portal_list: - if netutils.is_valid_ipv6(ip): - target_portal_list.append('[%s]:%s' % (ip, - str(self.iscsi_port))) - else: - target_portal_list.append('%s:%s' % (ip, str(self.iscsi_port))) - - iscsi_properties = {} - iscsi_properties['target_discovered'] = True - iscsi_properties['target_iqn'] = target_name - iscsi_properties['target_portal'] = target_portal_list[0] - if len(target_portal_list) > 1: - iscsi_properties['target_portals'] = target_portal_list - iscsi_properties['target_lun'] = lun_id - iscsi_properties['volume_id'] = volume.id - if authentication: - iscsi_properties['auth_username'] = auth_user - iscsi_properties['auth_password'] = auth_password - iscsi_properties['auth_method'] = 'CHAP' - - return iscsi_properties - - def _get_vrts_lun_list(self): - """Get Lun list.""" - data = {} - path = self._lun_list_str - provider = '%s:%s' % (self._va_ip, self._port) - - lun_list = self._access_api(self.session, provider, path, - json.dumps(data), 'GET') - - if not lun_list: - message = _('ACCESSIscsiDriver get LUN list ' - 'operation failed') - LOG.error(message) - raise exception.VolumeBackendAPIException(message=message) - - return lun_list - - def _vrts_target_initiator_mapping(self, target_name, initiator_name): - """Map target to initiator.""" - path = self._target_map_str - provider = '%s:%s' % (self._va_ip, self._port) - - data = {} - data["target_name"] = target_name - data["initiator_name"] = initiator_name - - result = self._access_api(self.session, provider, path, - json.dumps(data), 'POST') - - if not result: - message = (_('ACCESSIscsiDriver target-initiator mapping ' - 'failed for target %s') - % target_name) - LOG.error(message) - raise exception.VolumeBackendAPIException(message=message) - - def initialize_connection(self, volume, connector, initiator_data=None): - """Initializes the connection and returns connection info. - - The iscsi driver returns a driver_volume_type of 'iscsi'. - the format of the driver data is defined in _vrts_get_iscsi_properties. - Example return value:: - - { - 'driver_volume_type': 'iscsi' - 'data': { - 'target_discovered': True, - 'target_iqn': 'iqn.2010-10.org.openstack:volume-00000001', - 'target_portal': '127.0.0.0.1:3260', - 'target_lun': 1, - 'volume_id': '12345678-1234-4321-1234-123456789012', - } - } - """ - lun_name = self._get_va_lun_name(volume.id) - target = {'target_name': ''} - - def _inner(): - lun_list = self._get_vrts_lun_list() - for lun in lun_list['output']['output']['luns']: - if lun['lun_name'] == lun_name: - target['target_name'] = lun['target_name'] - raise loopingcall.LoopingCallDone() - - timer = loopingcall.FixedIntervalWithTimeoutLoopingCall(_inner) - try: - timer.start(interval=5, timeout=self.LUN_FOUND_INTERVAL).wait() - except loopingcall.LoopingCallTimeOut: - message = (_('ACCESSIscsiDriver initialize_connection ' - 'failed for %s as no target was found') - % volume.id) - - LOG.error(message) - raise exception.VolumeBackendAPIException(message=message) - - self._vrts_target_initiator_mapping(target['target_name'], - connector['initiator']) - - iscsi_properties = self._vrts_get_iscsi_properties( - volume, target['target_name']) - - return { - 'driver_volume_type': 'iscsi', - 'data': iscsi_properties - } - - def terminate_connection(self, volume, connector, **kwargs): - """Disallow connection from connector.""" - pass - - def _vrts_parse_xml_file(self, filename): - """VRTS target info. - - - - - iqn.2017-02.com.veritas:target03 - 10.182.174.188 - - - iqn.2017-02.com.veritas:target04 - 10.182.174.189 - - - - - :param filename: the configuration file - :returns: list - """ - myfile = open(filename, 'r') - data = myfile.read() - myfile.close() - dom = minidom.parseString(data) - - mylist = [] - target = {} - - try: - for trg in dom.getElementsByTagName('Target'): - target['name'] = (trg.getElementsByTagName('Name')[0] - .childNodes[0].nodeValue) - target['portal_ip'] = (trg.getElementsByTagName('PortalIP')[0] - .childNodes[0].nodeValue) - target['auth'] = (trg.getElementsByTagName('Authentication')[0] - .childNodes[0].nodeValue) - if target['auth'] == '1': - target['auth_user'] = (trg.getElementsByTagName - ('Auth_username')[0] - .childNodes[0].nodeValue) - target['auth_password'] = (trg.getElementsByTagName - ('Auth_password')[0] - .childNodes[0].nodeValue) - - mylist.append(target) - target = {} - except IndexError: - pass - - return mylist - - def _vrts_get_fs_list(self): - """Get FS list.""" - path = self._fs_list_str - provider = '%s:%s' % (self._va_ip, self._port) - data = {} - fs_list = self._access_api(self.session, provider, path, - json.dumps(data), 'GET') - - if not fs_list: - message = _('ACCESSIscsiDriver get FS list ' - 'operation failed') - LOG.error(message) - raise exception.VolumeBackendAPIException(message=message) - - return fs_list - - def _vrts_get_online_targets(self, available_targets): - """Out of available targets get list of targets which are online.""" - - online_targets = [] - path = self._target_list_status - provider = '%s:%s' % (self._va_ip, self._port) - data = {} - target_status_list = self._access_api(self.session, provider, path, - json.dumps(data), 'GET') - - try: - target_status_output = (ast. - literal_eval(target_status_list['output'])) - except KeyError: - message = _('ACCESSIscsiDriver get online target list ' - 'operation failed') - LOG.error(message) - raise exception.VolumeBackendAPIException(message=message) - - for target in available_targets: - if target['name'] in target_status_output.keys(): - if target_status_output[target['name']] == 'ONLINE': - online_targets.append(target) - - return online_targets - - def _vrts_get_targets_store(self): - """Get target and its store list.""" - path = self._target_list_str - provider = '%s:%s' % (self._va_ip, self._port) - data = {} - target_list = self._access_api(self.session, provider, path, - json.dumps(data), 'GET') - - if not target_list: - message = _('ACCESSIscsiDriver get target list ' - 'operation failed') - LOG.error(message) - raise exception.VolumeBackendAPIException(message=message) - - return target_list['output']['output']['targets'] - - def _vrts_get_assigned_store(self, target, vrts_target_list): - """Get the store mapped to given target.""" - for vrts_target in vrts_target_list: - if vrts_target['wwn'] == target: - return vrts_target['fs_list'][0] - - def _vrts_is_space_available_in_store(self, vol_size, store_name, fs_list): - """Check whether space is available on store.""" - if self._sparse_lun_support: - return True - - for fs in fs_list: - if fs['name'] == store_name: - fs_avilable_space = (int(fs['file_storage_capacity']) - - int(fs['file_storage_used'])) - free_space = fs_avilable_space / units.Gi - - if free_space > vol_size: - return True - break - return False - - def _vrts_get_suitable_target(self, target_list, vol_size): - """Get a suitable target for lun creation. - - Picking random target at first, if space is not available - in first selected target then check each target one by one - for suitable one. - """ - - target_count = len(target_list) - - incrmnt_pointer = 0 - target_index = randint(0, (target_count - 1)) - - fs_list = self._vrts_get_fs_list() - - vrts_target_list = self._vrts_get_targets_store() - - store_name = self._vrts_get_assigned_store( - target_list[target_index]['name'], - vrts_target_list - ) - - if not self._vrts_is_space_available_in_store( - vol_size, store_name, fs_list): - while (incrmnt_pointer != target_count - 1): - target_index = (target_index + 1) % target_count - store_name = self._vrts_get_assigned_store( - target_list[target_index]['name'], - vrts_target_list - ) - if self._vrts_is_space_available_in_store( - vol_size, store_name, fs_list): - return target_list[target_index]['name'] - incrmnt_pointer = incrmnt_pointer + 1 - else: - return target_list[target_index]['name'] - - return False - - def create_volume(self, volume): - """Creates a Veritas Access Iscsi LUN.""" - create_dense = False - if 'dense' in volume.metadata.keys(): - create_dense = strutils.bool_from_string( - volume.metadata['dense']) - - lun_name = self._get_va_lun_name(volume.id) - lun_size = '%sg' % volume.size - path = self._lun_create_str - provider = '%s:%s' % (self._va_ip, self._port) - - target_list = self._vrts_parse_xml_file(self.target_info_file) - - target_name = self._vrts_get_suitable_target(target_list, volume.size) - - if not target_name: - message = (_('ACCESSIscsiDriver create volume failed %s ' - 'as no space is available') % volume.id) - LOG.error(message) - raise exception.VolumeBackendAPIException(message=message) - - data = {} - data["lun_name"] = lun_name - data["target_name"] = target_name - data["size"] = lun_size - if not self._sparse_lun_support or create_dense: - data["option"] = "option=dense" - - result = self._access_api(self.session, provider, path, - json.dumps(data), 'POST') - - if not result: - message = (_('ACCESSIscsiDriver create volume failed %s') - % volume.id) - LOG.error(message) - raise exception.VolumeBackendAPIException(message=message) - - def delete_volume(self, volume): - """Deletes a Veritas Access Iscsi LUN.""" - lun_name = self._get_va_lun_name(volume.id) - lun_list = self._get_vrts_lun_list() - target_name = "" - - for lun in lun_list['output']['output']['luns']: - if lun['lun_name'] == lun_name: - target_name = lun['target_name'] - - path = self._lun_destroy_str - provider = '%s:%s' % (self._va_ip, self._port) - - data = {} - data["lun_name"] = lun_name - data["target_name"] = target_name - - result = self._access_api(self.session, provider, path, - json.dumps(data), 'POST') - - if not result: - message = (_('ACCESSIscsiDriver delete volume failed %s') - % volume.id) - LOG.error(message) - raise exception.VolumeBackendAPIException(message=message) - - def create_snapshot(self, snapshot): - """Creates a snapshot of LUN.""" - lun_name = self._get_va_lun_name(snapshot.volume_id) - snap_name = self._get_va_lun_name(snapshot.id) - path = self._snapshot_create_str - provider = '%s:%s' % (self._va_ip, self._port) - - data = {} - data["lun_name"] = lun_name - data["snap_name"] = snap_name - - result = self._access_api(self.session, provider, path, - json.dumps(data), 'POST') - - if not result: - message = (_('ACCESSIscsiDriver create snapshot failed for %s') - % snapshot.volume_id) - LOG.error(message) - raise exception.VolumeBackendAPIException(message=message) - - def delete_snapshot(self, snapshot): - """Deletes a snapshot of LUN.""" - lun_name = self._get_va_lun_name(snapshot.volume_id) - snap_name = self._get_va_lun_name(snapshot.id) - path = self._snapshot_destroy_str - provider = '%s:%s' % (self._va_ip, self._port) - - data = {} - data["lun_name"] = lun_name - data["snap_name"] = snap_name - - result = self._access_api(self.session, provider, path, - json.dumps(data), 'POST') - - if not result: - message = (_('ACCESSIscsiDriver delete snapshot failed for %s') - % snapshot.id) - LOG.error(message) - raise exception.VolumeBackendAPIException(message=message) - - def create_cloned_volume(self, volume, src_vref): - """Create a clone of the volume.""" - lun_name = self._get_va_lun_name(src_vref.id) - cloned_lun_name = self._get_va_lun_name(volume.id) - - lun_found = False - - lun_list = self._get_vrts_lun_list() - for lun in lun_list['output']['output']['luns']: - if lun['lun_name'] == lun_name: - store_name = lun['fs_name'] - lun_found = True - break - - if not lun_found: - message = (_('ACCESSIscsiDriver create cloned volume ' - 'failed %s as no source volume found') % volume.id) - LOG.error(message) - raise exception.VolumeBackendAPIException(message=message) - - fs_list = self._vrts_get_fs_list() - - if not self._vrts_is_space_available_in_store(volume.size, store_name, - fs_list): - message = (_('ACCESSIscsiDriver create cloned volume ' - 'failed %s as no space is available') % volume.id) - LOG.error(message) - raise exception.VolumeBackendAPIException(message=message) - - path = self._lun_clone_create_str - provider = '%s:%s' % (self._va_ip, self._port) - - data = {} - data["lun_name"] = lun_name - data["clone_name"] = cloned_lun_name - - result = self._access_api(self.session, provider, path, - json.dumps(data), 'POST') - - if not result: - message = (_('ACCESSIscsiDriver create cloned ' - 'volume failed for %s') - % src_vref.id) - LOG.error(message) - raise exception.VolumeBackendAPIException(message=message) - - if volume.size > src_vref.size: - self._vrts_extend_lun(volume, volume.size) - - def create_volume_from_snapshot(self, volume, snapshot): - """Creates a volume from snapshot.""" - LOG.debug('ACCESSIscsiDriver create_volume_from_snapshot called') - - lun_name = self._get_va_lun_name(volume.id) - snap_name = self._get_va_lun_name(snapshot.id) - - path = self._snapshot_list_str - provider = '%s:%s' % (self._va_ip, self._port) - data = {} - data["snap_name"] = snap_name - snap_info = self._access_api(self.session, provider, path, - json.dumps(data), 'GET') - - target_name = "" - if snap_info: - for snap in snap_info['output']['output']['snapshots']: - if snap['snapshot_name'] == snap_name: - target_name = snap['target_name'] - break - - if target_name == "": - message = (_('ACCESSIscsiDriver create volume from snapshot ' - 'failed for volume %s as failed to gather ' - 'snapshot details') - % volume.id) - LOG.error(message) - raise exception.VolumeBackendAPIException(message=message) - - vrts_target_list = self._vrts_get_targets_store() - store_name = self._vrts_get_assigned_store( - target_name, vrts_target_list) - - fs_list = self._vrts_get_fs_list() - - if not self._vrts_is_space_available_in_store(volume.size, store_name, - fs_list): - message = (_('ACCESSIscsiDriver create volume from snapshot ' - 'failed %s as no space is available') % volume.id) - LOG.error(message) - raise exception.VolumeBackendAPIException(message=message) - - path = self._lun_create_from_snap_str - provider = '%s:%s' % (self._va_ip, self._port) - - data = {} - data["lun_name"] = lun_name - data["snap_name"] = snap_name - - result = self._access_api(self.session, provider, path, - json.dumps(data), 'POST') - - if not result: - message = (_('ACCESSIscsiDriver create volume from snapshot ' - 'failed for volume %s') - % volume.id) - LOG.error(message) - raise exception.VolumeBackendAPIException(message=message) - - if volume.size > snapshot.volume_size: - self._vrts_extend_lun(volume, volume.size) - - def _vrts_extend_lun(self, volume, size): - """Extend vrts LUN to given size.""" - lun_name = self._get_va_lun_name(volume.id) - target = {'target_name': ''} - - def _inner(): - lun_list = self._get_vrts_lun_list() - for lun in lun_list['output']['output']['luns']: - if lun['lun_name'] == lun_name: - target['target_name'] = lun['target_name'] - raise loopingcall.LoopingCallDone() - - timer = loopingcall.FixedIntervalWithTimeoutLoopingCall(_inner) - - try: - timer.start(interval=5, timeout=self.LUN_FOUND_INTERVAL).wait() - except loopingcall.LoopingCallTimeOut: - return False - - lun_size = '%sg' % size - path = self._lun_extend_str - provider = '%s:%s' % (self._va_ip, self._port) - - data = {} - data["lun_name"] = lun_name - data["target_name"] = target['target_name'] - data["size"] = lun_size - - result = self._access_api(self.session, provider, path, - json.dumps(data), 'POST') - return result - - def extend_volume(self, volume, size): - """Extend the volume to new size""" - lun_name = self._get_va_lun_name(volume.id) - lun_found = False - - lun_list = self._get_vrts_lun_list() - for lun in lun_list['output']['output']['luns']: - if lun['lun_name'] == lun_name: - store_name = lun['fs_name'] - lun_found = True - break - - if not lun_found: - message = (_('ACCESSIscsiDriver extend volume ' - 'failed %s as no volume found at backend') - % volume.id) - LOG.error(message) - raise exception.VolumeBackendAPIException(message=message) - - fs_list = self._vrts_get_fs_list() - - if not self._vrts_is_space_available_in_store(size, store_name, - fs_list): - message = (_('ACCESSIscsiDriver extend volume ' - 'failed %s as no space is available') % volume.id) - LOG.error(message) - raise exception.VolumeBackendAPIException(message=message) - - result = self._vrts_extend_lun(volume, size) - - if not result: - message = (_('ACCESSIscsiDriver extend ' - 'volume failed for %s') - % volume.id) - LOG.error(message) - raise exception.VolumeBackendAPIException(message=message) - - def _get_api(self, provider, tail): - api_root = 'https://%s/api/access' % (provider) - if tail == self._fs_list_str: - api_root = 'https://%s/api' % (provider) - - return api_root + tail - - def _access_api(self, session, provider, path, input_data, method): - """Returns False if failure occurs.""" - kwargs = {'data': input_data} - if not isinstance(input_data, dict): - kwargs['headers'] = {'Content-Type': 'application/json'} - full_url = self._get_api(provider, path) - response = session.request(method, full_url, **kwargs) - if response.status_code == 401: - LOG.debug('Generating new session.') - self.session = self._authenticate_access(self._va_ip, - self._user, self._pwd) - response = self.session.request(method, full_url, **kwargs) - - if response.status_code != http_client.OK: - LOG.error('Access API operation failed with HTTP error code %s.', - str(response.status_code)) - return False - result = response.json() - return result - - def _authenticate_access(self, address, username, password): - session = requests.session() - session.verify = self.verify - session.auth = NoAuth() - - # Here 'address' will be only IPv4. - response = session.post('https://%s:%s/api/rest/authenticate' - % (address, self._port), - data={'username': username, - 'password': password}) - if response.status_code != http_client.OK: - LOG.error('Failed to authenticate to remote cluster at %s as %s.', - address, username) - raise exception.NotAuthorized(_('Authentication failure.')) - result = response.json() - session.headers.update({'Authorization': 'Bearer {}' - .format(result['token'])}) - session.headers.update({'Content-Type': 'application/json'}) - - return session - - def _get_va_backend_capacity(self): - """Get VA backend total and free capacity.""" - target_list = self._vrts_parse_xml_file(self.target_info_file) - fs_list = self._vrts_get_fs_list() - vrts_target_list = self._vrts_get_targets_store() - - total_space = 0 - free_space = 0 - - target_name = [] - target_store = [] - - for target in target_list: - target_name.append(target['name']) - - for target in vrts_target_list: - if target['wwn'] in target_name: - target_store.append(target['fs_list'][0]) - - for store in target_store: - for fs in fs_list: - if fs['name'] == store: - total_space = total_space + fs['file_storage_capacity'] - fs_free_space = (fs['file_storage_capacity'] - - fs['file_storage_used']) - - if fs_free_space > free_space: - free_space = fs_free_space - - total_capacity = int(total_space) / units.Gi - free_capacity = int(free_space) / units.Gi - - return (total_capacity, free_capacity) - - def get_volume_stats(self, refresh=False): - """Retrieve status info from share volume group.""" - - total_capacity, free_capacity = self._get_va_backend_capacity() - backend_name = self.configuration.safe_get('volume_backend_name') - res_percentage = self.configuration.safe_get('reserved_percentage') - self._stats["volume_backend_name"] = backend_name or 'VeritasISCSI' - self._stats["vendor_name"] = 'Veritas' - self._stats["reserved_percentage"] = res_percentage or 0 - self._stats["driver_version"] = self.VERSION - self._stats["storage_protocol"] = self.DRIVER_VOLUME_TYPE - self._stats['total_capacity_gb'] = total_capacity - self._stats['free_capacity_gb'] = free_capacity - self._stats['thin_provisioning_support'] = True - - return self._stats diff --git a/doc/source/configuration/block-storage/drivers/veritas-access-iscsi-driver.rst b/doc/source/configuration/block-storage/drivers/veritas-access-iscsi-driver.rst deleted file mode 100644 index 7081f1619de..00000000000 --- a/doc/source/configuration/block-storage/drivers/veritas-access-iscsi-driver.rst +++ /dev/null @@ -1,91 +0,0 @@ -=========================== -Veritas ACCESS iSCSI driver -=========================== - -Veritas Access is a software-defined scale-out network-attached -storage (NAS) solution for unstructured data that works on commodity -hardware and takes advantage of placing data on premise or in the -cloud based on intelligent policies. Through Veritas Access iSCSI -Driver, OpenStack Block Storage can use Veritas Access backend as a -block storage resource. The driver enables you to create iSCSI volumes -that an OpenStack Block Storage server can allocate to any virtual machine -running on a compute host. - -Requirements -~~~~~~~~~~~~ - -The Veritas ACCESS iSCSI Driver, version ``1.0.0`` and later, supports -Veritas ACCESS release ``7.4`` and later. - -Supported operations -~~~~~~~~~~~~~~~~~~~~ - -- Create and delete volumes. -- Create and delete snapshots. -- Create volume from snapshot. -- Extend a volume. -- Attach and detach volumes. -- Clone volumes. - -Configuration -~~~~~~~~~~~~~ - -#. Enable RESTful service on the Veritas Access Backend. - -#. Create Veritas Access iSCSI target, add store and portal IP to it. - - You can create target and add portal IP, store to it as follows: - - .. code-block:: console - - Target> iscsi target create iqn.2018-02.com.veritas:target02 - Target> iscsi target store add target_fs iqn.2018-02.com.veritas:target02 - Target> iscsi target portal add iqn.2018-02.com.veritas:target02 10.10.10.1 - ... - - You can add authentication to target as follows: - - .. code-block:: console - - Target> iscsi target auth incominguser add iqn.2018-02.com.veritas:target02 user1 - ... - -#. Ensure that the Veritas Access iSCSI target service is online. If the - Veritas Access - iSCSI target service is not online, enable the service by using the CLI or - REST API. - - .. code-block:: console - - Target> iscsi service start - Target> iscsi service status - ... - - Define the following required properties in the ``cinder.conf`` file: - - .. code-block:: ini - - volume_driver = cinder.volume.drivers.veritas_access.veritas_iscsi.ACCESSIscsiDriver - san_ip = va_console_ip - san_api_port = 14161 - san_login = master - san_password = password - target_port = 3260 - vrts_lun_sparse = True - vrts_target_config = /etc/cinder/vrts_target.xml - -#. Define Veritas Access Target details in ``/etc/cinder/vrts_target.xml``: - - .. code-block:: console - - - - - - iqn.2018-02.com.veritas:target02 - 10.10.10.1 - 0 - - - - ... diff --git a/doc/source/reference/support-matrix.ini b/doc/source/reference/support-matrix.ini index fe28bde86e4..da2eaf0c620 100644 --- a/doc/source/reference/support-matrix.ini +++ b/doc/source/reference/support-matrix.ini @@ -159,9 +159,6 @@ title=StorPool Storage Driver (storpool) [driver.synology] title=Synology Storage Driver (iSCSI) -[driver.vrtsaccess] -title=Veritas Access iSCSI Driver (iSCSI) - [driver.vrtscnfs] title=Veritas Cluster NFS Driver (NFS) @@ -235,7 +232,6 @@ driver.rbd=complete driver.seagate=complete driver.storpool=complete driver.synology=complete -driver.vrtsaccess=missing driver.vrtscnfs=missing driver.vmware=complete driver.win_iscsi=complete @@ -295,7 +291,6 @@ driver.rbd=complete driver.seagate=complete driver.storpool=complete driver.synology=complete -driver.vrtsaccess=complete driver.vrtscnfs=complete driver.vmware=complete driver.win_iscsi=complete @@ -355,7 +350,6 @@ driver.rbd=missing driver.seagate=missing driver.storpool=missing driver.synology=missing -driver.vrtsaccess=missing driver.vrtscnfs=missing driver.vmware=missing driver.win_iscsi=missing @@ -418,7 +412,6 @@ driver.rbd=missing driver.seagate=missing driver.storpool=missing driver.synology=missing -driver.vrtsaccess=missing driver.vrtscnfs=missing driver.vmware=missing driver.win_iscsi=missing @@ -480,7 +473,6 @@ driver.rbd=complete driver.seagate=missing driver.storpool=complete driver.synology=missing -driver.vrtsaccess=missing driver.vrtscnfs=missing driver.vmware=missing driver.win_iscsi=missing @@ -543,7 +535,6 @@ driver.rbd=missing driver.seagate=missing driver.storpool=missing driver.synology=missing -driver.vrtsaccess=missing driver.vrtscnfs=missing driver.vmware=missing driver.win_iscsi=missing @@ -605,7 +596,6 @@ driver.rbd=complete driver.seagate=missing driver.storpool=complete driver.synology=missing -driver.vrtsaccess=missing driver.vrtscnfs=missing driver.vmware=missing driver.win_iscsi=missing @@ -668,7 +658,6 @@ driver.rbd=missing driver.seagate=missing driver.storpool=complete driver.synology=missing -driver.vrtsaccess=missing driver.vrtscnfs=missing driver.vmware=missing driver.win_iscsi=missing @@ -731,7 +720,6 @@ driver.rbd=complete driver.seagate=complete driver.storpool=complete driver.synology=missing -driver.vrtsaccess=missing driver.vrtscnfs=missing driver.vmware=missing driver.win_iscsi=missing @@ -791,7 +779,6 @@ driver.rbd=missing driver.seagate=missing driver.storpool=missing driver.synology=missing -driver.vrtsaccess=missing driver.vrtscnfs=missing driver.vmware=complete driver.win_iscsi=missing @@ -855,7 +842,6 @@ driver.rbd=complete driver.seagate=missing driver.storpool=missing driver.synology=missing -driver.vrtsaccess=missing driver.vrtscnfs=missing driver.vmware=missing driver.win_iscsi=missing diff --git a/doc/source/reference/support-matrix.rst b/doc/source/reference/support-matrix.rst index 255ce830403..75569d14fbe 100644 --- a/doc/source/reference/support-matrix.rst +++ b/doc/source/reference/support-matrix.rst @@ -91,4 +91,6 @@ release. * Nimble Storage Driver * ProphetStor Flexvisor Driver * Sheepdog Driver + * Veritas Access Storage Driver * Virtuozzo Storage Driver + diff --git a/releasenotes/notes/veritas-access-driver-removal-dd9f0bc34c798c84.yaml b/releasenotes/notes/veritas-access-driver-removal-dd9f0bc34c798c84.yaml new file mode 100644 index 00000000000..8d2d0687ed1 --- /dev/null +++ b/releasenotes/notes/veritas-access-driver-removal-dd9f0bc34c798c84.yaml @@ -0,0 +1,7 @@ +--- +upgrade: + - | + The Veritas Access driver was marked unsupported in the + Train release and has now been removed. All data on + Veritas Access backends should be migrated to a supported + storage backend before upgrading your Cinder installation.