1347 lines
58 KiB
Python
1347 lines
58 KiB
Python
# Copyright 2018 Inspur Corp.
|
|
# 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.
|
|
|
|
"""
|
|
Volume driver test for Inspur AS13000
|
|
"""
|
|
|
|
import json
|
|
import mock
|
|
import random
|
|
import time
|
|
|
|
import ddt
|
|
import eventlet
|
|
from oslo_config import cfg
|
|
import requests
|
|
|
|
from cinder import context
|
|
from cinder import exception
|
|
from cinder import test
|
|
from cinder.tests.unit import fake_snapshot
|
|
from cinder.tests.unit import fake_volume
|
|
from cinder.volume import configuration
|
|
from cinder.volume.drivers.inspur.as13000 import as13000_driver
|
|
from cinder.volume import volume_utils
|
|
|
|
|
|
CONF = cfg.CONF
|
|
|
|
test_config = configuration.Configuration(None)
|
|
test_config.san_ip = 'some_ip'
|
|
test_config.san_api_port = 'as13000_api_port'
|
|
test_config.san_login = 'username'
|
|
test_config.san_password = 'password'
|
|
test_config.as13000_ipsan_pools = ['fakepool']
|
|
test_config.as13000_meta_pool = 'meta_pool'
|
|
test_config.use_chap_auth = True
|
|
test_config.chap_username = 'fakeuser'
|
|
test_config.chap_password = 'fakepass'
|
|
|
|
|
|
class FakeResponse(object):
|
|
def __init__(self, status, output):
|
|
self.status_code = status
|
|
self.text = 'return message'
|
|
self._json = output
|
|
|
|
def json(self):
|
|
return self._json
|
|
|
|
def close(self):
|
|
pass
|
|
|
|
|
|
@ddt.ddt
|
|
class RestAPIExecutorTestCase(test.TestCase):
|
|
def setUp(self):
|
|
self.rest_api = as13000_driver.RestAPIExecutor(
|
|
test_config.san_ip,
|
|
test_config.san_api_port,
|
|
test_config.san_login,
|
|
test_config.san_password)
|
|
super(RestAPIExecutorTestCase, self).setUp()
|
|
|
|
def test_login(self):
|
|
mock__login = self.mock_object(self.rest_api, '_login',
|
|
mock.Mock(return_value='fake_token'))
|
|
self.rest_api.login()
|
|
mock__login.assert_called_once()
|
|
self.assertEqual('fake_token', self.rest_api._token)
|
|
|
|
def test__login(self):
|
|
response = {'token': 'fake_token', 'expireTime': '7200', 'type': 0}
|
|
mock_sra = self.mock_object(self.rest_api, 'send_rest_api',
|
|
mock.Mock(return_value=response))
|
|
|
|
result = self.rest_api._login()
|
|
|
|
self.assertEqual('fake_token', result)
|
|
|
|
login_params = {'name': test_config.san_login,
|
|
'password': test_config.san_password}
|
|
mock_sra.assert_called_once_with(method='security/token',
|
|
params=login_params,
|
|
request_type='post')
|
|
|
|
def test_send_rest_api(self):
|
|
expected = {'value': 'abc'}
|
|
mock_sa = self.mock_object(self.rest_api, 'send_api',
|
|
mock.Mock(return_value=expected))
|
|
result = self.rest_api.send_rest_api(
|
|
method='fake_method',
|
|
params='fake_params',
|
|
request_type='fake_type')
|
|
self.assertEqual(expected, result)
|
|
mock_sa.assert_called_once_with(
|
|
'fake_method',
|
|
'fake_params',
|
|
'fake_type')
|
|
|
|
def test_send_rest_api_retry(self):
|
|
expected = {'value': 'abc'}
|
|
mock_sa = self.mock_object(
|
|
self.rest_api,
|
|
'send_api',
|
|
mock.Mock(side_effect=(exception.VolumeDriverException, expected)))
|
|
mock_login = self.mock_object(self.rest_api, 'login', mock.Mock())
|
|
result = self.rest_api.send_rest_api(
|
|
method='fake_method',
|
|
params='fake_params',
|
|
request_type='fake_type'
|
|
)
|
|
self.assertEqual(expected, result)
|
|
|
|
mock_sa.assert_called_with(
|
|
'fake_method',
|
|
'fake_params',
|
|
'fake_type')
|
|
mock_login.assert_called_once()
|
|
|
|
def test_send_rest_api_3times_fail(self):
|
|
mock_sa = self.mock_object(
|
|
self.rest_api, 'send_api', mock.Mock(
|
|
side_effect=(exception.VolumeDriverException)))
|
|
mock_login = self.mock_object(self.rest_api, 'login', mock.Mock())
|
|
self.assertRaises(
|
|
exception.VolumeDriverException,
|
|
self.rest_api.send_rest_api,
|
|
method='fake_method',
|
|
params='fake_params',
|
|
request_type='fake_type')
|
|
mock_sa.assert_called_with('fake_method',
|
|
'fake_params',
|
|
'fake_type')
|
|
mock_login.assert_called()
|
|
|
|
def test_send_rest_api_backend_error_fail(self):
|
|
side_effect = exception.VolumeBackendAPIException('fake_err_msg')
|
|
mock_sa = self.mock_object(self.rest_api,
|
|
'send_api',
|
|
mock.Mock(side_effect=side_effect))
|
|
mock_login = self.mock_object(self.rest_api, 'login')
|
|
|
|
self.assertRaises(exception.VolumeBackendAPIException,
|
|
self.rest_api.send_rest_api,
|
|
method='fake_method',
|
|
params='fake_params',
|
|
request_type='fake_type')
|
|
mock_sa.assert_called_with('fake_method',
|
|
'fake_params',
|
|
'fake_type')
|
|
mock_login.assert_not_called()
|
|
|
|
@ddt.data(
|
|
{'method': 'fake_method', 'request_type': 'post', 'params':
|
|
{'fake_param': 'fake_value'}},
|
|
{'method': 'fake_method', 'request_type': 'get', 'params':
|
|
{'fake_param': 'fake_value'}},
|
|
{'method': 'fake_method', 'request_type': 'delete', 'params':
|
|
{'fake_param': 'fake_value'}},
|
|
{'method': 'fake_method', 'request_type': 'put', 'params':
|
|
{'fake_param': 'fake_value'}}, )
|
|
@ddt.unpack
|
|
def test_send_api(self, method, params, request_type):
|
|
self.rest_api._token = 'fake_token'
|
|
if request_type in ('post', 'delete', 'put'):
|
|
fake_output = {'code': 0, 'message': 'success'}
|
|
elif request_type == 'get':
|
|
fake_output = {'code': 0, 'data': 'fake_date'}
|
|
mock_request = self.mock_object(
|
|
requests, request_type, mock.Mock(
|
|
return_value=FakeResponse(
|
|
200, fake_output)))
|
|
self.rest_api.send_api(
|
|
method,
|
|
params=params,
|
|
request_type=request_type)
|
|
mock_request.assert_called_once_with(
|
|
'http://%s:%s/rest/%s' %
|
|
(test_config.san_ip,
|
|
test_config.san_api_port,
|
|
method),
|
|
data=json.dumps(params),
|
|
headers={'X-Auth-Token': 'fake_token'})
|
|
|
|
@ddt.data({'method': r'security/token',
|
|
'params': {'name': test_config.san_login,
|
|
'password': test_config.san_password},
|
|
'request_type': 'post'},
|
|
{'method': r'security/token',
|
|
'params': None,
|
|
'request_type': 'delete'})
|
|
@ddt.unpack
|
|
def test_send_api_access_success(self, method, params, request_type):
|
|
if request_type == 'post':
|
|
fake_value = {'code': 0, 'data': {
|
|
'token': 'fake_token',
|
|
'expireTime': '7200',
|
|
'type': 0}}
|
|
mock_requests = self.mock_object(
|
|
requests, 'post', mock.Mock(
|
|
return_value=FakeResponse(
|
|
200, fake_value)))
|
|
result = self.rest_api.send_api(method, params, request_type)
|
|
self.assertEqual(fake_value['data'], result)
|
|
mock_requests.assert_called_once_with(
|
|
'http://%s:%s/rest/%s' %
|
|
(test_config.san_ip,
|
|
test_config.san_api_port,
|
|
method),
|
|
data=json.dumps(params),
|
|
headers=None)
|
|
if request_type == 'delete':
|
|
fake_value = {'code': 0, 'message': 'Success!'}
|
|
self.rest_api._token = 'fake_token'
|
|
mock_requests = self.mock_object(
|
|
requests, 'delete', mock.Mock(
|
|
return_value=FakeResponse(
|
|
200, fake_value)))
|
|
self.rest_api.send_api(method, params, request_type)
|
|
mock_requests.assert_called_once_with(
|
|
'http://%s:%s/rest/%s' %
|
|
(test_config.san_ip,
|
|
test_config.san_api_port,
|
|
method),
|
|
data=None,
|
|
headers={'X-Auth-Token': 'fake_token'})
|
|
|
|
def test_send_api_wrong_access_fail(self):
|
|
req_params = {'method': r'security/token',
|
|
'params': {'name': test_config.san_login,
|
|
'password': 'fake_password'},
|
|
'request_type': 'post'}
|
|
fake_value = {'message': ' User name or password error.', 'code': 400}
|
|
mock_request = self.mock_object(
|
|
requests, 'post', mock.Mock(
|
|
return_value=FakeResponse(
|
|
200, fake_value)))
|
|
self.assertRaises(
|
|
exception.VolumeBackendAPIException,
|
|
self.rest_api.send_api,
|
|
method=req_params['method'],
|
|
params=req_params['params'],
|
|
request_type=req_params['request_type'])
|
|
mock_request.assert_called_once_with(
|
|
'http://%s:%s/rest/%s' %
|
|
(test_config.san_ip,
|
|
test_config.san_api_port,
|
|
req_params['method']),
|
|
data=json.dumps(
|
|
req_params['params']),
|
|
headers=None)
|
|
|
|
def test_send_api_token_overtime_fail(self):
|
|
self.rest_api._token = 'fake_token'
|
|
fake_value = {'method': 'fake_url',
|
|
'params': 'fake_params',
|
|
'reuest_type': 'post'}
|
|
fake_out_put = {'message': 'Unauthorized access!', 'code': 301}
|
|
mock_requests = self.mock_object(
|
|
requests, 'post', mock.Mock(
|
|
return_value=FakeResponse(
|
|
200, fake_out_put)))
|
|
self.assertRaises(exception.VolumeDriverException,
|
|
self.rest_api.send_api,
|
|
method='fake_url',
|
|
params='fake_params',
|
|
request_type='post')
|
|
mock_requests.assert_called_once_with(
|
|
'http://%s:%s/rest/%s' %
|
|
(test_config.san_ip,
|
|
test_config.san_api_port,
|
|
fake_value['method']),
|
|
data=json.dumps('fake_params'),
|
|
headers={
|
|
'X-Auth-Token': 'fake_token'})
|
|
|
|
def test_send_api_fail(self):
|
|
self.rest_api._token = 'fake_token'
|
|
fake_output = {'code': 999, 'message': 'fake_message'}
|
|
mock_request = self.mock_object(
|
|
requests, 'post', mock.Mock(
|
|
return_value=FakeResponse(
|
|
200, fake_output)))
|
|
self.assertRaises(
|
|
exception.VolumeBackendAPIException,
|
|
self.rest_api.send_api,
|
|
method='fake_method',
|
|
params='fake_params',
|
|
request_type='post')
|
|
mock_request.assert_called_once_with(
|
|
'http://%s:%s/rest/%s' %
|
|
(test_config.san_ip,
|
|
test_config.san_api_port,
|
|
'fake_method'),
|
|
data=json.dumps('fake_params'),
|
|
headers={'X-Auth-Token': 'fake_token'}
|
|
)
|
|
|
|
|
|
@ddt.ddt
|
|
class AS13000DriverTestCase(test.TestCase):
|
|
def __init__(self, *args, **kwds):
|
|
super(AS13000DriverTestCase, self).__init__(*args, **kwds)
|
|
self._ctxt = context.get_admin_context()
|
|
self.configuration = test_config
|
|
|
|
def setUp(self):
|
|
self.rest_api = as13000_driver.RestAPIExecutor(
|
|
test_config.san_ip,
|
|
test_config.san_api_port,
|
|
test_config.san_login,
|
|
test_config.san_password)
|
|
self.as13000_san = as13000_driver.AS13000Driver(
|
|
configuration=self.configuration)
|
|
super(AS13000DriverTestCase, self).setUp()
|
|
|
|
@ddt.data(None, 'pool1')
|
|
def test_do_setup(self, meta_pool):
|
|
mock_login = self.mock_object(as13000_driver.RestAPIExecutor,
|
|
'login', mock.Mock())
|
|
fake_nodes = [{'healthStatus': 1, 'ip': 'fakeip1'},
|
|
{'healthStatus': 1, 'ip': 'fakeip2'},
|
|
{'healthStatus': 1, 'ip': 'fakeip3'}]
|
|
mock_gcs = self.mock_object(self.as13000_san,
|
|
'_get_cluster_status',
|
|
mock.Mock(return_value=fake_nodes))
|
|
fake_pools = {
|
|
'pool1': {'name': 'pool1', 'type': '1'},
|
|
'pool2': {'name': 'pool2', 'type': 2}
|
|
}
|
|
mock_gpi = self.mock_object(self.as13000_san,
|
|
'_get_pools_info',
|
|
mock.Mock(return_value=fake_pools))
|
|
mock_cp = self.mock_object(self.as13000_san,
|
|
'_check_pools',
|
|
mock.Mock())
|
|
mock_cmp = self.mock_object(self.as13000_san,
|
|
'_check_meta_pool',
|
|
mock.Mock())
|
|
|
|
self.as13000_san.meta_pool = meta_pool
|
|
self.as13000_san.pools = ['pool1', 'pool2']
|
|
self.as13000_san.do_setup(self._ctxt)
|
|
|
|
mock_login.assert_called_once()
|
|
mock_gcs.assert_called_once()
|
|
if meta_pool:
|
|
mock_gpi.assert_called_with(['pool1', 'pool2', 'pool1'])
|
|
else:
|
|
mock_gpi.assert_called_with(['pool1', 'pool2'])
|
|
self.assertEqual('pool1', self.as13000_san.meta_pool)
|
|
mock_cp.assert_called_once()
|
|
mock_cmp.assert_called_once()
|
|
|
|
def test_check_for_setup_error(self):
|
|
mock_sg = self.mock_object(configuration.Configuration, 'safe_get',
|
|
mock.Mock(return_value='fake_config'))
|
|
self.as13000_san.nodes = [{'fakenode': 'fake_name'}]
|
|
self.as13000_san.check_for_setup_error()
|
|
mock_sg.assert_called()
|
|
|
|
def test_check_for_setup_error_no_healthy_node_fail(self):
|
|
mock_sg = self.mock_object(configuration.Configuration, 'safe_get',
|
|
mock.Mock(return_value='fake_config'))
|
|
self.as13000_san.nodes = []
|
|
self.assertRaises(exception.VolumeDriverException,
|
|
self.as13000_san.check_for_setup_error)
|
|
mock_sg.assert_called()
|
|
|
|
def test_check_for_setup_error_no_config_fail(self):
|
|
mock_sg = self.mock_object(configuration.Configuration, 'safe_get',
|
|
mock.Mock(return_value=None))
|
|
self.as13000_san.nodes = []
|
|
self.assertRaises(exception.InvalidConfigurationValue,
|
|
self.as13000_san.check_for_setup_error)
|
|
mock_sg.assert_called()
|
|
|
|
def test__check_pools(self):
|
|
fake_pools_info = {
|
|
'pool1': {'name': 'pool1', 'type': '1'},
|
|
'pool2': {'name': 'pool2', 'type': 1}
|
|
}
|
|
self.as13000_san.pools = ['pool1']
|
|
self.as13000_san.pools_info = fake_pools_info
|
|
self.as13000_san._check_pools()
|
|
|
|
def test__check_pools_fail(self):
|
|
fake_pools_info = {
|
|
'pool1': {'name': 'pool1', 'type': '1'},
|
|
'pool2': {'name': 'pool2', 'type': 1}
|
|
}
|
|
self.as13000_san.pools = ['pool0, pool1']
|
|
self.as13000_san.pools_info = fake_pools_info
|
|
self.assertRaises(exception.InvalidInput,
|
|
self.as13000_san._check_pools)
|
|
|
|
def test__check_meta_pool(self):
|
|
fake_pools_info = {
|
|
'pool1': {'name': 'pool1', 'type': 2},
|
|
'pool2': {'name': 'pool2', 'type': 1}
|
|
}
|
|
self.as13000_san.meta_pool = 'pool2'
|
|
self.as13000_san.pools_info = fake_pools_info
|
|
self.as13000_san._check_meta_pool()
|
|
|
|
@ddt.data(None, 'pool0', 'pool1')
|
|
def test__check_meta_pool_failed(self, meta_pool):
|
|
fake_pools_info = {
|
|
'pool1': {'name': 'pool1', 'type': 2},
|
|
'pool2': {'name': 'pool2', 'type': 1}
|
|
}
|
|
|
|
self.as13000_san.meta_pool = meta_pool
|
|
self.as13000_san.pools_info = fake_pools_info
|
|
self.assertRaises(exception.InvalidInput,
|
|
self.as13000_san._check_meta_pool)
|
|
|
|
@mock.patch.object(as13000_driver.RestAPIExecutor,
|
|
'send_rest_api')
|
|
def test_create_volume(self, mock_rest):
|
|
volume = fake_volume.fake_volume_obj(self._ctxt, host='H@B#P')
|
|
self.as13000_san.pools_info = {'P': {'name': 'P', 'type': 1}}
|
|
self.as13000_san.meta_pool = 'meta_pool'
|
|
self.as13000_san.create_volume(volume)
|
|
|
|
mock_rest.assert_called_once_with(
|
|
method='block/lvm',
|
|
params={
|
|
"name": volume.name.replace('-', '_'),
|
|
"capacity": volume.size * 1024,
|
|
"dataPool": 'P',
|
|
"dataPoolType": 1,
|
|
"metaPool": 'meta_pool'
|
|
},
|
|
request_type='post')
|
|
|
|
@ddt.data(1, 2)
|
|
def test_create_volume_from_snapshot(self, size):
|
|
volume = fake_volume.fake_volume_obj(self._ctxt, size=size)
|
|
volume2 = fake_volume.fake_volume_obj(self._ctxt)
|
|
snapshot = fake_snapshot.fake_snapshot_obj(self._ctxt, volume=volume2)
|
|
|
|
mock_eh = self.mock_object(volume_utils,
|
|
'extract_host',
|
|
mock.Mock(return_value='fake_pool'))
|
|
_tnd_mock = mock.Mock(side_effect=('source_volume',
|
|
'dest_volume',
|
|
'snapshot'))
|
|
mock_tnd = self.mock_object(self.as13000_san,
|
|
'_trans_name_down',
|
|
_tnd_mock)
|
|
mock_lock_op = self.mock_object(self.as13000_san,
|
|
'_snapshot_lock_op',
|
|
mock.Mock())
|
|
mock_rest = self.mock_object(as13000_driver.RestAPIExecutor,
|
|
'send_rest_api',
|
|
mock.Mock())
|
|
mock_fv = self.mock_object(self.as13000_san,
|
|
'_filling_volume',
|
|
mock.Mock())
|
|
mock_wvf = self.mock_object(self.as13000_san,
|
|
'_wait_volume_filled',
|
|
mock.Mock())
|
|
mock_ev = self.mock_object(self.as13000_san, 'extend_volume',
|
|
mock.Mock())
|
|
|
|
self.as13000_san.create_volume_from_snapshot(volume, snapshot)
|
|
|
|
lock_op_calls = [
|
|
mock.call('lock', 'source_volume', 'snapshot', 'fake_pool'),
|
|
mock.call('unlock', 'source_volume', 'snapshot', 'fake_pool')
|
|
]
|
|
mock_lock_op.assert_has_calls(lock_op_calls)
|
|
mock_fv.assert_called_once_with('dest_volume', 'fake_pool')
|
|
mock_wvf.assert_called_once_with('dest_volume', 'fake_pool')
|
|
|
|
mock_eh.assert_called()
|
|
mock_tnd.assert_called()
|
|
params = {
|
|
'originalLvm': 'source_volume',
|
|
'originalPool': 'fake_pool',
|
|
'originalSnap': 'snapshot',
|
|
'name': 'dest_volume',
|
|
'pool': 'fake_pool'}
|
|
mock_rest.assert_called_once_with(method='snapshot/volume/cloneLvm',
|
|
params=params,
|
|
request_type='post')
|
|
if size == 2:
|
|
mock_ev.assert_called_once_with(volume, size)
|
|
|
|
def test_create_volume_from_snapshot_fail(self):
|
|
volume = fake_volume.fake_volume_obj(self._ctxt)
|
|
snapshot = fake_snapshot.fake_snapshot_obj(self._ctxt, volume_size=10)
|
|
self.assertRaises(
|
|
exception.InvalidInput,
|
|
self.as13000_san.create_volume_from_snapshot, volume, snapshot)
|
|
|
|
@ddt.data(1, 2)
|
|
def test_create_cloned_volume(self, size):
|
|
volume = fake_volume.fake_volume_obj(self._ctxt, size=size)
|
|
volume_src = fake_volume.fake_volume_obj(self._ctxt)
|
|
mock_eh = self.mock_object(volume_utils,
|
|
'extract_host',
|
|
mock.Mock(return_value='fake_pool'))
|
|
mock_tnd = self.mock_object(
|
|
self.as13000_san, '_trans_name_down', mock.Mock(
|
|
side_effect=('fake_name1', 'fake_name2')))
|
|
mock_rest = self.mock_object(as13000_driver.RestAPIExecutor,
|
|
'send_rest_api',
|
|
mock.Mock())
|
|
mock_ev = self.mock_object(self.as13000_san,
|
|
'extend_volume',
|
|
mock.Mock())
|
|
self.as13000_san.create_cloned_volume(volume, volume_src)
|
|
mock_eh.assert_called()
|
|
mock_tnd.assert_called()
|
|
method = 'block/lvm/clone'
|
|
params = {
|
|
'srcVolumeName': 'fake_name2',
|
|
'srcPoolName': 'fake_pool',
|
|
'destVolumeName': 'fake_name1',
|
|
'destPoolName': 'fake_pool'}
|
|
request_type = 'post'
|
|
mock_rest.assert_called_once_with(
|
|
method=method, params=params, request_type=request_type)
|
|
if size == 2:
|
|
mock_ev.assert_called_once_with(volume, size)
|
|
|
|
def test_create_clone_volume_fail(self):
|
|
volume = fake_volume.fake_volume_obj(self._ctxt)
|
|
volume_source = fake_volume.fake_volume_obj(self._ctxt, size=2)
|
|
self.assertRaises(
|
|
exception.InvalidInput,
|
|
self.as13000_san.create_cloned_volume, volume, volume_source)
|
|
|
|
def test_extend_volume(self):
|
|
volume = fake_volume.fake_volume_obj(self._ctxt)
|
|
mock_tnd = self.mock_object(
|
|
self.as13000_san, '_trans_name_down', mock.Mock(
|
|
return_value='fake_name'))
|
|
mock_cv = self.mock_object(self.as13000_san,
|
|
'_check_volume',
|
|
mock.Mock(return_value=True))
|
|
mock_eh = self.mock_object(volume_utils,
|
|
'extract_host',
|
|
mock.Mock(return_value='fake_pool'))
|
|
mock_rest = self.mock_object(as13000_driver.RestAPIExecutor,
|
|
'send_rest_api',
|
|
mock.Mock())
|
|
self.as13000_san.extend_volume(volume, 10)
|
|
mock_tnd.assert_called_once_with(volume.name)
|
|
mock_cv.assert_called_once_with(volume)
|
|
mock_eh.assert_called_once_with(volume.host, level='pool')
|
|
method = 'block/lvm'
|
|
request_type = 'put'
|
|
params = {'pool': 'fake_pool',
|
|
'name': 'fake_name',
|
|
'newCapacity': 10240}
|
|
mock_rest.assert_called_once_with(method=method,
|
|
request_type=request_type,
|
|
params=params)
|
|
|
|
def test_extend_volume_fail(self):
|
|
volume = fake_volume.fake_volume_obj(self._ctxt)
|
|
mock_tnd = self.mock_object(
|
|
self.as13000_san, '_trans_name_down', mock.Mock(
|
|
return_value='fake_name'))
|
|
mock_cv = self.mock_object(self.as13000_san,
|
|
'_check_volume',
|
|
mock.Mock(return_value=False))
|
|
self.assertRaises(exception.VolumeDriverException,
|
|
self.as13000_san.extend_volume, volume, 10)
|
|
mock_tnd.assert_called_once_with(volume.name)
|
|
mock_cv.assert_called_once_with(volume)
|
|
|
|
@ddt.data(True, False)
|
|
def test_delete_volume(self, volume_exist):
|
|
volume = fake_volume.fake_volume_obj(self._ctxt)
|
|
mock_eh = self.mock_object(volume_utils,
|
|
'extract_host',
|
|
mock.Mock(return_value='fake_pool'))
|
|
mock_tnd = self.mock_object(
|
|
self.as13000_san, '_trans_name_down', mock.Mock(
|
|
return_value='fake_name'))
|
|
mock_cv = self.mock_object(self.as13000_san,
|
|
'_check_volume',
|
|
mock.Mock(return_value=volume_exist))
|
|
mock_rest = self.mock_object(as13000_driver.RestAPIExecutor,
|
|
'send_rest_api',
|
|
mock.Mock())
|
|
self.as13000_san.delete_volume(volume)
|
|
mock_tnd.assert_called_once_with(volume.name)
|
|
mock_cv.assert_called_once_with(volume)
|
|
|
|
if volume_exist:
|
|
mock_eh.assert_called_once_with(volume.host, level='pool')
|
|
|
|
method = 'block/lvm?pool=%s&lvm=%s' % ('fake_pool', 'fake_name')
|
|
request_type = 'delete'
|
|
mock_rest.assert_called_once_with(method=method,
|
|
request_type=request_type)
|
|
|
|
def test_create_snapshot(self):
|
|
volume = fake_volume.fake_volume_obj(self._ctxt)
|
|
snapshot = fake_snapshot.fake_snapshot_obj(self._ctxt, volume=volume)
|
|
mock_eh = self.mock_object(volume_utils,
|
|
'extract_host',
|
|
mock.Mock(return_value='fake_pool'))
|
|
mock_cv = self.mock_object(self.as13000_san,
|
|
'_check_volume',
|
|
mock.Mock(return_value=True))
|
|
mock_tnd = self.mock_object(
|
|
self.as13000_san, '_trans_name_down', mock.Mock(
|
|
side_effect=('fake_name', 'fake_snap')))
|
|
mock_rest = self.mock_object(as13000_driver.RestAPIExecutor,
|
|
'send_rest_api',
|
|
mock.Mock())
|
|
self.as13000_san.create_snapshot(snapshot)
|
|
|
|
mock_eh.assert_called_once_with(volume.host, level='pool')
|
|
mock_tnd.assert_called()
|
|
mock_cv.assert_called_once_with(snapshot.volume)
|
|
method = 'snapshot/volume'
|
|
params = {'snapName': 'fake_snap',
|
|
'volumeName': 'fake_name',
|
|
'poolName': 'fake_pool',
|
|
'snapType': 'r'}
|
|
request_type = 'post'
|
|
mock_rest.assert_called_once_with(method=method,
|
|
params=params,
|
|
request_type=request_type)
|
|
|
|
def test_create_snapshot_fail(self):
|
|
volume = fake_volume.fake_volume_obj(self._ctxt)
|
|
snapshot = fake_snapshot.fake_snapshot_obj(self._ctxt, volume=volume)
|
|
mock_cv = self.mock_object(self.as13000_san,
|
|
'_check_volume',
|
|
mock.Mock(return_value=False))
|
|
self.assertRaises(exception.VolumeDriverException,
|
|
self.as13000_san.create_snapshot, snapshot)
|
|
mock_cv.assert_called_once_with(snapshot.volume)
|
|
|
|
def test_delete_snapshot(self):
|
|
volume = fake_volume.fake_volume_obj(self._ctxt)
|
|
snapshot = fake_snapshot.fake_snapshot_obj(self._ctxt, volume=volume)
|
|
mock_eh = self.mock_object(volume_utils,
|
|
'extract_host',
|
|
mock.Mock(return_value='fake_pool'))
|
|
mock_cv = self.mock_object(self.as13000_san,
|
|
'_check_volume',
|
|
mock.Mock(return_value=True))
|
|
mock_tnd = self.mock_object(
|
|
self.as13000_san, '_trans_name_down', mock.Mock(
|
|
side_effect=('fake_name', 'fake_snap')))
|
|
mock_rest = self.mock_object(as13000_driver.RestAPIExecutor,
|
|
'send_rest_api',
|
|
mock.Mock())
|
|
self.as13000_san.delete_snapshot(snapshot)
|
|
|
|
mock_eh.assert_called_once_with(volume.host, level='pool')
|
|
mock_tnd.assert_called()
|
|
mock_cv.assert_called_once_with(snapshot.volume)
|
|
|
|
method = ('snapshot/volume?snapName=%s&volumeName=%s&poolName=%s'
|
|
% ('fake_snap', 'fake_name', 'fake_pool'))
|
|
request_type = 'delete'
|
|
mock_rest.assert_called_once_with(method=method,
|
|
request_type=request_type)
|
|
|
|
def test_delete_snapshot_fail(self):
|
|
volume = fake_volume.fake_volume_obj(self._ctxt)
|
|
snapshot = fake_snapshot.fake_snapshot_obj(self._ctxt, volume=volume)
|
|
mock_cv = self.mock_object(self.as13000_san,
|
|
'_check_volume',
|
|
mock.Mock(return_value=False))
|
|
self.assertRaises(exception.VolumeDriverException,
|
|
self.as13000_san.delete_snapshot, snapshot)
|
|
mock_cv.assert_called_once_with(snapshot.volume)
|
|
|
|
@ddt.data((time.time() - 3000), (time.time() - 4000))
|
|
def test__update_volume_stats(self, time_token):
|
|
self.as13000_san.VENDOR = 'INSPUR'
|
|
self.as13000_san.VERSION = 'V1.3.1'
|
|
self.as13000_san.PROTOCOL = 'iSCSI'
|
|
mock_sg = self.mock_object(configuration.Configuration, 'safe_get',
|
|
mock.Mock(return_value='fake_backend_name'))
|
|
fake_pool_backend = [{'pool_name': 'fake_pool'},
|
|
{'pool_name': 'fake_pool1'}]
|
|
self.as13000_san.pools = ['fake_pool']
|
|
mock_gps = self.mock_object(self.as13000_san, '_get_pools_stats',
|
|
mock.Mock(return_value=fake_pool_backend))
|
|
self.as13000_san._stats = None
|
|
self.as13000_san._token_time = time_token
|
|
self.as13000_san.token_available_time = 3600
|
|
mock_login = self.mock_object(as13000_driver.RestAPIExecutor,
|
|
'login')
|
|
|
|
self.as13000_san._update_volume_stats()
|
|
backend_data = {'driver_version': 'V1.3.1',
|
|
'pools': [{'pool_name': 'fake_pool'}],
|
|
'storage_protocol': 'iSCSI',
|
|
'vendor_name': 'INSPUR',
|
|
'volume_backend_name': 'fake_backend_name'}
|
|
|
|
self.assertEqual(backend_data, self.as13000_san._stats)
|
|
mock_sg.assert_called_once_with('volume_backend_name')
|
|
mock_gps.assert_called_once()
|
|
if (time.time() - time_token) > 3600:
|
|
mock_login.assert_called_once()
|
|
else:
|
|
mock_login.assert_not_called()
|
|
|
|
@ddt.data((4, u'127.0.0.1', '3260'),
|
|
(6, u'FF01::101', '3260'))
|
|
@ddt.unpack
|
|
def test__build_target_portal(self, version, ip, port):
|
|
portal = self.as13000_san._build_target_portal(ip, port)
|
|
if version == 4:
|
|
self.assertEqual(portal, '127.0.0.1:3260')
|
|
else:
|
|
self.assertEqual(portal, '[FF01::101]:3260')
|
|
|
|
@ddt.data((True, True, True),
|
|
(True, True, False),
|
|
(False, True, True),
|
|
(False, True, False),
|
|
(False, False, True),
|
|
(False, False, False),
|
|
(True, False, True),
|
|
(True, False, False))
|
|
@ddt.unpack
|
|
def test_initialize_connection(self, host_exist, multipath, chap_enabled):
|
|
volume = fake_volume.fake_volume_obj(self._ctxt)
|
|
connector = {'multipath': multipath,
|
|
'ip': 'fake_ip',
|
|
'host': 'fake_host'}
|
|
self.as13000_san.configuration.use_chap_auth = chap_enabled
|
|
fakenode = [{'name': 'fake_name1', 'ip': 'node_ip1'},
|
|
{'name': 'fake_name2', 'ip': 'node_ip2'},
|
|
{'name': 'fake_name3', 'ip': 'node_ip3'}]
|
|
self.as13000_san.nodes = fakenode
|
|
if multipath:
|
|
mock_gtfc = self.mock_object(
|
|
self.as13000_san,
|
|
'_get_target_from_conn',
|
|
mock.Mock(return_value=(host_exist,
|
|
'target_name',
|
|
['fake_name1', 'fake_name2'])))
|
|
else:
|
|
mock_gtfc = self.mock_object(
|
|
self.as13000_san,
|
|
'_get_target_from_conn',
|
|
mock.Mock(return_value=(host_exist,
|
|
'target_name',
|
|
['fake_name1'])))
|
|
|
|
mock_altt = self.mock_object(self.as13000_san,
|
|
'_add_lun_to_target',
|
|
mock.Mock())
|
|
mock_ct = self.mock_object(self.as13000_san,
|
|
'_create_target',
|
|
mock.Mock())
|
|
mock_ahtt = self.mock_object(self.as13000_san,
|
|
'_add_host_to_target',
|
|
mock.Mock())
|
|
mock_actt = self.mock_object(self.as13000_san,
|
|
'_add_chap_to_target',
|
|
mock.Mock())
|
|
mock_gli = self.mock_object(self.as13000_san,
|
|
'_get_lun_id',
|
|
mock.Mock(return_value='1'))
|
|
mock_rr = self.mock_object(random, 'randint',
|
|
mock.Mock(return_value='12345678'))
|
|
mock_btp = self.mock_object(self.as13000_san,
|
|
'_build_target_portal',
|
|
mock.Mock(side_effect=['node_ip1:3260',
|
|
'node_ip2:3260',
|
|
'node_ip3:3260']))
|
|
|
|
connect_info = self.as13000_san.initialize_connection(
|
|
volume, connector)
|
|
|
|
expect_conn_data = {
|
|
'target_discovered': True,
|
|
'volume_id': volume.id,
|
|
}
|
|
if host_exist:
|
|
if multipath:
|
|
expect_conn_data.update({
|
|
'target_portals': ['node_ip1:3260', 'node_ip2:3260'],
|
|
'target_luns': [1] * 2,
|
|
'target_iqns': ['target_name'] * 2
|
|
})
|
|
else:
|
|
expect_conn_data.update({
|
|
'target_portal': 'node_ip1:3260',
|
|
'target_lun': 1,
|
|
'target_iqn': 'target_name'
|
|
})
|
|
else:
|
|
target_name = 'target.inspur.fake_host-12345678'
|
|
if multipath:
|
|
expect_conn_data.update({
|
|
'target_portals': ['node_ip1:3260',
|
|
'node_ip2:3260',
|
|
'node_ip3:3260'],
|
|
'target_luns': [1] * 3,
|
|
'target_iqns': [target_name] * 3
|
|
})
|
|
else:
|
|
expect_conn_data.update({
|
|
'target_portal': 'node_ip1:3260',
|
|
'target_lun': 1,
|
|
'target_iqn': target_name
|
|
})
|
|
|
|
if chap_enabled:
|
|
expect_conn_data['auth_method'] = 'CHAP'
|
|
expect_conn_data['auth_username'] = 'fakeuser'
|
|
expect_conn_data['auth_password'] = 'fakepass'
|
|
|
|
expect_datas = {
|
|
'driver_volume_type': 'iscsi',
|
|
'data': expect_conn_data
|
|
}
|
|
|
|
self.assertEqual(expect_datas, connect_info)
|
|
mock_gtfc.assert_called_once_with('fake_ip')
|
|
mock_altt.assert_called_once()
|
|
if not host_exist:
|
|
mock_ct.assert_called_once()
|
|
mock_ahtt.assert_called_once()
|
|
mock_rr.assert_called_once()
|
|
if chap_enabled:
|
|
mock_actt.assert_called_once()
|
|
|
|
mock_gli.assert_called_once()
|
|
mock_btp.assert_called()
|
|
|
|
@ddt.data(True, False)
|
|
def test_terminate_connection(self, delete_target):
|
|
volume = fake_volume.fake_volume_obj(self._ctxt, host='fakehost')
|
|
connector = {'multipath': False,
|
|
'ip': 'fake_ip',
|
|
'host': 'fake_host'}
|
|
mock_tnd = self.mock_object(self.as13000_san, '_trans_name_down',
|
|
mock.Mock(return_value='fake_volume'))
|
|
fake_target_list = [{'hostIp': ['fake_ip'],
|
|
'name': 'target_name',
|
|
'lun': [
|
|
{'lvm': 'fake_volume', 'lunID': 'fake_id'}]}]
|
|
mock_gtl = self.mock_object(self.as13000_san, '_get_target_list',
|
|
mock.Mock(return_value=fake_target_list))
|
|
mock_dlft = self.mock_object(self.as13000_san,
|
|
'_delete_lun_from_target',
|
|
mock.Mock())
|
|
if delete_target:
|
|
mock_gll = self.mock_object(self.as13000_san, '_get_lun_list',
|
|
mock.Mock(return_value=[]))
|
|
else:
|
|
mock_gll = self.mock_object(self.as13000_san, '_get_lun_list',
|
|
mock.Mock(return_value=[1, 2]))
|
|
mock_dt = self.mock_object(self.as13000_san, '_delete_target',
|
|
mock.Mock())
|
|
self.as13000_san.terminate_connection(volume, connector)
|
|
mock_tnd.assert_called_once_with(volume.name)
|
|
mock_gtl.assert_called_once()
|
|
mock_dlft.assert_called_once_with(lun_id='fake_id',
|
|
target_name='target_name')
|
|
mock_gll.assert_called_once_with('target_name')
|
|
if delete_target:
|
|
mock_dt.assert_called_once_with('target_name')
|
|
else:
|
|
mock_dt.assert_not_called()
|
|
|
|
@ddt.data(True, False)
|
|
def test_terminate_connection_force(self, delete_target):
|
|
volume = fake_volume.fake_volume_obj(self._ctxt, host='fakehost')
|
|
connector = {}
|
|
mock_tnd = self.mock_object(self.as13000_san, '_trans_name_down',
|
|
mock.Mock(return_value='fake_volume'))
|
|
fake_target_list = [{'hostIp': ['fake_hostIp'],
|
|
'name':'target_name',
|
|
'lun':[{'lvm': 'fake_volume',
|
|
'lunID': 'fake_id'}]}]
|
|
mock_gtl = self.mock_object(self.as13000_san, '_get_target_list',
|
|
mock.Mock(return_value=fake_target_list))
|
|
mock_dlft = self.mock_object(self.as13000_san,
|
|
'_delete_lun_from_target',
|
|
mock.Mock())
|
|
if delete_target:
|
|
mock_gll = self.mock_object(self.as13000_san, '_get_lun_list',
|
|
mock.Mock(return_value=[]))
|
|
else:
|
|
mock_gll = self.mock_object(self.as13000_san, '_get_lun_list',
|
|
mock.Mock(return_value=[1, 2]))
|
|
mock_dt = self.mock_object(self.as13000_san, '_delete_target',
|
|
mock.Mock())
|
|
|
|
self.as13000_san.terminate_connection(volume, connector)
|
|
|
|
mock_tnd.assert_called_once_with(volume.name)
|
|
mock_gtl.assert_called_once()
|
|
mock_dlft.assert_called_once_with(lun_id='fake_id',
|
|
target_name='target_name')
|
|
mock_gll.assert_called_once_with('target_name')
|
|
if delete_target:
|
|
mock_dt.assert_called_once_with('target_name')
|
|
else:
|
|
mock_dt.assert_not_called()
|
|
|
|
@mock.patch.object(as13000_driver.RestAPIExecutor,
|
|
'send_rest_api')
|
|
def test__get_pools_info(self, mock_rest):
|
|
fake_pools_data = [{'name': 'pool1', 'type': 1},
|
|
{'name': 'pool2', 'type': 2}]
|
|
mock_rest.return_value = fake_pools_data
|
|
|
|
# get a partial of pools
|
|
result_pools_info = self.as13000_san._get_pools_info(['pool1'])
|
|
self.assertEqual(result_pools_info,
|
|
{'pool1': {'name': 'pool1', 'type': 1}})
|
|
|
|
# get both exist pools
|
|
result_pools_info = self.as13000_san._get_pools_info(['pool1',
|
|
'pool2'])
|
|
self.assertEqual(result_pools_info,
|
|
{'pool1': {'name': 'pool1', 'type': 1},
|
|
'pool2': {'name': 'pool2', 'type': 2}})
|
|
|
|
# get pools not exist
|
|
result_pools_info = self.as13000_san._get_pools_info(['pool1',
|
|
'pool2',
|
|
'pool3'])
|
|
self.assertEqual(result_pools_info,
|
|
{'pool1': {'name': 'pool1', 'type': 1},
|
|
'pool2': {'name': 'pool2', 'type': 2}})
|
|
|
|
def test__get_pools_stats(self):
|
|
pool_date = [{'ID': 'fake_id',
|
|
'name': 'fake_name',
|
|
'totalCapacity': '2t',
|
|
'usedCapacity': '300g'}]
|
|
self.as13000_san.pools = ['fake_name']
|
|
mock_rest = self.mock_object(as13000_driver.RestAPIExecutor,
|
|
'send_rest_api',
|
|
mock.Mock(return_value=pool_date))
|
|
mock_uc = self.mock_object(self.as13000_san, '_unit_convert',
|
|
mock.Mock(side_effect=(2000, 300)))
|
|
pool_info = {
|
|
'pool_name': 'fake_name',
|
|
'total_capacity_gb': 2000,
|
|
'free_capacity_gb': 1700,
|
|
'thin_provisioning_support': True,
|
|
'thick_provisioning_support': False,
|
|
}
|
|
|
|
result_pools = self.as13000_san._get_pools_stats()
|
|
|
|
expect_pools = [pool_info]
|
|
self.assertEqual(expect_pools, result_pools)
|
|
mock_rest.assert_called_once_with(method='block/pool?type=2',
|
|
request_type='get')
|
|
mock_uc.assert_called()
|
|
|
|
@ddt.data('fake_ip3', 'fake_ip5')
|
|
def test__get_target_from_conn(self, host_ip):
|
|
target_list = [
|
|
{
|
|
'hostIp': ['fake_ip1', 'fake_ip2'],
|
|
'name':'fake_target_1',
|
|
'node':['fake_node1', 'fake_node2']
|
|
},
|
|
{
|
|
'hostIp': ['fake_ip3', 'fake_ip4'],
|
|
'name': 'fake_target_2',
|
|
'node': ['fake_node4', 'fake_node3']
|
|
}
|
|
]
|
|
mock_gtl = self.mock_object(self.as13000_san,
|
|
'_get_target_list',
|
|
mock.Mock(return_value=target_list))
|
|
|
|
host_exist, target_name, node = (
|
|
self.as13000_san._get_target_from_conn(host_ip))
|
|
|
|
if host_ip == 'fake_ip3':
|
|
self.assertEqual((True, 'fake_target_2',
|
|
['fake_node4', 'fake_node3']),
|
|
(host_exist, target_name, node))
|
|
else:
|
|
self.assertEqual((False, None, None),
|
|
(host_exist, target_name, node))
|
|
mock_gtl.assert_called_once()
|
|
|
|
def test__get_target_list(self):
|
|
mock_rest = self.mock_object(as13000_driver.RestAPIExecutor,
|
|
'send_rest_api',
|
|
mock.Mock(return_value='fake_date'))
|
|
method = 'block/target/detail'
|
|
request_type = 'get'
|
|
result = self.as13000_san._get_target_list()
|
|
self.assertEqual('fake_date', result)
|
|
mock_rest.assert_called_once_with(method=method,
|
|
request_type=request_type)
|
|
|
|
def test__create_target(self):
|
|
mock_rest = self.mock_object(as13000_driver.RestAPIExecutor,
|
|
'send_rest_api',
|
|
mock.Mock())
|
|
target_name = 'fake_name'
|
|
target_node = 'fake_node'
|
|
method = 'block/target'
|
|
params = {'name': target_name, 'nodeName': target_node}
|
|
request_type = 'post'
|
|
self.as13000_san._create_target(target_name, target_node)
|
|
mock_rest.assert_called_once_with(method=method,
|
|
params=params,
|
|
request_type=request_type)
|
|
|
|
def test__delete_target(self):
|
|
mock_rest = self.mock_object(as13000_driver.RestAPIExecutor,
|
|
'send_rest_api',
|
|
mock.Mock())
|
|
target_name = 'fake_name'
|
|
method = 'block/target?name=%s' % target_name
|
|
request_type = 'delete'
|
|
self.as13000_san._delete_target(target_name)
|
|
mock_rest.assert_called_once_with(method=method,
|
|
request_type=request_type)
|
|
|
|
def test__add_chap_to_target(self):
|
|
mock_rest = self.mock_object(as13000_driver.RestAPIExecutor,
|
|
'send_rest_api',
|
|
mock.Mock())
|
|
target_name = 'fake_name'
|
|
chap_username = 'fake_user'
|
|
chap_password = 'fake_pass'
|
|
self.as13000_san._add_chap_to_target(target_name,
|
|
chap_username,
|
|
chap_password)
|
|
|
|
method = 'block/chap/bond'
|
|
params = {'target': target_name,
|
|
'user': chap_username,
|
|
'password': chap_password}
|
|
request_type = 'post'
|
|
mock_rest.assert_called_once_with(method=method,
|
|
params=params,
|
|
request_type=request_type)
|
|
|
|
def test__add_host_to_target(self):
|
|
mock_rest = self.mock_object(as13000_driver.RestAPIExecutor,
|
|
'send_rest_api',
|
|
mock.Mock())
|
|
target_name = 'fake_name'
|
|
host_ip = 'fake_ip'
|
|
method = 'block/host'
|
|
params = {'name': target_name, 'hostIp': host_ip}
|
|
request_type = 'post'
|
|
self.as13000_san._add_host_to_target(host_ip, target_name)
|
|
mock_rest.assert_called_once_with(method=method,
|
|
params=params,
|
|
request_type=request_type)
|
|
|
|
def test__add_lun_to_target(self):
|
|
volume = fake_volume.fake_volume_obj(self._ctxt, host='fakehost')
|
|
mock_eh = self.mock_object(volume_utils,
|
|
'extract_host',
|
|
mock.Mock(return_value='fake_pool'))
|
|
mock_tnd = self.mock_object(self.as13000_san,
|
|
'_trans_name_down',
|
|
mock.Mock(return_value='fake_name'))
|
|
mock_rest = self.mock_object(as13000_driver.RestAPIExecutor,
|
|
'send_rest_api',
|
|
mock.Mock())
|
|
|
|
target_name = 'fake_target'
|
|
self.as13000_san._add_lun_to_target(target_name, volume)
|
|
method = 'block/lun'
|
|
params = {'name': target_name,
|
|
'pool': 'fake_pool',
|
|
'lvm': 'fake_name'}
|
|
request_type = 'post'
|
|
mock_eh.assert_called_once_with(volume.host, level='pool')
|
|
mock_tnd.assert_called_once_with(volume.name)
|
|
mock_rest.assert_called_once_with(method=method,
|
|
params=params,
|
|
request_type=request_type)
|
|
|
|
def test__add_lun_to_target_retry_3times(self):
|
|
volume = fake_volume.fake_volume_obj(self._ctxt, host='fakehost')
|
|
mock_eh = self.mock_object(volume_utils,
|
|
'extract_host',
|
|
mock.Mock(return_value='fake_pool'))
|
|
mock_tnd = self.mock_object(self.as13000_san,
|
|
'_trans_name_down',
|
|
mock.Mock(return_value='fake_name'))
|
|
mock_rest = self.mock_object(
|
|
as13000_driver.RestAPIExecutor,
|
|
'send_rest_api',
|
|
mock.Mock(side_effect=(exception.VolumeDriverException,
|
|
mock.MagicMock())))
|
|
|
|
target_name = 'fake_target'
|
|
self.as13000_san._add_lun_to_target(target_name, volume)
|
|
method = 'block/lun'
|
|
params = {'name': target_name,
|
|
'pool': 'fake_pool',
|
|
'lvm': 'fake_name'}
|
|
request_type = 'post'
|
|
mock_eh.assert_called_with(volume.host, level='pool')
|
|
mock_tnd.assert_called_with(volume.name)
|
|
mock_rest.assert_called_with(method=method,
|
|
params=params,
|
|
request_type=request_type)
|
|
|
|
def test__add_lun_to_target_fail(self):
|
|
volume = fake_volume.fake_volume_obj(self._ctxt, host='fakehost')
|
|
mock_eh = self.mock_object(volume_utils,
|
|
'extract_host',
|
|
mock.Mock(return_value='fake_pool'))
|
|
mock_tnd = self.mock_object(self.as13000_san,
|
|
'_trans_name_down',
|
|
mock.Mock(return_value='fake_name'))
|
|
mock_rest = self.mock_object(
|
|
as13000_driver.RestAPIExecutor,
|
|
'send_rest_api',
|
|
mock.Mock(side_effect=exception.VolumeDriverException))
|
|
|
|
target_name = 'fake_target'
|
|
self.assertRaises(exception.VolumeDriverException,
|
|
self.as13000_san._add_lun_to_target,
|
|
target_name=target_name,
|
|
volume=volume)
|
|
method = 'block/lun'
|
|
params = {'name': target_name,
|
|
'pool': 'fake_pool',
|
|
'lvm': 'fake_name'}
|
|
request_type = 'post'
|
|
mock_eh.assert_called_with(volume.host, level='pool')
|
|
mock_tnd.assert_called_with(volume.name)
|
|
mock_rest.assert_called_with(method=method,
|
|
params=params,
|
|
request_type=request_type)
|
|
|
|
def test__delete_lun_from_target(self):
|
|
mock_rest = self.mock_object(as13000_driver.RestAPIExecutor,
|
|
'send_rest_api',
|
|
mock.Mock())
|
|
target_name = 'fake_target'
|
|
lun_id = 'fake_id'
|
|
self.as13000_san._delete_lun_from_target(target_name, lun_id)
|
|
method = 'block/lun?name=%s&id=%s&force=1' % (target_name, lun_id)
|
|
request_type = 'delete'
|
|
mock_rest.assert_called_once_with(method=method,
|
|
request_type=request_type)
|
|
|
|
@ddt.data('lock', 'unlock')
|
|
def test__snapshot_lock_op(self, operation):
|
|
mock_rest = self.mock_object(as13000_driver.RestAPIExecutor,
|
|
'send_rest_api',
|
|
mock.Mock())
|
|
vol_name = 'fake_volume'
|
|
snap_name = 'fake_snapshot'
|
|
pool_name = "fake_pool"
|
|
self.as13000_san._snapshot_lock_op(operation,
|
|
vol_name,
|
|
snap_name,
|
|
pool_name)
|
|
|
|
method = 'snapshot/volume/' + operation
|
|
request_type = 'post'
|
|
params = {'snapName': snap_name,
|
|
'volumeName': vol_name,
|
|
'poolName': pool_name}
|
|
mock_rest.assert_called_once_with(method=method,
|
|
params=params,
|
|
request_type=request_type)
|
|
|
|
def test__filling_volume(self):
|
|
mock_rest = self.mock_object(as13000_driver.RestAPIExecutor,
|
|
'send_rest_api',
|
|
mock.Mock())
|
|
vol_name = 'fake_volume'
|
|
pool_name = 'fake_pool'
|
|
self.as13000_san._filling_volume(vol_name, pool_name)
|
|
params = {'pool': 'fake_pool', 'name': 'fake_volume'}
|
|
mock_rest.assert_called_once_with(method='block/lvm/filling',
|
|
params=params,
|
|
request_type='post')
|
|
|
|
def test__wait_volume_filled(self):
|
|
# Need to mock sleep as it is called by @utils.retry
|
|
self.mock_object(time, 'sleep')
|
|
|
|
expected = [{'name': 'fake_v1', 'lvmType': 1}]
|
|
mock_gv = self.mock_object(self.as13000_san, '_get_volumes',
|
|
mock.Mock(return_value=expected))
|
|
self.as13000_san._wait_volume_filled('fake_v1', 'fake_pool')
|
|
mock_gv.assert_called_with('fake_pool')
|
|
|
|
def test__wait_volume_filled_failed(self):
|
|
# Need to mock sleep as it is called by @utils.retry
|
|
self.mock_object(time, 'sleep')
|
|
|
|
expected = [{'name': 'fake_v1', 'lvmType': 2}]
|
|
mock_gv = self.mock_object(self.as13000_san, '_get_volumes',
|
|
mock.Mock(return_value=expected))
|
|
self.assertRaises(exception.VolumeDriverException,
|
|
self.as13000_san._wait_volume_filled,
|
|
'fake_v1',
|
|
'fake_pool')
|
|
mock_gv.assert_called_with('fake_pool')
|
|
|
|
def test__get_lun_list(self):
|
|
target_name = 'fake_name'
|
|
lun_list = ['lun_1', 'lun_2']
|
|
mock_rest = self.mock_object(as13000_driver.RestAPIExecutor,
|
|
'send_rest_api',
|
|
mock.Mock(return_value=lun_list))
|
|
lun_result = self.as13000_san._get_lun_list(target_name)
|
|
self.assertEqual(lun_list, lun_result)
|
|
method = 'block/lun?name=%s' % target_name
|
|
request_type = 'get'
|
|
mock_rest.assert_called_once_with(method=method,
|
|
request_type=request_type)
|
|
|
|
@ddt.data(True, False)
|
|
def test__check_volume(self, exist):
|
|
volume = fake_volume.fake_volume_obj(self._ctxt, host='fakehost')
|
|
mock_eh = self.mock_object(volume_utils,
|
|
'extract_host',
|
|
mock.Mock(return_value='fake_pool'))
|
|
mock_tnd = self.mock_object(self.as13000_san,
|
|
'_trans_name_down',
|
|
mock.Mock(return_value='fake_name'))
|
|
mock_el = self.mock_object(eventlet, 'sleep',
|
|
mock.Mock(return_value=None))
|
|
if exist:
|
|
mock_gv = self.mock_object(self.as13000_san, '_get_volumes',
|
|
mock.Mock(return_value=[
|
|
{'name': 'fake_name'},
|
|
{'name': 'fake_name2'}]))
|
|
else:
|
|
mock_gv = self.mock_object(self.as13000_san, '_get_volumes',
|
|
mock.Mock(return_value=[
|
|
{'name': 'fake_name2'},
|
|
{'name': 'fake_name3'}]))
|
|
expect = self.as13000_san._check_volume(volume)
|
|
self.assertEqual(exist, expect)
|
|
mock_eh.assert_called_once_with(volume.host, 'pool')
|
|
mock_tnd.assert_called_once_with(volume.name)
|
|
if exist:
|
|
mock_gv.assert_called_once_with('fake_pool')
|
|
else:
|
|
mock_gv.assert_called()
|
|
mock_el.assert_called()
|
|
|
|
def test__get_volumes(self):
|
|
volumes = [{'name': 'fake_name1'},
|
|
{'name': 'fake_name2'},
|
|
{'name': 'fake_name3'}]
|
|
pool = 'fake_pool'
|
|
mock_rest = self.mock_object(as13000_driver.RestAPIExecutor,
|
|
'send_rest_api',
|
|
mock.Mock(return_value=volumes))
|
|
result = self.as13000_san._get_volumes(pool)
|
|
method = 'block/lvm?pool=%s' % pool
|
|
request_type = 'get'
|
|
self.assertEqual(volumes, result)
|
|
mock_rest.assert_called_once_with(method=method,
|
|
request_type=request_type)
|
|
|
|
def test__get_cluster_status(self):
|
|
method = 'cluster/node'
|
|
request_type = 'get'
|
|
cluster = 'fake_cluster'
|
|
mock_rest = self.mock_object(as13000_driver.RestAPIExecutor,
|
|
'send_rest_api',
|
|
mock.Mock(return_value=cluster))
|
|
result = self.as13000_san._get_cluster_status()
|
|
self.assertEqual(cluster, result)
|
|
mock_rest.assert_called_once_with(method=method,
|
|
request_type=request_type)
|
|
|
|
@ddt.data(True, False)
|
|
def test__get_lun_id(self, lun_exist):
|
|
volume = fake_volume.fake_volume_obj(self._ctxt, host='fakehost')
|
|
if lun_exist:
|
|
lun_list = [{'id': '01', 'mappingLvm': r'fake_pool/fake_volume1'},
|
|
{'id': '02', 'mappingLvm': r'fake_pool/fake_volume2'}]
|
|
else:
|
|
lun_list = [{'id': '01', 'mappingLvm': r'fake_pool/fake_volume1'},
|
|
{'id': '02', 'mappingLvm': r'fake_pool/fake_volume0'}]
|
|
|
|
mock_eh = self.mock_object(volume_utils,
|
|
'extract_host',
|
|
mock.Mock(return_value='fake_pool'))
|
|
mock_tnd = self.mock_object(self.as13000_san,
|
|
'_trans_name_down',
|
|
mock.Mock(return_value='fake_volume2'))
|
|
mock_gll = self.mock_object(self.as13000_san, '_get_lun_list',
|
|
mock.Mock(return_value=lun_list))
|
|
|
|
lun_id = self.as13000_san._get_lun_id(volume, 'fake_target')
|
|
if lun_exist:
|
|
self.assertEqual('02', lun_id)
|
|
else:
|
|
self.assertIsNone(lun_id)
|
|
|
|
mock_eh.assert_called_once_with(volume.host, level='pool')
|
|
mock_tnd.assert_called_once_with(volume.name)
|
|
mock_gll.assert_called_once_with('fake_target')
|
|
|
|
def test__trans_name_down(self):
|
|
fake_name = 'test-abcd-1234_1234-234'
|
|
expect = 'test_abcd_1234_1234_234'
|
|
result = self.as13000_san._trans_name_down(fake_name)
|
|
self.assertEqual(expect, result)
|
|
|
|
@ddt.data('5000000000', '5000000k', '5000mb', '50G', '5TB', '5PB', '5EB')
|
|
def test__unit_convert(self, capacity):
|
|
trans = {'5000000000': '%.0f' % (float(5000000000) / (1024 ** 3)),
|
|
'5000000k': '%.0f' % (float(5000000) / (1024 ** 2)),
|
|
'5000mb': '%.0f' % (float(5000) / 1024),
|
|
'50G': '%.0f' % float(50),
|
|
'5TB': '%.0f' % (float(5) * 1024),
|
|
'5PB': '%.0f' % (float(5) * (1024 ** 2)),
|
|
'5EB': '%.0f' % (float(5) * (1024 ** 3))}
|
|
expect = float(trans[capacity])
|
|
result = self.as13000_san._unit_convert(capacity)
|
|
self.assertEqual(expect, result)
|