cinder/cinder/tests/unit/volume/drivers/sandstone/test_sds_client.py

561 lines
26 KiB
Python

# Copyright (c) 2019 SandStone data Technologies Co., Ltd
# 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.
"""Unittest for sds_client."""
import json
from unittest import mock
import requests
from cinder import test
from cinder.tests.unit.volume.drivers.sandstone import test_utils
from cinder.volume.drivers.sandstone import sds_client
class FakeSession(test_utils.FakeBaseSession):
"""Fake request session."""
method_map = {
'post': {
'capacity': {'data': {'capacity_bytes': 1024, 'free_bytes': 1024}},
'pool/list': {'data': [{'status': {'progress': 100},
'pool_name': 'fake_pool',
'realname': 'fake_pool',
'storage_policy': 'fake_replicate',
'domain_name': 'fake_domain',
'pool_id': 3,
'policy_type': 'replicated',
'size': 2}]},
'resource/initiator/list': {'data': {
'results': [{'iqn': 'fake_iqn',
'type': 'iscsi'}]}},
'resource/target/get_target_acl_list': {'data': {
'results': [{'autodiscovery': 'yes',
'name': 'fake_iqn',
'approved': 'yes',
'manual': 'no',
'ip': ''}]}},
'block/gateway/server/list': {'data': [{
'networks': [{'hostid': 'node0001',
'address': '1.1.1.1',
'type': 'iSCSI'}]}]},
'resource/target/list': {'data': {
'results': [{'status': 'fake_state',
'node': ['node0001'],
'name': 'fake_target',
'type': 'iSCSI',
'gateway': [{
'hostid': 'node0001',
'networks': [{
'hostid': 'node0001',
'type': 'iSCSI',
'address': 'fake_address'}],
'hostip': 'fake_hostip'}]}]}},
'resource/target/get_chap_list': {'data': [{
'user': 'fake_chapuser',
'level': 'level1'}]},
'resource/target/get_luns': {'data': {
'results': [{'lid': 1,
'name': 'fake_lun',
'pool_id': 1}]}},
'resource/lun/list': {'data': {
'results': [{'volumeName': 'fake_lun',
'pool_id': 1,
'capacity_bytes': 1024}]}},
'delaytask/list': {'data': {
'results': [{'status': 'completed',
'run_status': 'completed',
'executor': 'LunFlatten',
'progress': 100,
'parameter': {'pool_id': 1,
'lun_name': 'fake_lun'}}]}},
'resource/snapshot/list': {'data': {
'results': [{'snapName': 'fake_snapshot',
'lunName': 'fake_lun'}]}},
}
}
class TestSdsclient(test.TestCase):
"""Testcase sds client."""
def setUp(self):
"""Setup."""
super(TestSdsclient, self).setUp()
self.mock_object(requests, 'Session', FakeSession)
self.client = sds_client.RestCmd('192.168.200.100',
'fake_user',
'fake_password',
True)
self.client.login()
def test_login(self):
"""Test login and check headers."""
self.assertEqual('https://192.168.200.100',
self.client.session.headers['Referer'])
self.assertEqual('fake_token',
self.client.session.headers['X-XSRF-Token'])
self.assertEqual('XSRF-TOKEN=fake_token; username=fake_user; '
'sdsom_sessionid=fake_session',
self.client.session.headers['Cookie'])
def test_logout(self):
"""Test logout."""
retval = self.client.logout()
self.assertIsNone(retval)
def test_query_capacity_info(self):
"""Test query cluster capacity."""
with mock.patch.object(self.client.session, 'post',
wraps=self.client.session.post) as mocker:
retval = self.client.query_capacity_info()
mocker.assert_called_once_with(
'https://192.168.200.100/api/storage/'
'capacity')
self.assertDictEqual({'capacity_bytes': 1024, 'free_bytes': 1024},
retval)
def test_query_pool_info(self):
"""Test query pool status."""
with mock.patch.object(self.client.session, 'post',
wraps=self.client.session.post) as mocker:
retval = self.client.query_pool_info()
mocker.assert_called_once_with(
'https://192.168.200.100/api/storage/'
'pool/list')
self.assertListEqual([{'status': {'progress': 100},
'realname': 'fake_pool',
'pool_name': 'fake_pool',
'storage_policy': 'fake_replicate',
'domain_name': 'fake_domain',
'pool_id': 3,
'policy_type': 'replicated',
'size': 2}], retval)
def test_create_initiator(self):
"""Test create initiator."""
with mock.patch.object(self.client.session, 'post',
wraps=self.client.session.post) as mocker:
retval = self.client.create_initiator(
initiator_name='fake_iqn')
data = json.dumps(
{'iqn': 'fake_iqn', 'type': 'iSCSI',
'remark': 'Cinder iSCSI'})
mocker.assert_called_with(
'https://192.168.200.100/api/storage/'
'resource/initiator/create', data=data)
self.assertIsNone(retval)
@mock.patch.object(sds_client.RestCmd,
"_judge_delaytask_status")
def test_add_initiator_to_target(self,
mock__judge_delaytask_status):
"""Test add initiator to target."""
with mock.patch.object(self.client.session, 'post',
wraps=self.client.session.post) as mocker:
mock__judge_delaytask_status.return_value = None
retval = self.client.add_initiator_to_target(
target_name='fake_target',
initiator_name='fake_iqn')
data = json.dumps(
{'targetName': 'fake_target',
'iqns': [{'ip': '', 'iqn': 'fake_iqn'}]})
mocker.assert_called_with(
'https://192.168.200.100/api/storage/'
'resource/target/add_initiator_to_target', data=data)
self.assertIsNone(retval)
def test_query_initiator_by_name(self):
"""Test query initiator exist or not."""
with mock.patch.object(self.client.session, 'post',
wraps=self.client.session.post) as mocker:
retval = self.client.query_initiator_by_name(
initiator_name='fake_iqn')
data = json.dumps(
{'initiatorMark': '', 'pageno': 1,
'pagesize': 1000, 'type': 'iSCSI'})
mocker.assert_called_once_with(
'https://192.168.200.100/api/storage/'
'resource/initiator/list', data=data)
self.assertDictEqual({'iqn': 'fake_iqn',
'type': 'iscsi'}, retval)
def test_query_target_initiatoracl(self):
"""Test query target related initiator info."""
with mock.patch.object(self.client.session, 'post',
wraps=self.client.session.post) as mocker:
retval = self.client.query_target_initiatoracl(
target_name='fake_target',
initiator_name='fake_iqn')
data = json.dumps(
{'pageno': 1, 'pagesize': 1000,
'targetName': 'fake_target'})
mocker.assert_called_once_with(
'https://192.168.200.100/api/storage/'
'resource/target/get_target_acl_list', data=data)
self.assertListEqual([{'autodiscovery': 'yes',
'name': 'fake_iqn',
'approved': 'yes',
'manual': 'no',
'ip': ''}], retval)
def test_query_node_by_targetips(self):
"""Test query node id and node ip, relation dict."""
with mock.patch.object(self.client.session, 'post',
wraps=self.client.session.post) as mocker:
retval = self.client.query_node_by_targetips(
target_ips=['1.1.1.1'])
mocker.assert_called_once_with(
'https://192.168.200.100/api/storage/'
'block/gateway/server/list')
self.assertDictEqual({'1.1.1.1': 'node0001'}, retval)
def test_query_target_by_name(self):
"""Test query target exist or not."""
with mock.patch.object(self.client.session, 'post',
wraps=self.client.session.post) as mocker:
retval = self.client.query_target_by_name(
target_name='fake_target')
data = json.dumps(
{'pageno': 1, 'pagesize': 1000,
"thirdParty": [0, 1],
"targetMark": ""})
mocker.assert_called_once_with(
'https://192.168.200.100/api/storage/'
'resource/target/list', data=data)
self.assertDictEqual({
'status': 'fake_state',
'node': ['node0001'],
'name': 'fake_target',
'type': 'iSCSI',
'gateway': [{'hostid': 'node0001',
'networks': [{'hostid': 'node0001',
'type': 'iSCSI',
'address': 'fake_address'}],
'hostip': 'fake_hostip'}]}, retval)
def test_create_target(self):
"""Test create target."""
with mock.patch.object(self.client.session, 'post',
wraps=self.client.session.post) as mocker:
retval = self.client.create_target(target_name='fake_target',
targetip_to_hostid=
{'1.1.1.1': 'node0001',
'1.1.1.2': 'node0002',
'1.1.1.3': 'node0003'})
tip_to_hid = {'1.1.1.1': 'node0001',
'1.1.1.2': 'node0002',
'1.1.1.3': 'node0003'}
data = json.dumps(
{"type": "iSCSI", "readOnly": 0,
"thirdParty": 1, "targetName": "fake_target",
"networks": [{"hostid": host_id, "address": address}
for address, host_id
in tip_to_hid.items()]})
mocker.assert_called_with(
'https://192.168.200.100/api/storage/'
'resource/target/create', data=data)
self.assertIsNone(retval)
def test_add_chap_by_target(self):
"""Test add chap to target."""
with mock.patch.object(self.client.session, 'post',
wraps=self.client.session.post) as mocker:
retval = self.client.add_chap_by_target(
target_name='fake_target',
username='fake_chapuser',
password='fake_chappassword')
data = json.dumps(
{"password": "fake_chappassword",
"user": "fake_chapuser", "targetName": "fake_target"})
mocker.assert_called_once_with(
'https://192.168.200.100/api/storage/'
'resource/target/add_chap', data=data)
self.assertIsNone(retval)
def test_query_chapinfo_by_target(self):
"""Test query target chap info."""
with mock.patch.object(self.client.session, 'post',
wraps=self.client.session.post) as mocker:
retval = self.client.query_chapinfo_by_target(
target_name='fake_target',
username='fake_chapuser')
data = json.dumps({"targetName": "fake_target"})
mocker.assert_called_once_with(
'https://192.168.200.100/api/storage/'
'resource/target/get_chap_list', data=data)
self.assertDictEqual({'user': 'fake_chapuser',
'level': 'level1'}, retval)
def test_create_lun(self):
"""Test create lun."""
with mock.patch.object(self.client.session, 'post',
wraps=self.client.session.post) as mocker:
retval = self.client.create_lun(capacity_bytes=1024,
poolid=1,
volume_name='fake_lun')
data = json.dumps({"capacity_bytes": 1024,
"poolId": 1, "priority": "normal",
"qosSettings": {}, "volumeName": 'fake_lun'})
mocker.assert_called_with(
'https://192.168.200.100/api/storage/'
'resource/lun/add', data=data)
self.assertIsNone(retval)
def test_delete_lun(self):
"""Test delete lun."""
with mock.patch.object(self.client.session, 'post',
wraps=self.client.session.post) as mocker:
retval = self.client.delete_lun(poolid=1,
volume_name='fake_lun')
data = json.dumps({"delayTime": 0, "volumeNameList": [{
"poolId": 1,
"volumeName": "fake_lun"}]})
mocker.assert_called_once_with(
'https://192.168.200.100/api/storage/'
'resource/lun/batch_delete', data=data)
self.assertIsNone(retval)
def test_extend_lun(self):
"""Test resize lun."""
with mock.patch.object(self.client.session, 'post',
wraps=self.client.session.post) as mocker:
retval = self.client.extend_lun(capacity_bytes=2048,
poolid=1,
volume_name='fake_lun')
data = json.dumps({"capacity_bytes": 2048,
"poolId": 1,
"volumeName": 'fake_lun'})
mocker.assert_called_once_with(
'https://192.168.200.100/api/storage/'
'resource/lun/resize', data=data)
self.assertIsNone(retval)
@mock.patch.object(sds_client.RestCmd, "_judge_delaytask_status")
@mock.patch.object(sds_client.RestCmd, "query_lun_by_name")
def test_unmap_lun(self, mock_query_lun_by_name,
mock__judge_delaytask_status):
"""Test unmap lun from target."""
with mock.patch.object(self.client.session, 'post',
wraps=self.client.session.post) as mocker:
mock__judge_delaytask_status.return_value = None
lun_uuid = "c5c8533c-4ce0-11ea-bc01-005056a736f8"
mock_query_lun_by_name.return_value = {'uuid': lun_uuid}
retval = self.client.unmap_lun(target_name='fake_target',
poolid=1,
volume_name='fake_lun',
pool_name='fake_pool')
data = json.dumps({"targetName": "fake_target",
"targetLunList": [lun_uuid],
"targetSnapList": []})
mocker.assert_called_once_with(
'https://192.168.200.100/api/storage/'
'resource/target/unmap_luns', data=data)
self.assertIsNone(retval)
@mock.patch.object(sds_client.RestCmd, "_judge_delaytask_status")
@mock.patch.object(sds_client.RestCmd, "query_lun_by_name")
def test_mapping_lun(self, mock_query_lun_by_name,
mock__judge_delaytask_status):
"""Test map lun to target."""
with mock.patch.object(self.client.session, 'post',
wraps=self.client.session.post) as mocker:
mock__judge_delaytask_status.return_value = None
lun_uuid = "c5c8533c-4ce0-11ea-bc01-005056a736f8"
mock_query_lun_by_name.return_value = {'uuid': lun_uuid}
retval = self.client.mapping_lun(
target_name='fake_target',
poolid=1,
volume_name='fake_lun',
pool_name='fake_pool')
data = json.dumps(
{"targetName": 'fake_target',
"targetLunList": [lun_uuid],
"targetSnapList": []})
mocker.assert_called_with(
'https://192.168.200.100/api/storage/'
'resource/target/map_luns', data=data)
self.assertIsNone(retval)
def test_query_target_lunacl(self):
"""Test query target related lun info."""
with mock.patch.object(self.client.session, 'post',
wraps=self.client.session.post) as mocker:
retval = self.client.query_target_lunacl(target_name='fake_target',
poolid=1,
volume_name='fake_lun')
data = json.dumps({"pageno": 1, "pagesize": 1000,
"pools": [1],
"targetName": "fake_target"})
mocker.assert_called_once_with(
'https://192.168.200.100/api/storage/'
'resource/target/get_luns', data=data)
self.assertEqual(1, retval)
def test_query_lun_by_name(self):
"""Test query lun exist or not."""
with mock.patch.object(self.client.session, 'post',
wraps=self.client.session.post) as mocker:
retval = self.client.query_lun_by_name(
volume_name='fake_lun',
poolid=1)
data = json.dumps(
{"pageno": 1, "pagesize": 1000, "volumeMark": "fake_lun",
"sortType": "time", "sortOrder": "desc",
"pools": [1],
"thirdParty": [0, 1]})
mocker.assert_called_once_with(
'https://192.168.200.100/api/storage/'
'resource/lun/list', data=data)
self.assertDictEqual({'volumeName': 'fake_lun',
'pool_id': 1,
'capacity_bytes': 1024}, retval)
@mock.patch.object(sds_client.RestCmd, "_judge_delaytask_status")
def test_create_snapshot(self, mock__judge_delaytask_status):
"""Test create snapshot."""
with mock.patch.object(self.client.session, 'post',
wraps=self.client.session.post) as mocker:
mock__judge_delaytask_status.return_value = None
retval = self.client.create_snapshot(poolid=1,
volume_name='fake_lun',
snapshot_name='fake_snapshot')
data = json.dumps(
{"lunName": "fake_lun",
"poolId": 1,
"remark": "Cinder iSCSI snapshot.",
"snapName": "fake_snapshot"})
mocker.assert_called_with(
'https://192.168.200.100/api/storage/'
'resource/snapshot/add', data=data)
self.assertIsNone(retval)
@mock.patch.object(sds_client.RestCmd, "_judge_delaytask_status")
def test_delete_snapshot(self, mock__judge_delaytask_status):
"""Test delete snapshot."""
with mock.patch.object(self.client.session, 'post',
wraps=self.client.session.post) as mocker:
mock__judge_delaytask_status.return_value = None
retval = self.client.delete_snapshot(poolid=1,
volume_name='fake_lun',
snapshot_name='fake_snapshot')
data = json.dumps(
{"lunName": "fake_lun", "poolId": 1,
"snapName": "fake_snapshot"})
mocker.assert_called_once_with(
'https://192.168.200.100/api/storage/'
'resource/snapshot/delete', data=data)
self.assertIsNone(retval)
@mock.patch.object(sds_client.RestCmd, "flatten_lun")
@mock.patch.object(sds_client.RestCmd, "_judge_delaytask_status")
def test_create_lun_from_snapshot(self, mock__judge_delaytask_status,
mock_flatten_lun):
"""Test create lun from snapshot."""
with mock.patch.object(self.client.session, 'post',
wraps=self.client.session.post) as mocker:
mock__judge_delaytask_status.return_value = None
mock_flatten_lun.return_value = None
retval = self.client.create_lun_from_snapshot(
snapshot_name='fake_snapshot',
src_volume_name='fake_src_lun',
poolid=1,
dst_volume_name='fake_dst_lun')
data = json.dumps(
{"snapshot": {"poolId": 1,
"lunName": "fake_src_lun",
"snapName": "fake_snapshot"},
"cloneLun": {"lunName": "fake_dst_lun",
"poolId": 1}})
mocker.assert_called_once_with(
'https://192.168.200.100/api/storage/'
'resource/snapshot/clone', data=data)
self.assertIsNone(retval)
@mock.patch.object(sds_client.RestCmd, "_judge_delaytask_status")
def test_flatten_lun(self, mock__judge_delaytask_status):
"""Test flatten lun."""
with mock.patch.object(self.client.session, 'post',
wraps=self.client.session.post) as mocker:
mock__judge_delaytask_status.return_value = None
retval = self.client.flatten_lun(volume_name='fake_lun',
poolid=1)
data = json.dumps(
{"poolId": 1,
"volumeName": "fake_lun"})
mocker.assert_called_once_with(
'https://192.168.200.100/api/storage/'
'resource/lun/flatten', data=data)
self.assertIsNone(retval)
def test_query_flatten_lun_process(self):
"""Test query flatten process."""
with mock.patch.object(self.client.session, 'post',
wraps=self.client.session.post) as mocker:
retval = self.client.query_flatten_lun_process(
poolid=1,
volume_name='fake_lun')
data = json.dumps({"pageno": 1, "pagesize": 20})
mocker.assert_called_once_with(
'https://192.168.200.100/api/om/'
'delaytask/list', data=data)
self.assertDictEqual({'status': 'completed',
'run_status': 'completed',
'executor': 'LunFlatten',
'progress': 100,
'parameter': {'pool_id': 1,
'lun_name': 'fake_lun'}},
retval)
@mock.patch.object(sds_client.RestCmd, "create_snapshot")
@mock.patch.object(sds_client.RestCmd, "create_lun_from_snapshot")
@mock.patch.object(sds_client.RestCmd, "flatten_lun")
@mock.patch.object(sds_client.RestCmd, "delete_snapshot")
def test_create_lun_from_lun(self, mock_delete_snapshot,
mock_flatten_lun,
mock_create_lun_from_snapshot,
mock_create_snapshot):
"""Test create clone lun."""
self.client = sds_client.RestCmd(
"https://192.168.200.100",
"fake_user", "fake_password", True)
mock_create_snapshot.return_value = {'success': 1}
mock_create_lun_from_snapshot.return_value = {'success': 1}
mock_flatten_lun.return_value = {'success': 1}
mock_delete_snapshot.return_value = {'success': 1}
retval = self.client.create_lun_from_lun(
dst_volume_name='fake_dst_lun',
poolid=1,
src_volume_name='fake_src_lun')
self.assertIsNone(retval)
def test_query_snapshot_by_name(self):
"""Test query snapshot exist or not."""
with mock.patch.object(self.client.session, 'post',
wraps=self.client.session.post) as mocker:
retval = self.client.query_snapshot_by_name(
volume_name='fake_lun',
poolid=1,
snapshot_name='fake_snapshot')
data = json.dumps(
{"lunName": "fake_lun", "pageno": 1,
"pagesize": 1000, "poolId": 1,
"snapMark": ""})
mocker.assert_called_once_with(
'https://192.168.200.100/api/storage/'
'resource/snapshot/list', data=data)
self.assertListEqual([{'snapName': 'fake_snapshot',
'lunName': 'fake_lun'}], retval)