Merge "Yadro Tatlin Unified FC driver"
This commit is contained in:
commit
7d467069bb
@ -35,39 +35,55 @@ from cinder.volume.drivers.yadro.tatlin_client import TatlinClientV25
|
||||
from cinder.volume.drivers.yadro.tatlin_exception import TatlinAPIException
|
||||
|
||||
|
||||
RES_PORTS_RESP = [
|
||||
{
|
||||
"port": "fc20",
|
||||
"port_status": "healthy",
|
||||
"port_status_desc": "resource is available",
|
||||
"running": [
|
||||
"sp-0",
|
||||
"sp-1"
|
||||
],
|
||||
"wwn": [
|
||||
"10:00:14:52:90:00:03:10",
|
||||
"10:00:14:52:90:00:03:90"
|
||||
],
|
||||
"lun": "scsi-lun-fc20-5",
|
||||
"volume": "pty-vol-0d9627cb-c52e-49f1-878c-57c9bc3010c9",
|
||||
"lun_index": "5"
|
||||
}
|
||||
]
|
||||
VOL_ID = 'cinder-volume-id'
|
||||
|
||||
LUN_ID = 75
|
||||
|
||||
HOST_ID = 'host-id'
|
||||
|
||||
HOST_ID_2 = 'host-id-2'
|
||||
|
||||
HOST_GROUP_ID = 'group-id'
|
||||
|
||||
HOST_GROUP_NAME = 'cinder-group'
|
||||
|
||||
HOST_IQN = 'iqn.1994-05.com.redhat:12345'
|
||||
|
||||
POOL_NAME = 'cinder-pool-name'
|
||||
|
||||
POOL_ID = 'cinder-pool-id'
|
||||
|
||||
ALL_HOSTS_RESP = [
|
||||
{
|
||||
"version": "d6a2d310d9adb16f0d24d5352b5c4837",
|
||||
"id": "5e37d335-8fff-4aee-840a-34749301a16a",
|
||||
"name": "victoria-fc",
|
||||
"version": "c7216b2e14c8edc718e1664178f75777",
|
||||
"id": HOST_ID_2,
|
||||
"name": "cinder-host-2",
|
||||
"port_type": "fc",
|
||||
"initiators": [
|
||||
"21:00:34:80:0d:6b:aa:e3",
|
||||
"21:00:34:80:0d:6b:aa:e2"
|
||||
],
|
||||
"tags": [],
|
||||
"comment": "",
|
||||
"auth": {}
|
||||
}
|
||||
"initiators": ["21:00:34:80:0d:74:17:30", "21:00:34:80:0d:74:17:31"],
|
||||
},
|
||||
{
|
||||
"version": "216d08e98f8d4a695b6632fc3c79b1cc",
|
||||
"id": HOST_ID,
|
||||
"name": "cinder-host-1",
|
||||
"port_type": "fc",
|
||||
"initiators": ['21:00:00:24:ff:7f:35:b7', '21:00:00:24:ff:7f:35:b6'],
|
||||
},
|
||||
{
|
||||
"version": "301fc82d355a691248b1e1dd8164f5e5",
|
||||
"id": HOST_ID,
|
||||
"name": "cinder-host-1",
|
||||
"port_type": "iscsi",
|
||||
"initiators": [HOST_IQN],
|
||||
"auth": {"auth_type": "none"},
|
||||
},
|
||||
{
|
||||
"version": "401fc82d355a691248b1e1dd8164f5e5",
|
||||
"id": HOST_ID_2,
|
||||
"name": "cinder-host-2",
|
||||
"port_type": "iscsi",
|
||||
"initiators": ["iqn.1994-05.com.redhat:5daf702e9655"],
|
||||
"auth": {"auth_type": "none"},
|
||||
},
|
||||
]
|
||||
|
||||
RES_MAPPING_RESP = [
|
||||
@ -75,19 +91,45 @@ RES_MAPPING_RESP = [
|
||||
"resource_id": "62bbb941-ba4a-4101-927d-e527ce5ee011",
|
||||
"host_id": "5e37d335-8fff-4aee-840a-34749301a16a",
|
||||
"mapped_lun_id": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"resource_id": VOL_ID,
|
||||
"host_id": HOST_ID,
|
||||
"mapped_lun_id": LUN_ID
|
||||
},
|
||||
{
|
||||
"resource_id": "62bbb941-ba4a-4101-927d-e527ce5ee011",
|
||||
"host_id": "5e37d335-8fff-4aee-840a-34749301a16a",
|
||||
"mapped_lun_id": 1
|
||||
},
|
||||
]
|
||||
|
||||
RES_MAPPING_RESP2 = [
|
||||
{
|
||||
"resource_id": "62bbb941-ba4a-4101-927d-e527ce5ee011",
|
||||
"host_id": "5e37d335-8fff-4aee-840a-34749301a16a",
|
||||
"mapped_lun_id": 1
|
||||
},
|
||||
{
|
||||
"resource_id": "62bbb941-ba4a-4101-927d-e527ce5ee011",
|
||||
"host_id": "5e37d335-8fff-4aee-840a-34749301a16a",
|
||||
"mapped_lun_id": 1
|
||||
},
|
||||
]
|
||||
|
||||
POOL_LIST_RESPONCE = [
|
||||
{
|
||||
"id": "7e259486-deb8-4d11-8cb0-e2c5874aaa5e",
|
||||
"name": "cinder-pool",
|
||||
"id": POOL_ID,
|
||||
"name": POOL_NAME,
|
||||
"status": "ready"
|
||||
},
|
||||
{
|
||||
"id": "123",
|
||||
"name": "some-name",
|
||||
"status": "ready"
|
||||
}
|
||||
]
|
||||
|
||||
VOL_ID = 'cinder-volume-id'
|
||||
|
||||
ERROR_VOLUME = [
|
||||
{
|
||||
"ptyId": "f28ee814-22ed-4bb0-8b6a-f7ce9075034a",
|
||||
@ -132,7 +174,7 @@ RESOURCE_INFORMATION = {
|
||||
"lbaFormat": "4kn",
|
||||
"volume_id": "pty-vol-62bbb941-ba4a-4101-927d-e527ce5ee011",
|
||||
"wwid": "naa.614529011650000c4000800000000004",
|
||||
"lun_id": "4",
|
||||
"lun_id": LUN_ID,
|
||||
"cached": "true",
|
||||
"rCacheMode": "enabled",
|
||||
"wCacheMode": "enabled",
|
||||
@ -152,7 +194,7 @@ RESOURCE_INFORMATION = {
|
||||
],
|
||||
"lun": "scsi-lun-fc21-4",
|
||||
"volume": "pty-vol-62bbb941-ba4a-4101-927d-e527ce5ee011",
|
||||
"lun_index": "4"
|
||||
"lun_index": LUN_ID
|
||||
},
|
||||
{
|
||||
"port": "fc20",
|
||||
@ -169,7 +211,7 @@ RESOURCE_INFORMATION = {
|
||||
],
|
||||
"lun": "scsi-lun-fc20-4",
|
||||
"volume": "pty-vol-62bbb941-ba4a-4101-927d-e527ce5ee011",
|
||||
"lun_index": "4"
|
||||
"lun_index": LUN_ID
|
||||
}
|
||||
],
|
||||
"volume_path": "/dev/mapper/dmc-89382c6c-7cf9-4ff8-bdbb-f438d20c960a",
|
||||
@ -179,13 +221,44 @@ RESOURCE_INFORMATION = {
|
||||
}
|
||||
}
|
||||
|
||||
VOL_PORTS_RESP = [
|
||||
{
|
||||
"port": "p01",
|
||||
"port_status": "healthy",
|
||||
"running": ["sp-0", "sp-1"],
|
||||
"wwn": ["iqn.2017-01.com.yadro:tatlin:sn.09082200a51002"],
|
||||
"lun_index": LUN_ID,
|
||||
},
|
||||
{
|
||||
"port": "p11",
|
||||
"port_status": "healthy",
|
||||
"running": ["sp-0", "sp-1"],
|
||||
"wwn": ["iqn.2017-01.com.yadro:tatlin:sn.09082200a51002"],
|
||||
"lun_index": LUN_ID,
|
||||
},
|
||||
{
|
||||
"port": "p10",
|
||||
"port_status": "healthy",
|
||||
"running": ["sp-0", "sp-1"],
|
||||
"wwn": ["iqn.2017-01.com.yadro:tatlin:sn.09082200a51002"],
|
||||
"lun_index": LUN_ID,
|
||||
},
|
||||
{
|
||||
"port": "p00",
|
||||
"port_status": "healthy",
|
||||
"running": ["sp-0", "sp-1"],
|
||||
"wwn": ["iqn.2017-01.com.yadro:tatlin:sn.09082200a51002"],
|
||||
"lun_index": LUN_ID
|
||||
},
|
||||
]
|
||||
|
||||
ALL_HOST_GROUP_RESP = [
|
||||
{
|
||||
"version": "20c28d21549fb7ec5777637f72f50043",
|
||||
"id": "314b5546-45da-4c8f-a24c-b615265fbc32",
|
||||
"name": "cinder-group",
|
||||
"id": HOST_GROUP_ID,
|
||||
"name": HOST_GROUP_NAME,
|
||||
"host_ids": [
|
||||
"5e37d335-8fff-4aee-840a-34749301a16a"
|
||||
HOST_ID,
|
||||
],
|
||||
"tags": None,
|
||||
"comment": ""
|
||||
@ -413,18 +486,34 @@ class TatlinClientTest(TestCase):
|
||||
def test_get_host_group_id_success(self, send_request):
|
||||
send_request.return_value = MockResponse(
|
||||
ALL_HOST_GROUP_RESP, codes.ok)
|
||||
self.assertEqual(self.client.get_host_group_id('cinder-group'),
|
||||
'314b5546-45da-4c8f-a24c-b615265fbc32')
|
||||
self.assertEqual(self.client.get_host_group_id(HOST_GROUP_NAME),
|
||||
HOST_GROUP_ID)
|
||||
|
||||
@mock.patch.object(TatlinClientCommon,
|
||||
'is_volume_exists',
|
||||
return_value=True)
|
||||
@mock.patch.object(TatlinAccessAPI, 'send_request')
|
||||
def test_get_resource_ports_array(self, send_request, *args):
|
||||
send_request.return_value = MockResponse(RES_PORTS_RESP, codes.ok)
|
||||
def test_get_volume_ports(self, send_request):
|
||||
send_request.return_value = MockResponse(
|
||||
VOL_PORTS_RESP, requests.codes.ok)
|
||||
self.assertEqual(VOL_PORTS_RESP, self.client.get_volume_ports(VOL_ID))
|
||||
|
||||
self.assertListEqual(self.client.get_resource_ports_array(VOL_ID),
|
||||
["fc20"])
|
||||
@mock.patch.object(TatlinAccessAPI, 'send_request')
|
||||
def test_get_volume_ports_negative(self, send_request):
|
||||
send_request.return_value = MockResponse(
|
||||
{}, requests.codes.internal_server_error)
|
||||
self.assertRaises(VolumeBackendAPIException,
|
||||
self.client.get_volume_ports,
|
||||
VOL_ID)
|
||||
|
||||
@mock.patch.object(TatlinClientCommon, 'get_volume_ports')
|
||||
def test_get_resource_ports_array_empty(self, vol_ports):
|
||||
vol_ports.return_value = []
|
||||
self.assertListEqual([], self.client.get_resource_ports_array(VOL_ID))
|
||||
|
||||
@mock.patch.object(TatlinClientCommon, 'get_volume_ports')
|
||||
def test_get_resource_ports_array(self, vol_ports):
|
||||
vol_ports.return_value = VOL_PORTS_RESP
|
||||
self.assertListEqual(
|
||||
['p00', 'p01', 'p10', 'p11'],
|
||||
sorted(self.client.get_resource_ports_array(VOL_ID)))
|
||||
|
||||
@mock.patch.object(TatlinAccessAPI, 'send_request')
|
||||
def test_get_resource_mapping_negative(self, send_request):
|
||||
@ -436,8 +525,8 @@ class TatlinClientTest(TestCase):
|
||||
@mock.patch.object(TatlinAccessAPI, 'send_request')
|
||||
def test_get_pool_id_by_name(self, send_request, *args):
|
||||
send_request.return_value = MockResponse(POOL_LIST_RESPONCE, codes.ok)
|
||||
self.assertEqual(self.client.get_pool_id_by_name('cinder-pool'),
|
||||
'7e259486-deb8-4d11-8cb0-e2c5874aaa5e')
|
||||
self.assertEqual(self.client.get_pool_id_by_name(POOL_NAME),
|
||||
POOL_ID)
|
||||
|
||||
@mock.patch.object(TatlinAccessAPI, 'send_request')
|
||||
def test_get_all_hosts(self, send_request):
|
||||
|
@ -391,7 +391,7 @@ class TatlinCommonVolumeDriverTest(TestCase):
|
||||
@mock.patch.object(TatlinClientCommon,
|
||||
'is_volume_ready',
|
||||
return_value=True)
|
||||
def test_wait_volume_reay_success(self, is_ready):
|
||||
def test_wait_volume_ready_success(self, is_ready):
|
||||
self.driver.wait_volume_ready(DummyVolume('cinder_volume'))
|
||||
|
||||
@mock.patch.object(TatlinCommonVolumeDriver, '_update_qos')
|
||||
@ -505,7 +505,6 @@ class TatlinCommonVolumeDriverTest(TestCase):
|
||||
'62bbb941-ba4a-4101-927d-e527ce5ee011', '')
|
||||
|
||||
@mock.patch.object(TatlinCommonVolumeDriver, '_update_qos')
|
||||
@mock.patch.object(TatlinCommonVolumeDriver, 'wait_volume_online')
|
||||
@mock.patch.object(TatlinClientCommon, 'add_vol_to_host')
|
||||
@mock.patch.object(TatlinClientCommon,
|
||||
'is_volume_exists',
|
||||
|
366
cinder/tests/unit/volume/drivers/yadro/test_tatlin_fc.py
Normal file
366
cinder/tests/unit/volume/drivers/yadro/test_tatlin_fc.py
Normal file
@ -0,0 +1,366 @@
|
||||
# Copyright (C) 2021-2022 YADRO.
|
||||
# All rights reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
import unittest
|
||||
from unittest import mock
|
||||
|
||||
from cinder import exception
|
||||
from cinder.tests.unit.volume.drivers.yadro import test_tatlin_client as tc
|
||||
from cinder.volume import configuration
|
||||
from cinder.volume.drivers.yadro import tatlin_client
|
||||
from cinder.volume.drivers.yadro import tatlin_common
|
||||
from cinder.volume.drivers.yadro import tatlin_fc
|
||||
from cinder.volume.drivers.yadro import tatlin_utils
|
||||
|
||||
|
||||
FC_PORTS_RESP = [
|
||||
{
|
||||
"id": "fc-sp-0-1000145290000320",
|
||||
"meta": {"tatlin-node": "sp-0", "type": "fc", "port-type": "active"},
|
||||
"params": {"ifname": "fc40", "wwpn": "10:00:14:52:90:00:03:20"}
|
||||
},
|
||||
{
|
||||
"id": "fc-sp-0-1000145290000321",
|
||||
"meta": {"tatlin-node": "sp-0", "type": "fc", "port-type": "active"},
|
||||
"params": {"ifname": "fc41", "wwpn": "10:00:14:52:90:00:03:21"}
|
||||
},
|
||||
{
|
||||
"id": "fc-sp-0-1000145290000310",
|
||||
"meta": {"tatlin-node": "sp-0", "type": "fc", "port-type": "active"},
|
||||
"params": {"ifname": "fc20", "wwpn": "10:00:14:52:90:00:03:10"}
|
||||
},
|
||||
{
|
||||
"id": "fc-sp-0-1000145290000311",
|
||||
"meta": {"tatlin-node": "sp-0", "type": "fc", "port-type": "active"},
|
||||
"params": {"ifname": "fc21", "wwpn": "10:00:14:52:90:00:03:11"}
|
||||
},
|
||||
{
|
||||
"id": "fc-sp-1-1000145290000390",
|
||||
"meta": {"tatlin-node": "sp-1", "type": "fc", "port-type": "active"},
|
||||
"params": {"ifname": "fc20", "wwpn": "10:00:14:52:90:00:03:90"}
|
||||
},
|
||||
{
|
||||
"id": "fc-sp-1-1000145290000391",
|
||||
"meta": {"tatlin-node": "sp-1", "type": "fc", "port-type": "active"},
|
||||
"params": {"ifname": "fc21", "wwpn": "10:00:14:52:90:00:03:91"}
|
||||
},
|
||||
{
|
||||
"id": "fc-sp-1-10001452900003a0",
|
||||
"meta": {"tatlin-node": "sp-1", "type": "fc", "port-type": "active"},
|
||||
"params": {"ifname": "fc40", "wwpn": "10:00:14:52:90:00:03:a0"}
|
||||
},
|
||||
{
|
||||
"id": "fc-sp-1-10001452900003a1",
|
||||
"meta": {"tatlin-node": "sp-1", "type": "fc", "port-type": "active"},
|
||||
"params": {"ifname": "fc41", "wwpn": "10:00:14:52:90:00:03:a1"}
|
||||
},
|
||||
]
|
||||
|
||||
FC_PORTS_PORTALS = {
|
||||
'fc21': ['10:00:14:52:90:00:03:11', '10:00:14:52:90:00:03:91'],
|
||||
'fc20': ['10:00:14:52:90:00:03:10', '10:00:14:52:90:00:03:90'],
|
||||
}
|
||||
|
||||
FC_TARGET_WWNS = [
|
||||
'1000145290000390',
|
||||
'1000145290000311',
|
||||
'1000145290000310',
|
||||
'1000145290000391',
|
||||
]
|
||||
|
||||
FC_VOL_PORTS_RESP = [
|
||||
{
|
||||
"port": "fc21",
|
||||
"port_status": "healthy",
|
||||
"running": ["sp-0", "sp-1"],
|
||||
"wwn": ["10:00:14:52:90:00:03:11", "10:00:14:52:90:00:03:91"],
|
||||
"lun_index": tc.LUN_ID,
|
||||
},
|
||||
{
|
||||
"port": "fc20",
|
||||
"port_status": "healthy",
|
||||
"running": ["sp-0", "sp-1"],
|
||||
"wwn": ["10:00:14:52:90:00:03:10", "10:00:14:52:90:00:03:90"],
|
||||
"lun_index": tc.LUN_ID,
|
||||
},
|
||||
{
|
||||
"port": "fc40",
|
||||
"port_status": "healthy",
|
||||
"running": ["sp-0", "sp-1"],
|
||||
"wwn": ["10:00:14:52:90:00:03:09", "10:00:14:52:90:00:03:89"],
|
||||
"lun_index": tc.LUN_ID,
|
||||
},
|
||||
]
|
||||
|
||||
HOST_WWNS = [
|
||||
'21000024ff7f35b7',
|
||||
'21000024ff7f35b6',
|
||||
]
|
||||
|
||||
INITIATOR_TARGET_MAP = {
|
||||
'21000024ff7f35b7': FC_TARGET_WWNS,
|
||||
'21000024ff7f35b6': FC_TARGET_WWNS,
|
||||
}
|
||||
|
||||
FC_CONNECTOR = {'wwpns': HOST_WWNS, 'host': 'myhost'}
|
||||
|
||||
FC_CONNECTOR_2 = {'wwpns': ['123', '456'], 'host': 'myhost'}
|
||||
|
||||
VOLUME_DATA = {
|
||||
'discard': False,
|
||||
'target_discovered': True,
|
||||
'target_lun': tc.LUN_ID,
|
||||
'target_wwn': [
|
||||
'10:00:14:52:90:00:03:11',
|
||||
'10:00:14:52:90:00:03:91',
|
||||
'10:00:14:52:90:00:03:10',
|
||||
'10:00:14:52:90:00:03:90',
|
||||
],
|
||||
'initiator_target_map': INITIATOR_TARGET_MAP,
|
||||
}
|
||||
|
||||
|
||||
def get_fake_tatlin_config():
|
||||
config = configuration.Configuration(
|
||||
tatlin_common.tatlin_opts,
|
||||
configuration.SHARED_CONF_GROUP)
|
||||
config.san_ip = '127.0.0.1'
|
||||
config.san_password = 'pwd'
|
||||
config.san_login = 'admin'
|
||||
config.pool_name = tc.POOL_NAME
|
||||
config.host_group = 'cinder-group'
|
||||
config.tat_api_retry_count = 1
|
||||
config.wait_interval = 1
|
||||
config.wait_retry_count = 3
|
||||
config.chap_username = 'chap_user'
|
||||
config.chap_password = 'chap_passwd'
|
||||
config.state_path = '/tmp'
|
||||
config.export_ports = 'fc20,fc21'
|
||||
return config
|
||||
|
||||
|
||||
class TatlinFCVolumeDriverTest(unittest.TestCase):
|
||||
@mock.patch.object(tatlin_utils.TatlinVolumeConnections,
|
||||
'create_store')
|
||||
@mock.patch.object(tatlin_client.TatlinAccessAPI,
|
||||
'_authenticate_access')
|
||||
def setUp(self, auth_access, create_store):
|
||||
access_api = tatlin_client.TatlinAccessAPI(
|
||||
'127.0.0.1', '443', 'user', 'passwd', False)
|
||||
access_api._authenticate_access = mock.MagicMock()
|
||||
self.client = tatlin_client.TatlinClientCommon(
|
||||
access_api, api_retry_count=1, wait_interval=1, wait_retry_count=1)
|
||||
mock.patch.object(tatlin_client.TatlinAccessAPI,
|
||||
'_authenticate_access')
|
||||
self.driver = tatlin_fc.TatlinFCVolumeDriver(
|
||||
configuration=get_fake_tatlin_config())
|
||||
self.driver._get_tatlin_client = mock.MagicMock()
|
||||
self.driver._get_tatlin_client.return_value = self.client
|
||||
self.driver.do_setup(None)
|
||||
|
||||
@mock.patch.object(tatlin_fc.fczm_utils, 'add_fc_zone')
|
||||
@mock.patch.object(tatlin_common.TatlinCommonVolumeDriver,
|
||||
'_is_cinder_host_connection')
|
||||
@mock.patch.object(tatlin_fc.TatlinFCVolumeDriver,
|
||||
'_create_volume_data')
|
||||
@mock.patch.object(tatlin_common.TatlinCommonVolumeDriver,
|
||||
'_find_mapped_lun')
|
||||
@mock.patch.object(tatlin_common.TatlinCommonVolumeDriver,
|
||||
'add_volume_to_host')
|
||||
@mock.patch.object(tatlin_fc.TatlinFCVolumeDriver,
|
||||
'find_current_host')
|
||||
def test_initialize_connection(self,
|
||||
find_current_host,
|
||||
add_volume_to_host,
|
||||
find_mapped_lun,
|
||||
create_volume_data,
|
||||
is_cinder_connection,
|
||||
add_fc_zone):
|
||||
find_current_host.return_value = tc.HOST_ID
|
||||
find_mapped_lun.return_value = tc.LUN_ID
|
||||
is_cinder_connection.return_value = False
|
||||
create_volume_data.return_value = VOLUME_DATA
|
||||
volume = tc.DummyVolume(tc.VOL_ID)
|
||||
connector = FC_CONNECTOR
|
||||
data = self.driver.initialize_connection(volume, FC_CONNECTOR)
|
||||
self.assertDictEqual(
|
||||
data,
|
||||
{'driver_volume_type': 'fibre_channel', 'data': VOLUME_DATA}
|
||||
)
|
||||
find_current_host.assert_called_once()
|
||||
add_volume_to_host.assert_called_once_with(volume, tc.HOST_ID)
|
||||
is_cinder_connection.assert_called_once_with(connector)
|
||||
create_volume_data.assert_called_once_with(volume, connector)
|
||||
add_fc_zone.assert_called_once_with(data)
|
||||
|
||||
@mock.patch.object(tatlin_fc.TatlinFCVolumeDriver,
|
||||
'_create_volume_data')
|
||||
@mock.patch.object(tatlin_common.TatlinCommonVolumeDriver,
|
||||
'add_volume_to_host')
|
||||
@mock.patch.object(tatlin_common.TatlinCommonVolumeDriver,
|
||||
'_find_mapped_lun')
|
||||
@mock.patch.object(tatlin_fc.TatlinFCVolumeDriver,
|
||||
'find_current_host')
|
||||
@mock.patch.object(tatlin_utils.TatlinVolumeConnections,
|
||||
'increment')
|
||||
@mock.patch.object(tatlin_common.TatlinCommonVolumeDriver,
|
||||
'_is_cinder_host_connection')
|
||||
def test_initialize_connection_cinder_attachement(self,
|
||||
is_cinder_connection,
|
||||
increment, *args):
|
||||
is_cinder_connection.return_value = True
|
||||
volume = tc.DummyVolume(tc.VOL_ID)
|
||||
self.driver.initialize_connection(volume, FC_CONNECTOR)
|
||||
is_cinder_connection.assert_called_once_with(FC_CONNECTOR)
|
||||
increment.assert_called_once_with(tc.VOL_ID)
|
||||
|
||||
@mock.patch.object(tatlin_client.TatlinClientCommon,
|
||||
'get_port_portal')
|
||||
def test_get_ports_portals(self, get_port_portal):
|
||||
get_port_portal.return_value = FC_PORTS_RESP
|
||||
pp = self.driver._get_ports_portals()
|
||||
self.assertDictEqual(pp, FC_PORTS_PORTALS)
|
||||
|
||||
@mock.patch.object(tatlin_client.TatlinClientCommon,
|
||||
'get_all_hosts')
|
||||
def test_find_current_host(self, get_all_hosts):
|
||||
get_all_hosts.return_value = tc.ALL_HOSTS_RESP
|
||||
host_id = self.driver.find_current_host(FC_CONNECTOR)
|
||||
self.assertEqual(host_id, tc.HOST_ID)
|
||||
|
||||
@mock.patch.object(tatlin_client.TatlinClientCommon,
|
||||
'get_all_hosts')
|
||||
def test_find_current_host_not_found(self,
|
||||
get_all_hosts):
|
||||
get_all_hosts.return_value = tc.ALL_HOSTS_RESP
|
||||
self.assertRaises(exception.VolumeBackendAPIException,
|
||||
self.driver.find_current_host, FC_CONNECTOR_2)
|
||||
|
||||
@mock.patch.object(tatlin_fc.TatlinFCVolumeDriver,
|
||||
'_build_initiator_target_map')
|
||||
@mock.patch.object(tatlin_fc.TatlinFCVolumeDriver,
|
||||
'_get_ports_portals')
|
||||
@mock.patch.object(tatlin_client.TatlinClientCommon,
|
||||
'get_volume_ports')
|
||||
@mock.patch.object(tatlin_common.TatlinCommonVolumeDriver,
|
||||
'_find_mapped_lun')
|
||||
def test_create_volume_data(self,
|
||||
find_lun,
|
||||
volume_ports,
|
||||
ports_portals,
|
||||
build_map):
|
||||
find_lun.return_value = tc.LUN_ID
|
||||
volume_ports.return_value = FC_VOL_PORTS_RESP
|
||||
ports_portals.return_value = FC_PORTS_PORTALS
|
||||
build_map.return_value = INITIATOR_TARGET_MAP
|
||||
volume = tc.DummyVolume(tc.VOL_ID)
|
||||
connector = FC_CONNECTOR
|
||||
data = self.driver._create_volume_data(volume, connector)
|
||||
self.assertEqual(data['target_lun'], tc.LUN_ID)
|
||||
self.assertEqual(sorted(data['target_wwn']), sorted(FC_TARGET_WWNS))
|
||||
self.assertDictEqual(data['initiator_target_map'],
|
||||
INITIATOR_TARGET_MAP)
|
||||
|
||||
@mock.patch.object(tatlin_fc.fczm_utils, 'remove_fc_zone')
|
||||
@mock.patch.object(tatlin_client.TatlinClientCommon,
|
||||
'get_resource_mapping')
|
||||
@mock.patch.object(tatlin_fc.TatlinFCVolumeDriver,
|
||||
'_create_volume_data')
|
||||
@mock.patch.object(tatlin_fc.TatlinFCVolumeDriver,
|
||||
'find_current_host')
|
||||
@mock.patch.object(tatlin_common.TatlinCommonVolumeDriver,
|
||||
'_is_cinder_host_connection')
|
||||
@mock.patch.object(tatlin_common.TatlinCommonVolumeDriver,
|
||||
'remove_volume_from_host')
|
||||
def test_terminate_connection(self,
|
||||
remove_host,
|
||||
is_cinder,
|
||||
find_host,
|
||||
create_data,
|
||||
resource_mapping,
|
||||
remove_fc_zone):
|
||||
is_cinder.return_value = True
|
||||
find_host.return_value = tc.HOST_ID
|
||||
resource_mapping.return_value = tc.RES_MAPPING_RESP
|
||||
volume = tc.DummyVolume(tc.VOL_ID)
|
||||
connector = FC_CONNECTOR
|
||||
self.driver.terminate_connection(volume, connector)
|
||||
remove_host.assert_called_once_with(volume, tc.HOST_ID)
|
||||
remove_fc_zone.assert_not_called()
|
||||
|
||||
@mock.patch.object(tatlin_fc.fczm_utils, 'remove_fc_zone')
|
||||
@mock.patch.object(tatlin_client.TatlinClientCommon,
|
||||
'get_resource_mapping')
|
||||
@mock.patch.object(tatlin_fc.TatlinFCVolumeDriver,
|
||||
'_create_volume_data')
|
||||
@mock.patch.object(tatlin_fc.TatlinFCVolumeDriver,
|
||||
'find_current_host')
|
||||
@mock.patch.object(tatlin_common.TatlinCommonVolumeDriver,
|
||||
'_is_cinder_host_connection')
|
||||
@mock.patch.object(tatlin_common.TatlinCommonVolumeDriver,
|
||||
'remove_volume_from_host')
|
||||
def test_terminate_connection_with_zone_removal(self,
|
||||
remove_host,
|
||||
is_cinder,
|
||||
find_host,
|
||||
create_data,
|
||||
resource_mapping,
|
||||
remove_fc_zone):
|
||||
is_cinder.return_value = True
|
||||
find_host.return_value = tc.HOST_ID_2
|
||||
resource_mapping.side_effect = [
|
||||
tc.RES_MAPPING_RESP,
|
||||
tc.RES_MAPPING_RESP2,
|
||||
]
|
||||
create_data.return_value = VOLUME_DATA
|
||||
volume = tc.DummyVolume(tc.VOL_ID)
|
||||
connector = FC_CONNECTOR
|
||||
self.driver.terminate_connection(volume, connector)
|
||||
remove_host.assert_called_once_with(volume, tc.HOST_ID_2)
|
||||
remove_fc_zone.assert_called_once_with({
|
||||
'driver_volume_type': 'fibre_channel',
|
||||
'data': VOLUME_DATA,
|
||||
})
|
||||
|
||||
def test_build_initiator_target_map(self):
|
||||
self.driver._lookup_service = None
|
||||
connector = FC_CONNECTOR
|
||||
targets = FC_TARGET_WWNS
|
||||
itmap = self.driver._build_initiator_target_map(targets, connector)
|
||||
self.assertListEqual(sorted(itmap.keys()),
|
||||
sorted(INITIATOR_TARGET_MAP.keys()))
|
||||
for initiator in itmap:
|
||||
self.assertListEqual(sorted(itmap[initiator]),
|
||||
sorted(INITIATOR_TARGET_MAP[initiator]))
|
||||
|
||||
def test_build_initiator_target_map_with_lookup(self):
|
||||
lookup_service = mock.MagicMock()
|
||||
lookup_service.get_device_mapping_from_network.return_value = {
|
||||
'san-1': {
|
||||
'initiator_port_wwn_list': HOST_WWNS,
|
||||
'target_port_wwn_list': FC_TARGET_WWNS,
|
||||
},
|
||||
}
|
||||
self.driver._lookup_service = lookup_service
|
||||
connector = FC_CONNECTOR
|
||||
targets = FC_TARGET_WWNS
|
||||
itmap = self.driver._build_initiator_target_map(targets, connector)
|
||||
self.assertListEqual(sorted(itmap.keys()),
|
||||
sorted(INITIATOR_TARGET_MAP.keys()))
|
||||
for initiator in itmap:
|
||||
self.assertListEqual(sorted(itmap[initiator]),
|
||||
sorted(INITIATOR_TARGET_MAP[initiator]))
|
||||
lookup_service.get_device_mapping_from_network.assert_called_once_with(
|
||||
connector['wwpns'], targets)
|
@ -312,7 +312,7 @@ class TatlinISCSIVolumeDriverTest(TestCase):
|
||||
(MockResponse(ISCSI_HOST_INFO, 200)),
|
||||
]
|
||||
self.assertEqual(self.driver.find_current_host(
|
||||
'iqn.1994-05.com.redhat:4e5d7ab85a4c'),
|
||||
{'initiator': 'iqn.1994-05.com.redhat:4e5d7ab85a4c'}),
|
||||
'5e37d335-8fff-4aee-840a-34749301a16a')
|
||||
|
||||
@mock.patch.object(TatlinAccessAPI, 'send_request')
|
||||
|
@ -35,6 +35,7 @@ from cinder.volume import qos_specs
|
||||
from cinder.volume import volume_types
|
||||
from cinder.volume import volume_utils
|
||||
from cinder.volume.volume_utils import brick_get_connector_properties
|
||||
from cinder.zonemanager import utils as fczm_utils
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
@ -372,32 +373,50 @@ class TatlinCommonVolumeDriver(driver.VolumeDriver, object):
|
||||
ignore_errors=ignore_errors)
|
||||
_do_detach_volume()
|
||||
|
||||
@volume_utils.trace
|
||||
def initialize_connection(self, volume, connector):
|
||||
@utils.synchronized("tatlin-volume-connections-%s" % volume.name_id)
|
||||
def _initialize_connection():
|
||||
LOG.debug('Init %s with connector %s', volume.name_id, connector)
|
||||
current_host = self.find_current_host(connector)
|
||||
self.add_volume_to_host(volume, current_host)
|
||||
if self._is_cinder_host_connection(connector):
|
||||
self._connections.increment(volume.name_id)
|
||||
connection_info = self._create_connection_info(volume, connector)
|
||||
fczm_utils.add_fc_zone(connection_info)
|
||||
return connection_info
|
||||
return _initialize_connection()
|
||||
|
||||
@volume_utils.trace
|
||||
def terminate_connection(self, volume, connector, **kwargs):
|
||||
@utils.synchronized("tatlin-volume-connections-%s" % volume.name_id)
|
||||
def _terminate_connection():
|
||||
LOG.debug('Terminate connection for %s with connector %s',
|
||||
volume.name_id, connector)
|
||||
connection_info = self._create_connection_info(volume, connector)
|
||||
if not connector:
|
||||
return
|
||||
self.remove_volume_from_all_hosts(volume)
|
||||
return connection_info
|
||||
if self._is_cinder_host_connection(connector):
|
||||
connections = self._connections.decrement(volume.name_id)
|
||||
if connections > 0:
|
||||
LOG.debug('Not terminating connection: '
|
||||
'volume %s, existing connections: %s',
|
||||
volume.name_id, connections)
|
||||
return
|
||||
return connection_info
|
||||
hostname = connector['host']
|
||||
if self._is_nova_multiattached(volume, hostname):
|
||||
LOG.debug('Volume %s is attached on host %s to multiple VMs.'
|
||||
' Not terminating connection', volume.name_id,
|
||||
hostname)
|
||||
return
|
||||
|
||||
host = self.find_current_host(connector['initiator'])
|
||||
LOG.debug('Terminate connection volume %s removing from host %s',
|
||||
volume.name_id, host)
|
||||
self.remove_volume_from_host(volume, host)
|
||||
return connection_info
|
||||
host_id = self.find_current_host(connector)
|
||||
self.remove_volume_from_host(volume, host_id)
|
||||
resources = [r for r in self.tatlin_api.get_resource_mapping()
|
||||
if r.get('host_id', '') == host_id]
|
||||
if not resources:
|
||||
fczm_utils.remove_fc_zone(connection_info)
|
||||
return connection_info
|
||||
_terminate_connection()
|
||||
|
||||
def _is_cinder_host_connection(self, connector):
|
||||
@ -673,6 +692,13 @@ class TatlinCommonVolumeDriver(driver.VolumeDriver, object):
|
||||
def remove_volume_from_host(self, volume, host_id):
|
||||
self.tatlin_api.remove_vol_from_host(volume.name_id, host_id)
|
||||
|
||||
def remove_volume_from_all_hosts(self, volume):
|
||||
mappings = self.tatlin_api.get_resource_mapping()
|
||||
hosts = [m['host_id'] for m in mappings
|
||||
if 'resource_id' in m and m['resource_id'] == volume.name_id]
|
||||
for host_id in hosts:
|
||||
self.tatlin_api.remove_vol_from_host(volume.name_id, host_id)
|
||||
|
||||
def _is_port_assigned(self, volume_id, port):
|
||||
LOG.debug('VOLUME %s: Checking port %s ', volume_id, port)
|
||||
cur_ports = self.tatlin_api.get_resource_ports_array(volume_id)
|
||||
@ -684,20 +710,19 @@ class TatlinCommonVolumeDriver(driver.VolumeDriver, object):
|
||||
def _get_ports_portals(self):
|
||||
return {}
|
||||
|
||||
def _find_mapped_lun(self, volume_id, iqn):
|
||||
host_id = self.find_current_host(iqn)
|
||||
def _create_connection_info(self, volume, connector):
|
||||
return {}
|
||||
|
||||
def _find_mapped_lun(self, volume_id, connector):
|
||||
host_id = self.find_current_host(connector)
|
||||
result = self.tatlin_api.get_resource_mapping()
|
||||
for r in result:
|
||||
if 'host_id' in r:
|
||||
if r['resource_id'] == volume_id and r['host_id'] == host_id:
|
||||
LOG.debug('Current mapped lun record %s volume_id: %s '
|
||||
'host_id: is %s', r, volume_id, host_id)
|
||||
return r['mapped_lun_id']
|
||||
|
||||
mess = (_('Unable to get mapped lun for volume %s on host %s') %
|
||||
(volume_id, host_id))
|
||||
LOG.error(mess)
|
||||
|
||||
raise exception.VolumeBackendAPIException(message=mess)
|
||||
|
||||
@staticmethod
|
||||
@ -727,7 +752,7 @@ class TatlinCommonVolumeDriver(driver.VolumeDriver, object):
|
||||
wait_interval=self._wait_interval,
|
||||
wait_retry_count=self._wait_retry_count)
|
||||
|
||||
def find_current_host(self, wwn):
|
||||
def find_current_host(self, connector):
|
||||
return ''
|
||||
|
||||
@property
|
||||
|
124
cinder/volume/drivers/yadro/tatlin_fc.py
Normal file
124
cinder/volume/drivers/yadro/tatlin_fc.py
Normal file
@ -0,0 +1,124 @@
|
||||
# Copyright, 2023, KNS Group LLC (YADRO)
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from oslo_log import log as logging
|
||||
|
||||
from cinder.common import constants
|
||||
from cinder import exception
|
||||
from cinder.i18n import _
|
||||
from cinder import interface
|
||||
from cinder.volume import driver
|
||||
from cinder.volume.drivers.yadro import tatlin_common
|
||||
from cinder.zonemanager import utils as fczm_utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@interface.volumedriver
|
||||
class TatlinFCVolumeDriver(tatlin_common.TatlinCommonVolumeDriver,
|
||||
driver.FibreChannelDriver):
|
||||
"""ACCESS Tatlin FC Driver.
|
||||
|
||||
Executes commands relating to FC.
|
||||
Supports creation of volumes.
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
API version history:
|
||||
|
||||
1.0 - Initial version.
|
||||
"""
|
||||
|
||||
VERSION = '1.0'
|
||||
|
||||
SUPPORTS_ACTIVE_ACTIVE = True
|
||||
|
||||
# ThirdPartySystems wiki
|
||||
CI_WIKI_NAME = "Yadro_Tatlin_Unified_CI"
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(TatlinFCVolumeDriver, self).__init__(*args, **kwargs)
|
||||
self.backend_name = self.configuration.safe_get(
|
||||
'volume_backend_name') or 'TatlinFC'
|
||||
self.DRIVER_VOLUME_TYPE = constants.FC
|
||||
self._lookup_service = fczm_utils.create_lookup_service()
|
||||
|
||||
def _create_connection_info(self, volume, connector):
|
||||
info = {
|
||||
'driver_volume_type': constants.FC_VARIANT_1,
|
||||
'data': self._create_volume_data(volume, connector)
|
||||
}
|
||||
return info
|
||||
|
||||
def _get_ports_portals(self):
|
||||
result = self.tatlin_api.get_port_portal("fc")
|
||||
ports = {}
|
||||
for p in result:
|
||||
iface = p['params']['ifname']
|
||||
if self._export_ports and iface not in self._export_ports:
|
||||
continue
|
||||
ports.setdefault(iface, []).append(p['params']['wwpn'])
|
||||
return ports
|
||||
|
||||
def _create_volume_data(self, volume, connector):
|
||||
if connector is None:
|
||||
return {}
|
||||
lun_id = self._find_mapped_lun(volume.name_id, connector)
|
||||
volume_ports = self.tatlin_api.get_volume_ports(volume.name_id)
|
||||
ports_portals = self._get_ports_portals()
|
||||
data = {
|
||||
'target_discovered': True,
|
||||
'target_lun': lun_id,
|
||||
'discard': False,
|
||||
}
|
||||
target_wwns = []
|
||||
for port in volume_ports:
|
||||
wwpns = ports_portals.get(port['port'])
|
||||
if not wwpns:
|
||||
continue
|
||||
target_wwns += [w.replace(':', '') for w in wwpns]
|
||||
|
||||
data['target_wwn'] = target_wwns
|
||||
data['initiator_target_map'] = self._build_initiator_target_map(
|
||||
target_wwns, connector)
|
||||
return data
|
||||
|
||||
def find_current_host(self, connector):
|
||||
wwns = connector['wwpns']
|
||||
LOG.debug('Try to find host id for %s', wwns)
|
||||
result = self.tatlin_api.get_all_hosts()
|
||||
for h in result:
|
||||
for wwn in h['initiators']:
|
||||
if wwn.replace(':', '') in wwns:
|
||||
LOG.debug('Current host is %s', h['id'])
|
||||
return h['id']
|
||||
message = _('Unable to get host information for wwns: %s') % str(wwns)
|
||||
LOG.error(message)
|
||||
raise exception.VolumeBackendAPIException(message=message)
|
||||
|
||||
def _build_initiator_target_map(self, target_wwns, connector):
|
||||
result = {}
|
||||
|
||||
if self._lookup_service:
|
||||
mapping = self._lookup_service.get_device_mapping_from_network(
|
||||
connector['wwpns'], target_wwns)
|
||||
for fabric in mapping.values():
|
||||
for initiator in fabric['initiator_port_wwn_list']:
|
||||
result.setdefault(initiator, []).extend(
|
||||
fabric['target_port_wwn_list'])
|
||||
result = {i: list(set(t)) for i, t in result.items()}
|
||||
else:
|
||||
result = dict.fromkeys(connector['wwpns'], target_wwns)
|
||||
|
||||
return result
|
@ -18,11 +18,9 @@ from oslo_log import log as logging
|
||||
from cinder import exception
|
||||
from cinder.i18n import _
|
||||
from cinder import interface
|
||||
from cinder import utils
|
||||
from cinder.volume import driver
|
||||
from cinder.volume.drivers.yadro.tatlin_common import TatlinCommonVolumeDriver
|
||||
from cinder.volume.drivers.yadro.tatlin_exception import TatlinAPIException
|
||||
from cinder.volume import volume_utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
@ -39,9 +37,10 @@ class TatlinISCSIVolumeDriver(TatlinCommonVolumeDriver, driver.ISCSIDriver):
|
||||
API version history:
|
||||
|
||||
1.0 - Initial version.
|
||||
1.1 - Common code sharing with FC driver
|
||||
"""
|
||||
|
||||
VERSION = "1.0"
|
||||
VERSION = "1.1"
|
||||
|
||||
SUPPORTS_ACTIVE_ACTIVE = True
|
||||
|
||||
@ -56,31 +55,12 @@ class TatlinISCSIVolumeDriver(TatlinCommonVolumeDriver, driver.ISCSIDriver):
|
||||
'volume_backend_name') or 'TatlinISCSI')
|
||||
self.DRIVER_VOLUME_TYPE = 'iSCSI'
|
||||
|
||||
@volume_utils.trace
|
||||
def initialize_connection(self, volume, connector):
|
||||
@utils.synchronized("tatlin-volume-connections-%s" % volume.name_id)
|
||||
def _initialize_connection():
|
||||
LOG.debug('Init %s with connector %s', volume.name_id, connector)
|
||||
eth_ports = self._get_ports_portals()
|
||||
current_host = self.find_current_host(connector['initiator'])
|
||||
self.add_volume_to_host(volume, current_host)
|
||||
mapped_lun = self._find_mapped_lun(
|
||||
volume.name_id, connector['initiator'])
|
||||
port_result = self.tatlin_api.get_volume_ports(volume.name_id)
|
||||
|
||||
result = {
|
||||
def _create_connection_info(self, volume, connector):
|
||||
info = {
|
||||
'driver_volume_type': 'iscsi',
|
||||
'data': self._create_volume_data(port_result, eth_ports,
|
||||
mapped_lun)
|
||||
'data': self._create_volume_data(volume, connector)
|
||||
}
|
||||
|
||||
if self._is_cinder_host_connection(connector):
|
||||
self._connections.increment(volume.name_id)
|
||||
|
||||
LOG.debug('Current connection info %s', result)
|
||||
return result
|
||||
|
||||
return _initialize_connection()
|
||||
return info
|
||||
|
||||
def _get_ports_portals(self):
|
||||
try:
|
||||
@ -105,70 +85,56 @@ class TatlinISCSIVolumeDriver(TatlinCommonVolumeDriver, driver.ISCSIDriver):
|
||||
|
||||
return ports
|
||||
|
||||
def _create_volume_data(self, port_inf, eth_ports, lun_id):
|
||||
def _create_volume_data(self, volume, connector):
|
||||
if connector is None:
|
||||
return {}
|
||||
eth_ports = self._get_ports_portals()
|
||||
lun_id = self._find_mapped_lun(volume.name_id, connector)
|
||||
vol_ports = self.tatlin_api.get_volume_ports(volume.name_id)
|
||||
res = {'target_discovered': True, 'target_lun': lun_id}
|
||||
|
||||
tatlin_version = self.tatlin_api.get_tatlin_version()
|
||||
|
||||
if tatlin_version > (2, 3):
|
||||
if self._auth_method == 'CHAP':
|
||||
res['auth_method'] = 'CHAP'
|
||||
res['auth_username'] = self._chap_username
|
||||
res['auth_password'] = self._chap_password
|
||||
else:
|
||||
cred = self.tatlin_api.get_iscsi_cred()
|
||||
res['auth_method'] = 'CHAP'
|
||||
res['auth_username'] = cred['userid']
|
||||
res['auth_password'] = cred['password']
|
||||
|
||||
target_luns = []
|
||||
target_iqns = []
|
||||
target_portals = []
|
||||
LOG.debug('Port data: %s', port_inf)
|
||||
for port in port_inf:
|
||||
for port in vol_ports:
|
||||
if port['port'] not in eth_ports.keys():
|
||||
continue
|
||||
|
||||
ips = eth_ports[port['port']]
|
||||
target_portals += ips
|
||||
|
||||
luns = [lun_id for _ in ips]
|
||||
target_luns += luns
|
||||
|
||||
if 'running' in port:
|
||||
target_iqns += port['wwn'] * len(port['running'])
|
||||
else:
|
||||
target_iqns += port['wwn']
|
||||
|
||||
if not target_portals or not target_iqns or not target_luns:
|
||||
message = (_('Not enough connection data, '
|
||||
'luns: %s, portals: %s, iqns: %s') %
|
||||
target_luns, target_portals, target_iqns)
|
||||
LOG.error(message)
|
||||
raise exception.VolumeBackendAPIException(message=message)
|
||||
|
||||
res['target_lun'] = target_luns[0]
|
||||
res['target_luns'] = target_luns
|
||||
res['target_iqn'] = target_iqns[0]
|
||||
res['target_iqns'] = target_iqns
|
||||
res['target_portal'] = target_portals[0]
|
||||
res['target_portals'] = target_portals
|
||||
|
||||
LOG.debug("Volume data = %s", res)
|
||||
return res
|
||||
|
||||
def find_current_host(self, wwn):
|
||||
LOG.debug('Try to find host id for %s', wwn)
|
||||
|
||||
def find_current_host(self, connector):
|
||||
iqn = connector['initiator']
|
||||
LOG.debug('Try to find host id for %s', iqn)
|
||||
gr_id = self.tatlin_api.get_host_group_id(self._host_group)
|
||||
|
||||
group_info = self.tatlin_api.get_host_group_info(gr_id)
|
||||
LOG.debug('Group info for %s is %s', self._host_group, group_info)
|
||||
for host_id in group_info['host_ids']:
|
||||
if wwn in self.tatlin_api.get_host_info(host_id)['initiators']:
|
||||
LOG.debug('Found host %s for initiator %s', host_id, wwn)
|
||||
if iqn in self.tatlin_api.get_host_info(host_id)['initiators']:
|
||||
LOG.debug('Found host %s for initiator %s', host_id, iqn)
|
||||
return host_id
|
||||
|
||||
mess = _('Unable to find host for initiator %s' % wwn)
|
||||
LOG.error(mess)
|
||||
raise exception.VolumeBackendAPIException(message=mess)
|
||||
message = _('Unable to find host for initiator %s' % iqn)
|
||||
LOG.error(message)
|
||||
raise exception.VolumeBackendAPIException(message=message)
|
||||
|
@ -2,7 +2,7 @@
|
||||
YADRO Cinder Driver
|
||||
============================
|
||||
|
||||
YADRO Cinder driver provides iSCSI support for
|
||||
YADRO Cinder driver provides iSCSI and FC support for
|
||||
TATLIN.UNIFIED storages.
|
||||
|
||||
|
||||
@ -49,7 +49,7 @@ details about each setting, see the user's guide of the storage system.
|
||||
|
||||
#. Ports
|
||||
|
||||
Setup data ETH ports you want to export volumes to.
|
||||
Setup Ethernet or FC ports you want to export volumes to.
|
||||
|
||||
#. Hosts
|
||||
|
||||
@ -87,6 +87,22 @@ Add the following configuration to ``/etc/cinder/cinder.conf``:
|
||||
chap_username=<chap_username>
|
||||
chap_password=<chap_password>
|
||||
|
||||
or
|
||||
|
||||
.. code-block:: ini
|
||||
|
||||
[fc-1]
|
||||
volume_driver=cinder.volume.drivers.yadro.tatlin_fc.TatlinFCVolumeDriver
|
||||
san_ip=<management_ip>
|
||||
san_login=<login>
|
||||
san_password=<password>
|
||||
tat_api_retry_count=<count>
|
||||
api_port=<management_port>
|
||||
pool_name=<cinder_volumes_pool>
|
||||
export_ports=<port1>,<port2>
|
||||
host_group=<name>
|
||||
max_resource_count=<count>
|
||||
|
||||
``volume_driver``
|
||||
Volume driver name.
|
||||
|
||||
|
@ -226,7 +226,7 @@ title=Windows iSCSI Driver
|
||||
title=Windows SMB Driver
|
||||
|
||||
[driver.yadro]
|
||||
title=Yadro Tatlin Unified Driver (iSCSI)
|
||||
title=Yadro Tatlin Unified Driver (iSCSI, FC)
|
||||
|
||||
[driver.zadara]
|
||||
title=Zadara Storage Driver (iSCSI, NFS)
|
||||
|
@ -0,0 +1,4 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Yadro Tatlin Unified: Added initial version of the FC driver.
|
Loading…
Reference in New Issue
Block a user