Merge "NetApp ONTAP: Add core functions on REST client"
This commit is contained in:
commit
48a36c3800
File diff suppressed because it is too large
Load Diff
@ -1441,6 +1441,7 @@ class NetAppCmodeClientTestCase(test.TestCase):
|
||||
<num-records>1</num-records>
|
||||
<attributes-list>
|
||||
<net-interface-info>
|
||||
<vserver>fake_vserver</vserver>
|
||||
</net-interface-info>
|
||||
</attributes-list>
|
||||
</results>"""))
|
||||
@ -4494,3 +4495,46 @@ class NetAppCmodeClientTestCase(test.TestCase):
|
||||
}
|
||||
self.client.connection.send_request.assert_called_once_with(
|
||||
'file-rename-file', api_args)
|
||||
|
||||
def test_check_api_permissions(self):
|
||||
|
||||
mock_log = self.mock_object(client_cmode.LOG, 'warning')
|
||||
self.mock_object(self.client, 'check_cluster_api', return_value=True)
|
||||
|
||||
self.client.check_api_permissions()
|
||||
|
||||
self.client.check_cluster_api.assert_has_calls(
|
||||
[mock.call(*key) for key in client_cmode.SSC_API_MAP.keys()])
|
||||
self.assertEqual(0, mock_log.call_count)
|
||||
|
||||
def test_check_api_permissions_failed_ssc_apis(self):
|
||||
|
||||
def check_cluster_api(object_name, operation_name, api):
|
||||
if api != 'volume-get-iter':
|
||||
return False
|
||||
return True
|
||||
|
||||
self.mock_object(self.client, 'check_cluster_api',
|
||||
side_effect=check_cluster_api)
|
||||
|
||||
mock_log = self.mock_object(client_cmode.LOG, 'warning')
|
||||
|
||||
self.client.check_api_permissions()
|
||||
|
||||
self.assertEqual(1, mock_log.call_count)
|
||||
|
||||
def test_check_api_permissions_failed_volume_api(self):
|
||||
|
||||
def check_cluster_api(object_name, operation_name, api):
|
||||
if api == 'volume-get-iter':
|
||||
return False
|
||||
return True
|
||||
|
||||
self.mock_object(self.client, 'check_cluster_api',
|
||||
side_effect=check_cluster_api)
|
||||
mock_log = self.mock_object(client_cmode.LOG, 'warning')
|
||||
|
||||
self.assertRaises(exception.VolumeBackendAPIException,
|
||||
self.client.check_api_permissions)
|
||||
|
||||
self.assertEqual(0, mock_log.call_count)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -275,8 +275,9 @@ IGROUP1 = {'initiator-group-os-type': 'linux',
|
||||
QOS_SPECS = {}
|
||||
EXTRA_SPECS = {}
|
||||
MAX_THROUGHPUT = '21734278B/s'
|
||||
MIN_IOPS = '256IOPS'
|
||||
MAX_IOPS = '512IOPS'
|
||||
MIN_IOPS = '256iops'
|
||||
MAX_IOPS = '512iops'
|
||||
MAX_BPS = '1000000B/s'
|
||||
QOS_POLICY_GROUP_NAME = 'fake_qos_policy_group_name'
|
||||
|
||||
QOS_POLICY_GROUP_INFO_LEGACY = {
|
||||
@ -290,6 +291,11 @@ QOS_POLICY_GROUP_SPEC = {
|
||||
'policy_name': QOS_POLICY_GROUP_NAME,
|
||||
}
|
||||
|
||||
QOS_POLICY_GROUP_SPEC_BPS = {
|
||||
'max_throughput': MAX_BPS,
|
||||
'policy_name': QOS_POLICY_GROUP_NAME,
|
||||
}
|
||||
|
||||
QOS_POLICY_GROUP_SPEC_MAX = {
|
||||
'max_throughput': MAX_THROUGHPUT,
|
||||
'policy_name': QOS_POLICY_GROUP_NAME,
|
||||
@ -417,6 +423,19 @@ FAKE_LUN = netapp_api.NaElement.create_node_with_children(
|
||||
'volume': 'fakeLUN',
|
||||
'vserver': 'fake_vserver'})
|
||||
|
||||
FAKE_LUN_GET_ITER_RESULT = [
|
||||
{
|
||||
'Vserver': 'fake_vserver',
|
||||
'Volume': 'fake_volume',
|
||||
'Size': 123,
|
||||
'Qtree': 'fake_qtree',
|
||||
'Path': 'fake_path',
|
||||
'OsType': 'fake_os',
|
||||
'SpaceReserved': 'true',
|
||||
'UUID': 'fake-uuid',
|
||||
},
|
||||
]
|
||||
|
||||
CG_VOLUME_NAME = 'fake_cg_volume'
|
||||
CG_GROUP_NAME = 'fake_consistency_group'
|
||||
CG_POOL_NAME = 'cdot'
|
||||
@ -740,12 +759,219 @@ def get_fake_net_interface_get_iter_response():
|
||||
|
||||
|
||||
def get_fake_ifs():
|
||||
list_of_ifs = [
|
||||
etree.XML("""<net-interface-info>
|
||||
<address>FAKE_IP</address></net-interface-info>"""),
|
||||
etree.XML("""<net-interface-info>
|
||||
<address>FAKE_IP2</address></net-interface-info>"""),
|
||||
etree.XML("""<net-interface-info>
|
||||
<address>FAKE_IP3</address></net-interface-info>"""),
|
||||
]
|
||||
return [netapp_api.NaElement(el) for el in list_of_ifs]
|
||||
return [{'vserver': VSERVER_NAME}]
|
||||
|
||||
|
||||
AFF_SYSTEM_NODE_GET_ITER_RESPONSE_REST = {
|
||||
"records": [
|
||||
{
|
||||
"uuid": "9eff6c76-fc13-11ea-8799-525400",
|
||||
"name": "aff-node1",
|
||||
"model": "AFFA400",
|
||||
"is_all_flash_optimized": True,
|
||||
"is_all_flash_select_optimized": False,
|
||||
"_links": {
|
||||
"self": {
|
||||
"href": "/api/cluster/nodes/9eff6c76-fc13-11ea-8799-525400"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uuid": "9eff6c76-fc13-11ea-8799-52540006bba9",
|
||||
"name": "aff-node2",
|
||||
"model": "AFFA400",
|
||||
"is_all_flash_optimized": True,
|
||||
"is_all_flash_select_optimized": False,
|
||||
"_links": {
|
||||
"self": {
|
||||
"href": "/api/cluster/nodes/9eff6c76-fc13-11ea-8799-525400"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"num_records": 2,
|
||||
"_links": {
|
||||
"self": {
|
||||
"href": "/api/cluster/nodes?fields=model,name,"
|
||||
"is_all_flash_optimized,is_all_flash_select_optimized"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FAS_SYSTEM_NODE_GET_ITER_RESPONSE_REST = {
|
||||
"records": [
|
||||
{
|
||||
"uuid": "9eff6c76-fc13-11ea-8799-52540006bba9",
|
||||
"name": "fas-node1",
|
||||
"model": "FAS2554",
|
||||
"is_all_flash_optimized": False,
|
||||
"is_all_flash_select_optimized": False,
|
||||
"_links": {
|
||||
"self": {
|
||||
"href": "/api/cluster/nodes/9eff6c76-fc13-11ea-8799-525400"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uuid": "9eff6c76-fc13-11ea-8799-52540006bba9",
|
||||
"name": "fas-node2",
|
||||
"model": "FAS2554",
|
||||
"is_all_flash_optimized": False,
|
||||
"is_all_flash_select_optimized": False,
|
||||
"_links": {
|
||||
"self": {
|
||||
"href": "/api/cluster/nodes/9eff6c76-fc13-11ea-8799-525400"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"num_records": 2,
|
||||
"_links": {
|
||||
"self": {
|
||||
"href": "/api/cluster/nodes?fields=model,name,"
|
||||
"is_all_flash_optimized,is_all_flash_select_optimized"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HYBRID_SYSTEM_NODE_GET_ITER_RESPONSE_REST = {
|
||||
"records": [
|
||||
{
|
||||
"uuid": "9eff6c76-fc13-11ea-8799-52540006bba9",
|
||||
"name": "select-node",
|
||||
"model": "FDvM300",
|
||||
"is_all_flash_optimized": False,
|
||||
"is_all_flash_select_optimized": True,
|
||||
"_links": {
|
||||
"self": {
|
||||
"href": "/api/cluster/nodes/9eff6c76-fc13-11ea-8799-525400"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uuid": "9eff6c76-fc13-11ea-8799-52540006bba9",
|
||||
"name": "c190-node",
|
||||
"model": "AFF-C190",
|
||||
"is_all_flash_optimized": True,
|
||||
"is_all_flash_select_optimized": False,
|
||||
"_links": {
|
||||
"self": {
|
||||
"href": "/api/cluster/nodes/9eff6c76-fc13-11ea-8799-525400"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"num_records": 2,
|
||||
"_links": {
|
||||
"self": {
|
||||
"href": "/api/cluster/nodes?fields=model,name,"
|
||||
"is_all_flash_optimized,is_all_flash_select_optimized"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QOS_POLICY_BY_NAME_RESPONSE_REST = {
|
||||
"records": [
|
||||
{
|
||||
"uuid": "9eff6c76-fc13-11ea-8799-52540006bba9",
|
||||
"name": "openstack-cd-uuid",
|
||||
"_links": {
|
||||
"self": {
|
||||
"href": "/api/storage/qos/policies/"
|
||||
"9eff6c76-fc13-11ea-8799-52540006bba9"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"num_records": 1,
|
||||
"_links": {
|
||||
"self": {
|
||||
"href": "/api/storage/qos/policies?fields=name"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QOS_SPECS_REST = {}
|
||||
MAX_THROUGHPUT_REST = '21734278'
|
||||
MIN_IOPS_REST = '256'
|
||||
MAX_IOPS_REST = '512'
|
||||
MAX_BPS_REST = '1'
|
||||
|
||||
QOS_POLICY_GROUP_INFO_LEGACY_REST = {
|
||||
'legacy': 'legacy-' + QOS_POLICY_GROUP_NAME,
|
||||
'spec': None,
|
||||
}
|
||||
|
||||
QOS_POLICY_GROUP_SPEC_REST = {
|
||||
'min_throughput': MIN_IOPS_REST,
|
||||
'max_throughput': MAX_IOPS_REST,
|
||||
'policy_name': QOS_POLICY_GROUP_NAME,
|
||||
}
|
||||
|
||||
QOS_POLICY_GROUP_API_ARGS_REST = {
|
||||
'name': QOS_POLICY_GROUP_NAME,
|
||||
'svm': {
|
||||
'name': VSERVER_NAME
|
||||
},
|
||||
'fixed': {
|
||||
'max_throughput_iops': int(MAX_IOPS_REST),
|
||||
'min_throughput_iops': int(MIN_IOPS_REST)
|
||||
}
|
||||
}
|
||||
|
||||
QOS_POLICY_GROUP_API_ARGS_REST_BPS = {
|
||||
'name': QOS_POLICY_GROUP_NAME,
|
||||
'svm': {
|
||||
'name': VSERVER_NAME
|
||||
},
|
||||
'fixed': {
|
||||
'max_throughput_mbps': int(MAX_BPS_REST),
|
||||
}
|
||||
}
|
||||
|
||||
QOS_POLICY_GROUP_SPEC_MAX_REST = {
|
||||
'max_throughput': MAX_THROUGHPUT_REST,
|
||||
'policy_name': QOS_POLICY_GROUP_NAME,
|
||||
}
|
||||
|
||||
EXPECTED_IOPS_PER_GB_REST = '128'
|
||||
PEAK_IOPS_PER_GB_REST = '512'
|
||||
PEAK_IOPS_ALLOCATION_REST = 'used-space'
|
||||
EXPECTED_IOPS_ALLOCATION_REST = 'used-space'
|
||||
ABSOLUTE_MIN_IOPS_REST = '75'
|
||||
BLOCK_SIZE_REST = 'ANY'
|
||||
ADAPTIVE_QOS_SPEC_REST = {
|
||||
'policy_name': QOS_POLICY_GROUP_NAME,
|
||||
'expected_iops': EXPECTED_IOPS_PER_GB_REST,
|
||||
'expected_iops_allocation': EXPECTED_IOPS_ALLOCATION_REST,
|
||||
'peak_iops': PEAK_IOPS_PER_GB_REST,
|
||||
'peak_iops_allocation': PEAK_IOPS_ALLOCATION_REST,
|
||||
'absolute_min_iops': ABSOLUTE_MIN_IOPS_REST,
|
||||
'block_size': BLOCK_SIZE_REST,
|
||||
}
|
||||
|
||||
ADAPTIVE_QOS_API_ARGS_REST = {
|
||||
'name': QOS_POLICY_GROUP_NAME,
|
||||
'svm': {
|
||||
'name': VSERVER_NAME
|
||||
},
|
||||
'adaptive': {
|
||||
'absolute_min_iops': int(ABSOLUTE_MIN_IOPS_REST),
|
||||
'expected_iops': int(EXPECTED_IOPS_PER_GB_REST),
|
||||
'expected_iops_allocation': EXPECTED_IOPS_ALLOCATION_REST,
|
||||
'peak_iops': int(PEAK_IOPS_PER_GB_REST),
|
||||
'peak_iops_allocation': PEAK_IOPS_ALLOCATION_REST,
|
||||
'block_size': BLOCK_SIZE_REST,
|
||||
}
|
||||
}
|
||||
|
||||
QOS_POLICY_GROUP_INFO_REST = {
|
||||
'legacy': None, 'spec': QOS_POLICY_GROUP_SPEC_REST}
|
||||
QOS_POLICY_GROUP_INFO_MAX_REST = {
|
||||
'legacy': None, 'spec': QOS_POLICY_GROUP_SPEC_MAX_REST}
|
||||
ADAPTIVE_QOS_POLICY_GROUP_INFO_REST = {
|
||||
'legacy': None,
|
||||
'spec': ADAPTIVE_QOS_SPEC_REST,
|
||||
}
|
||||
|
||||
REST_FIELDS = 'uuid,name,style'
|
||||
|
@ -19,7 +19,6 @@
|
||||
from unittest import mock
|
||||
|
||||
import ddt
|
||||
import six
|
||||
|
||||
from cinder import exception
|
||||
from cinder.objects import fields
|
||||
@ -280,10 +279,8 @@ class NetAppBlockStorageCmodeLibraryTestCase(test.TestCase):
|
||||
self.library._get_lun_attr = mock.Mock(return_value={'Volume':
|
||||
'fakeLUN'})
|
||||
self.library.zapi_client = mock.Mock()
|
||||
self.library.zapi_client.get_lun_by_args.return_value = [
|
||||
mock.Mock(spec=netapp_api.NaElement)]
|
||||
lun = fake.FAKE_LUN
|
||||
self.library._get_lun_by_args = mock.Mock(return_value=[lun])
|
||||
lun = fake.FAKE_LUN_GET_ITER_RESULT
|
||||
self.library.zapi_client.get_lun_by_args.return_value = lun
|
||||
self.library._add_lun_to_table = mock.Mock()
|
||||
|
||||
self.library._clone_lun('fakeLUN', 'newFakeLUN', 'false')
|
||||
@ -303,10 +300,8 @@ class NetAppBlockStorageCmodeLibraryTestCase(test.TestCase):
|
||||
self.library._get_lun_attr = mock.Mock(return_value={'Volume':
|
||||
'fakeLUN'})
|
||||
self.library.zapi_client = mock.Mock()
|
||||
self.library.zapi_client.get_lun_by_args.return_value = [
|
||||
mock.Mock(spec=netapp_api.NaElement)]
|
||||
lun = fake.FAKE_LUN
|
||||
self.library._get_lun_by_args = mock.Mock(return_value=[lun])
|
||||
lun = fake.FAKE_LUN_GET_ITER_RESULT
|
||||
self.library.zapi_client.get_lun_by_args.return_value = lun
|
||||
self.library._add_lun_to_table = mock.Mock()
|
||||
|
||||
self.library._clone_lun('fakeLUN', 'newFakeLUN', 'false',
|
||||
@ -327,10 +322,8 @@ class NetAppBlockStorageCmodeLibraryTestCase(test.TestCase):
|
||||
'fakeLUN'})
|
||||
self.library.zapi_client = mock.Mock()
|
||||
self.library.lun_space_reservation = 'false'
|
||||
self.library.zapi_client.get_lun_by_args.return_value = [
|
||||
mock.Mock(spec=netapp_api.NaElement)]
|
||||
lun = fake.FAKE_LUN
|
||||
self.library._get_lun_by_args = mock.Mock(return_value=[lun])
|
||||
lun = fake.FAKE_LUN_GET_ITER_RESULT
|
||||
self.library.zapi_client.get_lun_by_args.return_value = lun
|
||||
self.library._add_lun_to_table = mock.Mock()
|
||||
|
||||
self.library._clone_lun('fakeLUN', 'newFakeLUN', is_snapshot=True)
|
||||
@ -1542,27 +1535,22 @@ class NetAppBlockStorageCmodeLibraryTestCase(test.TestCase):
|
||||
fake.LUN_WITH_METADATA['metadata'])
|
||||
new_snap_name = 'new-%s' % fake.SNAPSHOT['name']
|
||||
snapshot_path = lun_obj.metadata['Path']
|
||||
flexvol_name = lun_obj.metadata['Volume']
|
||||
block_count = 40960
|
||||
|
||||
mock__get_lun_from_table = self.mock_object(
|
||||
self.library, '_get_lun_from_table', return_value=lun_obj)
|
||||
mock__get_lun_block_count = self.mock_object(
|
||||
self.library, '_get_lun_block_count', return_value=block_count)
|
||||
mock_create_lun = self.mock_object(self.library.zapi_client,
|
||||
'create_lun')
|
||||
mock__clone_lun = self.mock_object(self.library, '_clone_lun')
|
||||
|
||||
self.library._clone_snapshot(fake.SNAPSHOT['name'])
|
||||
|
||||
mock__get_lun_from_table.assert_called_once_with(fake.SNAPSHOT['name'])
|
||||
mock__get_lun_block_count.assert_called_once_with(snapshot_path)
|
||||
mock_create_lun.assert_called_once_with(flexvol_name, new_snap_name,
|
||||
six.text_type(lun_obj.size),
|
||||
lun_obj.metadata)
|
||||
mock__clone_lun.assert_called_once_with(fake.SNAPSHOT['name'],
|
||||
new_snap_name,
|
||||
block_count=block_count)
|
||||
space_reserved='false',
|
||||
is_snapshot=True)
|
||||
|
||||
def test__clone_snapshot_invalid_block_count(self):
|
||||
lun_obj = block_base.NetAppLun(fake.LUN_WITH_METADATA['handle'],
|
||||
@ -1594,8 +1582,6 @@ class NetAppBlockStorageCmodeLibraryTestCase(test.TestCase):
|
||||
self.library, '_get_lun_from_table', return_value=lun_obj)
|
||||
mock__get_lun_block_count = self.mock_object(
|
||||
self.library, '_get_lun_block_count', return_value=block_count)
|
||||
mock_create_lun = self.mock_object(self.library.zapi_client,
|
||||
'create_lun')
|
||||
side_effect = exception.VolumeBackendAPIException(data='data')
|
||||
mock__clone_lun = self.mock_object(self.library, '_clone_lun',
|
||||
side_effect=side_effect)
|
||||
@ -1608,12 +1594,10 @@ class NetAppBlockStorageCmodeLibraryTestCase(test.TestCase):
|
||||
|
||||
mock__get_lun_from_table.assert_called_once_with(fake.SNAPSHOT['name'])
|
||||
mock__get_lun_block_count.assert_called_once_with(snapshot_path)
|
||||
mock_create_lun.assert_called_once_with(flexvol_name, new_snap_name,
|
||||
six.text_type(lun_obj.size),
|
||||
lun_obj.metadata)
|
||||
mock__clone_lun.assert_called_once_with(fake.SNAPSHOT['name'],
|
||||
new_snap_name,
|
||||
block_count=block_count)
|
||||
space_reserved='false',
|
||||
is_snapshot=True)
|
||||
mock_destroy_lun.assert_called_once_with(new_lun_path)
|
||||
|
||||
def test__swap_luns(self):
|
||||
|
@ -453,7 +453,7 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):
|
||||
|
||||
vserver = self.driver._get_vserver_for_ip('FAKE_IP')
|
||||
|
||||
self.assertIsNone(vserver)
|
||||
self.assertEqual(fake.VSERVER_NAME, vserver)
|
||||
|
||||
def test_check_for_setup_error(self):
|
||||
mock_add_looping_tasks = self.mock_object(
|
||||
@ -892,9 +892,8 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):
|
||||
is_snapshot=is_snapshot)
|
||||
|
||||
def test__clone_backing_file_for_volume(self):
|
||||
body = fake.get_fake_net_interface_get_iter_response()
|
||||
self.driver.zapi_client.get_if_info_by_ip = mock.Mock(
|
||||
return_value=[netapp_api.NaElement(body)])
|
||||
return_value=[{'ip': 'fake_ip'}])
|
||||
self.driver.zapi_client.get_vol_by_junc_vserver = mock.Mock(
|
||||
return_value='nfsvol')
|
||||
self.mock_object(self.driver, '_get_export_ip_path',
|
||||
|
@ -20,7 +20,6 @@ from unittest import mock
|
||||
import ddt
|
||||
import six
|
||||
|
||||
from cinder import exception
|
||||
from cinder.tests.unit import test
|
||||
from cinder.tests.unit.volume.drivers.netapp.dataontap.client import (
|
||||
fakes as fake_client)
|
||||
@ -46,45 +45,6 @@ class CapabilitiesLibraryTestCase(test.TestCase):
|
||||
config.volume_backend_name = 'fake_backend'
|
||||
return config
|
||||
|
||||
def test_check_api_permissions(self):
|
||||
|
||||
mock_log = self.mock_object(capabilities.LOG, 'warning')
|
||||
|
||||
self.ssc_library.check_api_permissions()
|
||||
|
||||
self.zapi_client.check_cluster_api.assert_has_calls(
|
||||
[mock.call(*key) for key in capabilities.SSC_API_MAP.keys()])
|
||||
self.assertEqual(0, mock_log.call_count)
|
||||
|
||||
def test_check_api_permissions_failed_ssc_apis(self):
|
||||
|
||||
def check_cluster_api(object_name, operation_name, api):
|
||||
if api != 'volume-get-iter':
|
||||
return False
|
||||
return True
|
||||
|
||||
self.zapi_client.check_cluster_api.side_effect = check_cluster_api
|
||||
mock_log = self.mock_object(capabilities.LOG, 'warning')
|
||||
|
||||
self.ssc_library.check_api_permissions()
|
||||
|
||||
self.assertEqual(1, mock_log.call_count)
|
||||
|
||||
def test_check_api_permissions_failed_volume_api(self):
|
||||
|
||||
def check_cluster_api(object_name, operation_name, api):
|
||||
if api == 'volume-get-iter':
|
||||
return False
|
||||
return True
|
||||
|
||||
self.zapi_client.check_cluster_api.side_effect = check_cluster_api
|
||||
mock_log = self.mock_object(capabilities.LOG, 'warning')
|
||||
|
||||
self.assertRaises(exception.VolumeBackendAPIException,
|
||||
self.ssc_library.check_api_permissions)
|
||||
|
||||
self.assertEqual(0, mock_log.call_count)
|
||||
|
||||
def test_get_ssc(self):
|
||||
|
||||
result = self.ssc_library.get_ssc()
|
||||
|
@ -410,12 +410,11 @@ class NetAppBlockStorageLibrary(object):
|
||||
def _extract_lun_info(self, lun):
|
||||
"""Extracts the LUNs from API and populates the LUN table."""
|
||||
|
||||
meta_dict = self._create_lun_meta(lun)
|
||||
path = lun.get_child_content('path')
|
||||
path = lun['Path']
|
||||
(_rest, _splitter, name) = path.rpartition('/')
|
||||
handle = self._create_lun_handle(meta_dict)
|
||||
size = lun.get_child_content('size')
|
||||
return NetAppLun(handle, name, size, meta_dict)
|
||||
handle = self._create_lun_handle(lun)
|
||||
size = lun['Size']
|
||||
return NetAppLun(handle, name, size, lun)
|
||||
|
||||
def _extract_and_populate_luns(self, api_luns):
|
||||
"""Extracts the LUNs from API and populates the LUN table."""
|
||||
@ -547,9 +546,6 @@ class NetAppBlockStorageLibrary(object):
|
||||
LOG.error("Error getting LUN attribute. Exception: %s", e)
|
||||
return None
|
||||
|
||||
def _create_lun_meta(self, lun):
|
||||
raise NotImplementedError()
|
||||
|
||||
def _get_fc_target_wwpns(self, include_partner=True):
|
||||
raise NotImplementedError()
|
||||
|
||||
@ -725,8 +721,8 @@ class NetAppBlockStorageLibrary(object):
|
||||
msg = _('Failure getting LUN info for %s.')
|
||||
raise exception.VolumeBackendAPIException(data=msg % seg[-1])
|
||||
lun_info = lun_infos[-1]
|
||||
bs = int(lun_info.get_child_content('block-size'))
|
||||
ls = int(lun_info.get_child_content('size'))
|
||||
bs = int(lun_info['BlockSize'])
|
||||
ls = int(lun_info['Size'])
|
||||
block_count = ls / bs
|
||||
return block_count
|
||||
|
||||
|
@ -236,27 +236,14 @@ class NetAppBlockStorageCmodeLibrary(block_base.NetAppBlockStorageLibrary,
|
||||
if len(lun) == 0:
|
||||
msg = _("No cloned LUN named %s found on the filer")
|
||||
raise exception.VolumeBackendAPIException(data=msg % new_name)
|
||||
clone_meta = self._create_lun_meta(lun[0])
|
||||
self._add_lun_to_table(
|
||||
block_base.NetAppLun('%s:%s' % (clone_meta['Vserver'],
|
||||
clone_meta['Path']),
|
||||
new_name,
|
||||
lun[0].get_child_content('size'),
|
||||
clone_meta))
|
||||
|
||||
def _create_lun_meta(self, lun):
|
||||
"""Creates LUN metadata dictionary."""
|
||||
self.zapi_client.check_is_naelement(lun)
|
||||
meta_dict = {}
|
||||
meta_dict['Vserver'] = lun.get_child_content('vserver')
|
||||
meta_dict['Volume'] = lun.get_child_content('volume')
|
||||
meta_dict['Qtree'] = lun.get_child_content('qtree')
|
||||
meta_dict['Path'] = lun.get_child_content('path')
|
||||
meta_dict['OsType'] = lun.get_child_content('multiprotocol-type')
|
||||
meta_dict['SpaceReserved'] = \
|
||||
lun.get_child_content('is-space-reservation-enabled')
|
||||
meta_dict['UUID'] = lun.get_child_content('uuid')
|
||||
return meta_dict
|
||||
clone_lun = lun[0]
|
||||
self._add_lun_to_table(
|
||||
block_base.NetAppLun('%s:%s' % (clone_lun['Vserver'],
|
||||
clone_lun['Path']),
|
||||
new_name,
|
||||
clone_lun['Size'],
|
||||
clone_lun))
|
||||
|
||||
def _get_fc_target_wwpns(self, include_partner=True):
|
||||
return self.zapi_client.get_fc_target_wwpns()
|
||||
@ -879,8 +866,6 @@ class NetAppBlockStorageCmodeLibrary(block_base.NetAppBlockStorageLibrary,
|
||||
LOG.info("Cloning LUN %s from snapshot %s in volume %s.", lun_name,
|
||||
snapshot_name, flexvol_name)
|
||||
|
||||
metadata = snapshot_lun.metadata
|
||||
|
||||
block_count = self._get_lun_block_count(snapshot_path)
|
||||
if block_count == 0:
|
||||
msg = _("%s cannot be reverted using clone operation"
|
||||
@ -889,12 +874,9 @@ class NetAppBlockStorageCmodeLibrary(block_base.NetAppBlockStorageLibrary,
|
||||
|
||||
new_snap_name = "new-%s" % snapshot_name
|
||||
|
||||
self.zapi_client.create_lun(
|
||||
flexvol_name, new_snap_name,
|
||||
six.text_type(snapshot_lun.size), metadata)
|
||||
try:
|
||||
self._clone_lun(snapshot_name, new_snap_name,
|
||||
block_count=block_count)
|
||||
space_reserved='false', is_snapshot=True)
|
||||
return new_snap_name
|
||||
except Exception:
|
||||
with excutils.save_and_reraise_exception():
|
||||
|
@ -644,6 +644,13 @@ class SSHUtil(object):
|
||||
|
||||
# REST API error codes.
|
||||
REST_UNAUTHORIZED = '6'
|
||||
REST_API_NOT_FOUND = '3'
|
||||
REST_UPDATE_SNAPMIRROR_FAILED = '13303844'
|
||||
REST_ERELATION_EXISTS = '6619637'
|
||||
REST_SNAPMIRROR_IN_PROGRESS = '13303810'
|
||||
REST_UPDATE_SNAPMIRROR_FAILED = '13303844'
|
||||
REST_NO_SUCH_LUN_MAP = '5374922'
|
||||
REST_NO_SUCH_FILE = '6684674'
|
||||
|
||||
|
||||
class RestNaServer(object):
|
||||
|
@ -37,6 +37,28 @@ DEFAULT_MAX_PAGE_LENGTH = 50
|
||||
ONTAP_SELECT_MODEL = 'FDvM300'
|
||||
ONTAP_C190 = 'C190'
|
||||
|
||||
# NOTE(cknight): The keys in this map are tuples that contain arguments needed
|
||||
# for efficient use of the system-user-capability-get-iter cDOT API. The
|
||||
# values are SSC extra specs associated with the APIs listed in the keys.
|
||||
SSC_API_MAP = {
|
||||
('storage.aggregate', 'show', 'aggr-options-list-info'): [
|
||||
'netapp_raid_type',
|
||||
],
|
||||
('storage.disk', 'show', 'storage-disk-get-iter'): [
|
||||
'netapp_disk_type',
|
||||
],
|
||||
('snapmirror', 'show', 'snapmirror-get-iter'): [
|
||||
'netapp_mirrored',
|
||||
],
|
||||
('volume.efficiency', 'show', 'sis-get-iter'): [
|
||||
'netapp_dedup',
|
||||
'netapp_compression',
|
||||
],
|
||||
('volume', '*show', 'volume-get-iter'): [
|
||||
'netapp_flexvol_encryption',
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
@six.add_metaclass(volume_utils.TraceWrapperMetaclass)
|
||||
class Client(client_base.Client):
|
||||
@ -182,6 +204,32 @@ class Client(client_base.Client):
|
||||
result.get_child_by_name('next-tag').set_content('')
|
||||
return result
|
||||
|
||||
def check_api_permissions(self):
|
||||
"""Check which APIs that support SSC functionality are available."""
|
||||
|
||||
inaccessible_apis = []
|
||||
invalid_extra_specs = []
|
||||
|
||||
for api_tuple, extra_specs in SSC_API_MAP.items():
|
||||
object_name, operation_name, api = api_tuple
|
||||
if not self.check_cluster_api(object_name,
|
||||
operation_name,
|
||||
api):
|
||||
inaccessible_apis.append(api)
|
||||
invalid_extra_specs.extend(extra_specs)
|
||||
|
||||
if inaccessible_apis:
|
||||
if 'volume-get-iter' in inaccessible_apis:
|
||||
msg = _('User not permitted to query Data ONTAP volumes.')
|
||||
raise exception.VolumeBackendAPIException(data=msg)
|
||||
else:
|
||||
LOG.warning('The configured user account does not have '
|
||||
'sufficient privileges to use all needed '
|
||||
'APIs. The following extra specs will fail '
|
||||
'or be ignored: %s.', invalid_extra_specs)
|
||||
|
||||
return invalid_extra_specs
|
||||
|
||||
def _get_cluster_nodes_info(self):
|
||||
"""Return a list of models of the nodes in the cluster"""
|
||||
api_args = {
|
||||
@ -481,7 +529,25 @@ class Client(client_base.Client):
|
||||
tag = result.get_child_content('next-tag')
|
||||
if tag is None:
|
||||
break
|
||||
return luns
|
||||
|
||||
lun_list = [self._create_lun_meta(lun) for lun in luns]
|
||||
return lun_list
|
||||
|
||||
def _create_lun_meta(self, lun):
|
||||
"""Creates LUN metadata dictionary."""
|
||||
self.check_is_naelement(lun)
|
||||
meta_dict = {}
|
||||
meta_dict['Vserver'] = lun.get_child_content('vserver')
|
||||
meta_dict['Volume'] = lun.get_child_content('volume')
|
||||
meta_dict['Size'] = lun.get_child_content('size')
|
||||
meta_dict['Qtree'] = lun.get_child_content('qtree')
|
||||
meta_dict['Path'] = lun.get_child_content('path')
|
||||
meta_dict['OsType'] = lun.get_child_content('multiprotocol-type')
|
||||
meta_dict['SpaceReserved'] = \
|
||||
lun.get_child_content('is-space-reservation-enabled')
|
||||
meta_dict['UUID'] = lun.get_child_content('uuid')
|
||||
meta_dict['BlockSize'] = lun.get_child_content('block-size')
|
||||
return meta_dict
|
||||
|
||||
def get_lun_map(self, path):
|
||||
"""Gets the LUN map by LUN path."""
|
||||
@ -853,7 +919,10 @@ class Client(client_base.Client):
|
||||
attr_list = luns.get_child_by_name('attributes-list')
|
||||
if not attr_list:
|
||||
return []
|
||||
return attr_list.get_children()
|
||||
|
||||
lun_list = [self._create_lun_meta(lun)
|
||||
for lun in attr_list.get_children()]
|
||||
return lun_list
|
||||
|
||||
def file_assign_qos(self, flex_vol, qos_policy_group_name,
|
||||
qos_policy_group_is_adaptive, file_path):
|
||||
@ -1061,7 +1130,8 @@ class Client(client_base.Client):
|
||||
num_records = result.get_child_content('num-records')
|
||||
if num_records and int(num_records) >= 1:
|
||||
attr_list = result.get_child_by_name('attributes-list')
|
||||
return attr_list.get_children()
|
||||
return [{'vserver': attr.get_child_content('vserver')}
|
||||
for attr in attr_list.get_children()]
|
||||
raise exception.NotFound(
|
||||
_('No interface found on cluster for ip %s') % ip)
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -314,7 +314,7 @@ class NetAppCmodeNfsDriver(nfs_base.NetAppNfsDriver,
|
||||
"""Gets the vserver and export volume for share."""
|
||||
(host_ip, export_path) = self._get_export_ip_path(volume_id, share)
|
||||
ifs = self.zapi_client.get_if_info_by_ip(host_ip)
|
||||
vserver = ifs[0].get_child_content('vserver')
|
||||
vserver = ifs[0].get('vserver')
|
||||
exp_volume = self.zapi_client.get_vol_by_junc_vserver(vserver,
|
||||
export_path)
|
||||
return vserver, exp_volume
|
||||
@ -512,7 +512,7 @@ class NetAppCmodeNfsDriver(nfs_base.NetAppNfsDriver,
|
||||
"""Get vserver for the mentioned ip."""
|
||||
try:
|
||||
ifs = self.zapi_client.get_if_info_by_ip(ip)
|
||||
vserver = ifs[0].get_child_content('vserver')
|
||||
vserver = ifs[0].get('vserver')
|
||||
return vserver
|
||||
except Exception:
|
||||
return None
|
||||
|
@ -22,34 +22,9 @@ import re
|
||||
from oslo_log import log as logging
|
||||
import six
|
||||
|
||||
from cinder import exception
|
||||
from cinder.i18n import _
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
# NOTE(cknight): The keys in this map are tuples that contain arguments needed
|
||||
# for efficient use of the system-user-capability-get-iter cDOT API. The
|
||||
# values are SSC extra specs associated with the APIs listed in the keys.
|
||||
SSC_API_MAP = {
|
||||
('storage.aggregate', 'show', 'aggr-options-list-info'): [
|
||||
'netapp_raid_type',
|
||||
],
|
||||
('storage.disk', 'show', 'storage-disk-get-iter'): [
|
||||
'netapp_disk_type',
|
||||
],
|
||||
('snapmirror', 'show', 'snapmirror-get-iter'): [
|
||||
'netapp_mirrored',
|
||||
],
|
||||
('volume.efficiency', 'show', 'sis-get-iter'): [
|
||||
'netapp_dedup',
|
||||
'netapp_compression',
|
||||
],
|
||||
('volume', '*show', 'volume-get-iter'): [
|
||||
'netapp_flexvol_encryption',
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
class CapabilitiesLibrary(object):
|
||||
|
||||
@ -64,30 +39,7 @@ class CapabilitiesLibrary(object):
|
||||
self.invalid_extra_specs = []
|
||||
|
||||
def check_api_permissions(self):
|
||||
"""Check which APIs that support SSC functionality are available."""
|
||||
|
||||
inaccessible_apis = []
|
||||
invalid_extra_specs = []
|
||||
|
||||
for api_tuple, extra_specs in SSC_API_MAP.items():
|
||||
object_name, operation_name, api = api_tuple
|
||||
if not self.zapi_client.check_cluster_api(object_name,
|
||||
operation_name,
|
||||
api):
|
||||
inaccessible_apis.append(api)
|
||||
invalid_extra_specs.extend(extra_specs)
|
||||
|
||||
if inaccessible_apis:
|
||||
if 'volume-get-iter' in inaccessible_apis:
|
||||
msg = _('User not permitted to query Data ONTAP volumes.')
|
||||
raise exception.VolumeBackendAPIException(data=msg)
|
||||
else:
|
||||
LOG.warning('The configured user account does not have '
|
||||
'sufficient privileges to use all needed '
|
||||
'APIs. The following extra specs will fail '
|
||||
'or be ignored: %s.', invalid_extra_specs)
|
||||
|
||||
self.invalid_extra_specs = invalid_extra_specs
|
||||
self.invalid_extra_specs = self.zapi_client.check_api_permissions()
|
||||
|
||||
def cluster_user_supported(self):
|
||||
return not self.invalid_extra_specs
|
||||
|
Loading…
Reference in New Issue
Block a user