cinder/cinder/tests/unit/test_zadara.py

780 lines
31 KiB
Python

# Copyright (c) 2016 Zadara Storage, Inc.
# 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.
"""
Tests for Zadara VPSA volume driver
"""
import copy
import mock
from six.moves import http_client
from cinder import exception
from cinder import test
from cinder.volume import configuration as conf
from cinder.volume.drivers import zadara
DEFAULT_RUNTIME_VARS = {
'status': 200,
'user': 'test',
'password': 'test_password',
'access_key': '0123456789ABCDEF',
'volumes': [],
'servers': [],
'controllers': [('active_ctrl', {'display-name': 'test_ctrl'})],
'counter': 1000,
'login': """
<hash>
<user>
<updated-at type="datetime">2012-04-30...</updated-at>
<access-key>%s</access-key>
<id type="integer">1</id>
<created-at type="datetime">2012-02-21...</created-at>
<email>jsmith@example.com</email>
<username>jsmith</username>
</user>
<status type="integer">0</status>
</hash>""",
'good': """
<hash>
<status type="integer">0</status>
</hash>""",
'bad_login': """
<hash>
<status type="integer">5</status>
<status-msg>Some message...</status-msg>
</hash>""",
'bad_volume': """
<hash>
<status type="integer">10081</status>
<status-msg>Virtual volume xxx not found</status-msg>
</hash>""",
'bad_server': """
<hash>
<status type="integer">10086</status>
<status-msg>Server xxx not found</status-msg>
</hash>""",
'server_created': """
<create-server-response>
<server-name>%s</server-name>
<status type='integer'>0</status>
</create-server-response>""",
}
RUNTIME_VARS = None
class FakeRequest(object):
def __init__(self, method, url, body):
self.method = method
self.url = url
self.body = body
self.status = RUNTIME_VARS['status']
def read(self):
ops = {'POST': [('/api/users/login.xml', self._login),
('/api/volumes.xml', self._create_volume),
('/api/servers.xml', self._create_server),
('/api/servers/*/volumes.xml', self._attach),
('/api/volumes/*/detach.xml', self._detach),
('/api/volumes/*/expand.xml', self._expand),
('/api/consistency_groups/*/snapshots.xml',
self._create_snapshot),
('/api/consistency_groups/*/clone.xml',
self._create_clone)],
'DELETE': [('/api/volumes/*', self._delete),
('/api/snapshots/*', self._delete_snapshot)],
'GET': [('/api/volumes.xml', self._list_volumes),
('/api/pools.xml', self._list_pools),
('/api/vcontrollers.xml', self._list_controllers),
('/api/servers.xml', self._list_servers),
('/api/consistency_groups/*/snapshots.xml',
self._list_vol_snapshots),
('/api/volumes/*/servers.xml',
self._list_vol_attachments)]
}
ops_list = ops[self.method]
modified_url = self.url.split('?')[0]
for (templ_url, func) in ops_list:
if self._compare_url(modified_url, templ_url):
result = func()
return result
def _compare_url(self, url, template_url):
items = url.split('/')
titems = template_url.split('/')
for (i, titem) in enumerate(titems):
if titem != '*' and titem != items[i]:
return False
return True
def _get_parameters(self, data):
items = data.split('&')
params = {}
for item in items:
if item:
(k, v) = item.split('=')
params[k] = v
return params
def _get_counter(self):
cnt = RUNTIME_VARS['counter']
RUNTIME_VARS['counter'] += 1
return cnt
def _login(self):
params = self._get_parameters(self.body)
if (params['user'] == RUNTIME_VARS['user'] and
params['password'] == RUNTIME_VARS['password']):
return RUNTIME_VARS['login'] % RUNTIME_VARS['access_key']
else:
return RUNTIME_VARS['bad_login']
def _incorrect_access_key(self, params):
return (params['access_key'] != RUNTIME_VARS['access_key'])
def _create_volume(self):
params = self._get_parameters(self.body)
if self._incorrect_access_key(params):
return RUNTIME_VARS['bad_login']
params['display-name'] = params['name']
params['cg-name'] = params['name']
params['snapshots'] = []
params['attachments'] = []
vpsa_vol = 'volume-%07d' % self._get_counter()
RUNTIME_VARS['volumes'].append((vpsa_vol, params))
return RUNTIME_VARS['good']
def _create_server(self):
params = self._get_parameters(self.body)
if self._incorrect_access_key(params):
return RUNTIME_VARS['bad_login']
params['display-name'] = params['display_name']
vpsa_srv = 'srv-%07d' % self._get_counter()
RUNTIME_VARS['servers'].append((vpsa_srv, params))
return RUNTIME_VARS['server_created'] % vpsa_srv
def _attach(self):
params = self._get_parameters(self.body)
if self._incorrect_access_key(params):
return RUNTIME_VARS['bad_login']
srv = self.url.split('/')[3]
vol = params['volume_name[]']
for (vol_name, params) in RUNTIME_VARS['volumes']:
if vol_name == vol:
attachments = params['attachments']
if srv in attachments:
# already attached - ok
return RUNTIME_VARS['good']
else:
attachments.append(srv)
return RUNTIME_VARS['good']
return RUNTIME_VARS['bad_volume']
def _detach(self):
params = self._get_parameters(self.body)
if self._incorrect_access_key(params):
return RUNTIME_VARS['bad_login']
vol = self.url.split('/')[3]
srv = params['server_name[]']
for (vol_name, params) in RUNTIME_VARS['volumes']:
if vol_name == vol:
attachments = params['attachments']
if srv not in attachments:
return RUNTIME_VARS['bad_server']
else:
attachments.remove(srv)
return RUNTIME_VARS['good']
return RUNTIME_VARS['bad_volume']
def _expand(self):
params = self._get_parameters(self.body)
if self._incorrect_access_key(params):
return RUNTIME_VARS['bad_login']
vol = self.url.split('/')[3]
capacity = params['capacity']
for (vol_name, params) in RUNTIME_VARS['volumes']:
if vol_name == vol:
params['capacity'] = capacity
return RUNTIME_VARS['good']
return RUNTIME_VARS['bad_volume']
def _create_snapshot(self):
params = self._get_parameters(self.body)
if self._incorrect_access_key(params):
return RUNTIME_VARS['bad_login']
cg_name = self.url.split('/')[3]
snap_name = params['display_name']
for (vol_name, params) in RUNTIME_VARS['volumes']:
if params['cg-name'] == cg_name:
snapshots = params['snapshots']
if snap_name in snapshots:
# already attached
return RUNTIME_VARS['bad_volume']
else:
snapshots.append(snap_name)
return RUNTIME_VARS['good']
return RUNTIME_VARS['bad_volume']
def _delete_snapshot(self):
snap = self.url.split('/')[3].split('.')[0]
for (vol_name, params) in RUNTIME_VARS['volumes']:
if snap in params['snapshots']:
params['snapshots'].remove(snap)
return RUNTIME_VARS['good']
return RUNTIME_VARS['bad_volume']
def _create_clone(self):
params = self._get_parameters(self.body)
if self._incorrect_access_key(params):
return RUNTIME_VARS['bad_login']
params['display-name'] = params['name']
params['cg-name'] = params['name']
params['capacity'] = 1
params['snapshots'] = []
params['attachments'] = []
vpsa_vol = 'volume-%07d' % self._get_counter()
RUNTIME_VARS['volumes'].append((vpsa_vol, params))
return RUNTIME_VARS['good']
def _delete(self):
vol = self.url.split('/')[3].split('.')[0]
for (vol_name, params) in RUNTIME_VARS['volumes']:
if vol_name == vol:
if params['attachments']:
# there are attachments - should be volume busy error
return RUNTIME_VARS['bad_volume']
else:
RUNTIME_VARS['volumes'].remove((vol_name, params))
return RUNTIME_VARS['good']
return RUNTIME_VARS['bad_volume']
def _generate_list_resp(self, header, footer, body, lst, vol):
resp = header
for (obj, params) in lst:
if vol:
resp += body % (obj,
params['display-name'],
params['cg-name'],
params['capacity'])
else:
resp += body % (obj, params['display-name'])
resp += footer
return resp
def _list_volumes(self):
header = """<show-volumes-response>
<status type='integer'>0</status>
<volumes type='array'>"""
footer = "</volumes></show-volumes-response>"
body = """<volume>
<name>%s</name>
<display-name>%s</display-name>
<cg-name>%s</cg-name>
<status>Available</status>
<virtual-capacity type='integer'>%s</virtual-capacity>
<allocated-capacity type='integer'>1</allocated-capacity>
<raid-group-name>r5</raid-group-name>
<cache>write-through</cache>
<created-at type='datetime'>2012-01-28...</created-at>
<modified-at type='datetime'>2012-01-28...</modified-at>
</volume>"""
return self._generate_list_resp(header,
footer,
body,
RUNTIME_VARS['volumes'],
True)
def _list_controllers(self):
header = """<show-vcontrollers-response>
<status type='integer'>0</status>
<vcontrollers type='array'>"""
footer = "</vcontrollers></show-vcontrollers-response>"
body = """<vcontroller>
<name>%s</name>
<display-name>%s</display-name>
<state>active</state>
<target>iqn.2011-04.com.zadarastorage:vsa-xxx:1</target>
<iscsi-ip>1.1.1.1</iscsi-ip>
<mgmt-ip>1.1.1.1</mgmt-ip>
<software-ver>0.0.09-05.1--77.7</software-ver>
<heartbeat1>ok</heartbeat1>
<heartbeat2>ok</heartbeat2>
<vpsa-chap-user>test_chap_user</vpsa-chap-user>
<vpsa-chap-secret>test_chap_secret</vpsa-chap-secret>
</vcontroller>"""
return self._generate_list_resp(header,
footer,
body,
RUNTIME_VARS['controllers'],
False)
def _list_pools(self):
header = """<show-pools-response>
<status type="integer">0</status>
<pools type="array">
"""
footer = "</pools></show-pools-response>"
return header + footer
def _list_servers(self):
header = """<show-servers-response>
<status type='integer'>0</status>
<servers type='array'>"""
footer = "</servers></show-servers-response>"
body = """<server>
<name>%s</name>
<display-name>%s</display-name>
<iqn>%s</iqn>
<status>Active</status>
<created-at type='datetime'>2012-01-28...</created-at>
<modified-at type='datetime'>2012-01-28...</modified-at>
</server>"""
resp = header
for (obj, params) in RUNTIME_VARS['servers']:
resp += body % (obj, params['display-name'], params['iqn'])
resp += footer
return resp
def _get_server_obj(self, name):
for (srv_name, params) in RUNTIME_VARS['servers']:
if srv_name == name:
return params
def _list_vol_attachments(self):
vol = self.url.split('/')[3]
header = """<show-servers-response>
<status type="integer">0</status>
<servers type="array">"""
footer = "</servers></show-servers-response>"
body = """<server>
<name>%s</name>
<display-name>%s</display-name>
<iqn>%s</iqn>
<target>iqn.2011-04.com.zadarastorage:vsa-xxx:1</target>
<lun>0</lun>
</server>"""
for (vol_name, params) in RUNTIME_VARS['volumes']:
if vol_name == vol:
attachments = params['attachments']
resp = header
for server in attachments:
srv_params = self._get_server_obj(server)
resp += body % (server,
srv_params['display-name'],
srv_params['iqn'])
resp += footer
return resp
return RUNTIME_VARS['bad_volume']
def _list_vol_snapshots(self):
cg_name = self.url.split('/')[3]
header = """<show-snapshots-on-cg-response>
<status type="integer">0</status>
<snapshots type="array">"""
footer = "</snapshots></show-snapshots-on-cg-response>"
body = """<snapshot>
<name>%s</name>
<display-name>%s</display-name>
<status>normal</status>
<cg-name>%s</cg-name>
<pool-name>pool-00000001</pool-name>
</snapshot>"""
for (vol_name, params) in RUNTIME_VARS['volumes']:
if params['cg-name'] == cg_name:
snapshots = params['snapshots']
resp = header
for snap in snapshots:
resp += body % (snap, snap, cg_name)
resp += footer
return resp
return RUNTIME_VARS['bad_volume']
class FakeHTTPConnection(object):
"""A fake http_client.HTTPConnection for zadara volume driver tests."""
def __init__(self, host, port, use_ssl=False):
self.host = host
self.port = port
self.use_ssl = use_ssl
self.req = None
def request(self, method, url, body):
self.req = FakeRequest(method, url, body)
def getresponse(self):
return self.req
def close(self):
self.req = None
class FakeHTTPSConnection(FakeHTTPConnection):
def __init__(self, host, port):
super(FakeHTTPSConnection, self).__init__(host, port, use_ssl=True)
class ZadaraVPSADriverTestCase(test.TestCase):
"""Test case for Zadara VPSA volume driver."""
@mock.patch.object(http_client, 'HTTPConnection', FakeHTTPConnection)
@mock.patch.object(http_client, 'HTTPSConnection', FakeHTTPSConnection)
def setUp(self):
super(ZadaraVPSADriverTestCase, self).setUp()
global RUNTIME_VARS
RUNTIME_VARS = copy.deepcopy(DEFAULT_RUNTIME_VARS)
self.configuration = mock.Mock(conf.Configuration(None))
self.configuration.append_config_values(zadara.zadara_opts)
self.configuration.reserved_percentage = 10
self.configuration.zadara_use_iser = True
self.configuration.zadara_vpsa_host = '192.168.5.5'
self.configuration.zadara_vpsa_port = '80'
self.configuration.zadara_user = 'test'
self.configuration.zadara_password = 'test_password'
self.configuration.zadara_vpsa_poolname = 'pool-0001'
self.configuration.zadara_vol_encrypt = False
self.configuration.zadara_vol_name_template = 'OS_%s'
self.configuration.zadara_vpsa_use_ssl = False
self.configuration.zadara_default_snap_policy = False
self.driver = (zadara.ZadaraVPSAISCSIDriver(
configuration=self.configuration))
self.driver.do_setup(None)
@mock.patch.object(http_client, 'HTTPConnection', FakeHTTPConnection)
@mock.patch.object(http_client, 'HTTPSConnection', FakeHTTPSConnection)
def test_create_destroy(self):
"""Create/Delete volume."""
volume = {'name': 'test_volume_01', 'size': 1}
self.driver.create_volume(volume)
self.driver.delete_volume(volume)
@mock.patch.object(http_client, 'HTTPConnection', FakeHTTPConnection)
@mock.patch.object(http_client, 'HTTPSConnection', FakeHTTPSConnection)
def test_create_destroy_multiple(self):
"""Create/Delete multiple volumes."""
self.driver.create_volume({'name': 'test_volume_01', 'size': 1})
self.driver.create_volume({'name': 'test_volume_02', 'size': 2})
self.driver.create_volume({'name': 'test_volume_03', 'size': 3})
self.driver.delete_volume({'name': 'test_volume_02'})
self.driver.delete_volume({'name': 'test_volume_03'})
self.driver.delete_volume({'name': 'test_volume_01'})
self.driver.delete_volume({'name': 'test_volume_04'})
@mock.patch.object(http_client, 'HTTPConnection', FakeHTTPConnection)
@mock.patch.object(http_client, 'HTTPSConnection', FakeHTTPSConnection)
def test_destroy_non_existent(self):
"""Delete non-existent volume."""
volume = {'name': 'test_volume_02', 'size': 1}
self.driver.delete_volume(volume)
@mock.patch.object(http_client, 'HTTPConnection', FakeHTTPConnection)
@mock.patch.object(http_client, 'HTTPSConnection', FakeHTTPSConnection)
def test_empty_apis(self):
"""Test empty func (for coverage only)."""
context = None
volume = {'name': 'test_volume_01', 'size': 1}
self.driver.create_export(context, volume)
self.driver.ensure_export(context, volume)
self.driver.remove_export(context, volume)
self.assertRaises(NotImplementedError,
self.driver.local_path,
None)
self.driver.check_for_setup_error()
@mock.patch.object(http_client, 'HTTPConnection', FakeHTTPConnection)
@mock.patch.object(http_client, 'HTTPSConnection', FakeHTTPSConnection)
def test_volume_attach_detach(self):
"""Test volume attachment and detach."""
volume = {'name': 'test_volume_01', 'size': 1, 'id': 123}
connector = dict(initiator='test_iqn.1')
self.driver.create_volume(volume)
props = self.driver.initialize_connection(volume, connector)
self.assertEqual('iser', props['driver_volume_type'])
data = props['data']
self.assertEqual('1.1.1.1:3260', data['target_portal'])
self.assertEqual('iqn.2011-04.com.zadarastorage:vsa-xxx:1',
data['target_iqn'])
self.assertEqual(int('0'), data['target_lun'])
self.assertEqual(123, data['volume_id'])
self.assertEqual('CHAP', data['auth_method'])
self.assertEqual('test_chap_user', data['auth_username'])
self.assertEqual('test_chap_secret', data['auth_password'])
self.driver.terminate_connection(volume, connector)
self.driver.delete_volume(volume)
@mock.patch.object(http_client, 'HTTPConnection', FakeHTTPConnection)
@mock.patch.object(http_client, 'HTTPSConnection', FakeHTTPSConnection)
def test_volume_attach_multiple_detach(self):
"""Test multiple volume attachment and detach."""
volume = {'name': 'test_volume_01', 'size': 1, 'id': 123}
connector1 = dict(initiator='test_iqn.1')
connector2 = dict(initiator='test_iqn.2')
connector3 = dict(initiator='test_iqn.3')
self.driver.create_volume(volume)
self.driver.initialize_connection(volume, connector1)
self.driver.initialize_connection(volume, connector2)
self.driver.initialize_connection(volume, connector3)
self.driver.terminate_connection(volume, connector1)
self.driver.terminate_connection(volume, connector3)
self.driver.terminate_connection(volume, connector2)
self.driver.delete_volume(volume)
@mock.patch.object(http_client, 'HTTPConnection', FakeHTTPConnection)
@mock.patch.object(http_client, 'HTTPSConnection', FakeHTTPSConnection)
def test_wrong_attach_params(self):
"""Test different wrong attach scenarios."""
volume1 = {'name': 'test_volume_01', 'size': 1, 'id': 101}
connector1 = dict(initiator='test_iqn.1')
self.assertRaises(exception.VolumeNotFound,
self.driver.initialize_connection,
volume1, connector1)
@mock.patch.object(http_client, 'HTTPConnection', FakeHTTPConnection)
@mock.patch.object(http_client, 'HTTPSConnection', FakeHTTPSConnection)
def test_wrong_detach_params(self):
"""Test different wrong detachment scenarios."""
volume1 = {'name': 'test_volume_01', 'size': 1, 'id': 101}
volume2 = {'name': 'test_volume_02', 'size': 1, 'id': 102}
volume3 = {'name': 'test_volume_03', 'size': 1, 'id': 103}
connector1 = dict(initiator='test_iqn.1')
connector2 = dict(initiator='test_iqn.2')
connector3 = dict(initiator='test_iqn.3')
self.driver.create_volume(volume1)
self.driver.create_volume(volume2)
self.driver.initialize_connection(volume1, connector1)
self.driver.initialize_connection(volume2, connector2)
self.assertRaises(exception.ZadaraServerNotFound,
self.driver.terminate_connection,
volume1, connector3)
self.assertRaises(exception.VolumeNotFound,
self.driver.terminate_connection,
volume3, connector1)
self.assertRaises(exception.FailedCmdWithDump,
self.driver.terminate_connection,
volume1, connector2)
@mock.patch.object(http_client, 'HTTPConnection', FakeHTTPConnection)
@mock.patch.object(http_client, 'HTTPSConnection', FakeHTTPSConnection)
def test_wrong_login_reply(self):
"""Test wrong login reply."""
RUNTIME_VARS['login'] = """<hash>
<access-key>%s</access-key>
<status type="integer">0</status>
</hash>"""
self.assertRaises(exception.MalformedResponse,
self.driver.do_setup, None)
RUNTIME_VARS['login'] = """
<hash>
<user>
<updated-at type="datetime">2012-04-30...</updated-at>
<id type="integer">1</id>
<created-at type="datetime">2012-02-21...</created-at>
<email>jsmith@example.com</email>
<username>jsmith</username>
</user>
<access-key>%s</access-key>
<status type="integer">0</status>
</hash>"""
self.assertRaises(exception.MalformedResponse,
self.driver.do_setup, None)
@mock.patch.object(http_client, 'HTTPConnection', FakeHTTPConnection)
@mock.patch.object(http_client, 'HTTPSConnection', FakeHTTPSConnection)
def test_ssl_use(self):
"""Coverage test for SSL connection."""
self.flags(zadara_vpsa_use_ssl=True)
self.driver.do_setup(None)
self.flags(zadara_vpsa_use_ssl=False)
@mock.patch.object(http_client, 'HTTPConnection', FakeHTTPConnection)
@mock.patch.object(http_client, 'HTTPSConnection', FakeHTTPSConnection)
def test_bad_http_response(self):
"""Coverage test for non-good HTTP response."""
RUNTIME_VARS['status'] = 400
volume = {'name': 'test_volume_01', 'size': 1}
self.assertRaises(exception.BadHTTPResponseStatus,
self.driver.create_volume, volume)
@mock.patch.object(http_client, 'HTTPConnection', FakeHTTPConnection)
@mock.patch.object(http_client, 'HTTPSConnection', FakeHTTPSConnection)
def test_delete_without_detach(self):
"""Test volume deletion without detach."""
volume1 = {'name': 'test_volume_01', 'size': 1, 'id': 101}
connector1 = dict(initiator='test_iqn.1')
connector2 = dict(initiator='test_iqn.2')
connector3 = dict(initiator='test_iqn.3')
self.driver.create_volume(volume1)
self.driver.initialize_connection(volume1, connector1)
self.driver.initialize_connection(volume1, connector2)
self.driver.initialize_connection(volume1, connector3)
self.driver.delete_volume(volume1)
@mock.patch.object(http_client, 'HTTPConnection', FakeHTTPConnection)
@mock.patch.object(http_client, 'HTTPSConnection', FakeHTTPSConnection)
def test_no_active_ctrl(self):
RUNTIME_VARS['controllers'] = []
volume = {'name': 'test_volume_01', 'size': 1, 'id': 123}
connector = dict(initiator='test_iqn.1')
self.driver.create_volume(volume)
self.assertRaises(exception.ZadaraVPSANoActiveController,
self.driver.initialize_connection,
volume, connector)
@mock.patch.object(http_client, 'HTTPConnection', FakeHTTPConnection)
@mock.patch.object(http_client, 'HTTPSConnection', FakeHTTPSConnection)
def test_create_destroy_snapshot(self):
"""Create/Delete snapshot test."""
volume = {'name': 'test_volume_01', 'size': 1}
snapshot = {'name': 'snap_01',
'volume_name': volume['name']}
self.driver.create_volume(volume)
self.assertRaises(exception.VolumeDriverException,
self.driver.create_snapshot,
{'name': snapshot['name'],
'volume_name': 'wrong_vol'})
self.driver.create_snapshot(snapshot)
# Deleted should succeed for missing volume
self.driver.delete_snapshot({'name': snapshot['name'],
'volume_name': 'wrong_vol'})
# Deleted should succeed for missing snap
self.driver.delete_snapshot({'name': 'wrong_snap',
'volume_name': volume['name']})
self.driver.delete_snapshot(snapshot)
self.driver.delete_volume(volume)
@mock.patch.object(http_client, 'HTTPConnection', FakeHTTPConnection)
@mock.patch.object(http_client, 'HTTPSConnection', FakeHTTPSConnection)
def test_expand_volume(self):
"""Expand volume test."""
volume = {'name': 'test_volume_01', 'size': 10}
volume2 = {'name': 'test_volume_02', 'size': 10}
self.driver.create_volume(volume)
self.assertRaises(exception.ZadaraVolumeNotFound,
self.driver.extend_volume,
volume2, 15)
self.assertRaises(exception.InvalidInput,
self.driver.extend_volume,
volume, 5)
self.driver.extend_volume(volume, 15)
self.driver.delete_volume(volume)
@mock.patch.object(http_client, 'HTTPConnection', FakeHTTPConnection)
@mock.patch.object(http_client, 'HTTPSConnection', FakeHTTPSConnection)
def test_create_destroy_clones(self):
"""Create/Delete clones test."""
volume1 = {'name': 'test_volume_01', 'id': '01', 'size': 1}
volume2 = {'name': 'test_volume_02', 'id': '02', 'size': 2}
volume3 = {'name': 'test_volume_03', 'id': '03', 'size': 1}
snapshot = {'name': 'snap_01',
'id': '01',
'volume_name': volume1['name'],
'volume_size': 1}
self.driver.create_volume(volume1)
self.driver.create_snapshot(snapshot)
# Test invalid vol reference
self.assertRaises(exception.VolumeNotFound,
self.driver.create_volume_from_snapshot,
volume2,
{'name': snapshot['name'],
'id': snapshot['id'],
'volume_name': 'wrong_vol'})
# Test invalid snap reference
self.assertRaises(exception.SnapshotNotFound,
self.driver.create_volume_from_snapshot,
volume2,
{'name': 'wrong_snap',
'id': 'wrong_id',
'volume_name': snapshot['volume_name']})
# Test invalid src_vref for volume clone
self.assertRaises(exception.VolumeNotFound,
self.driver.create_cloned_volume,
volume3, volume2)
self.driver.create_volume_from_snapshot(volume2, snapshot)
self.driver.create_cloned_volume(volume3, volume1)
self.driver.delete_volume(volume3)
self.driver.delete_volume(volume2)
self.driver.delete_snapshot(snapshot)
self.driver.delete_volume(volume1)
@mock.patch.object(http_client, 'HTTPConnection', FakeHTTPConnection)
@mock.patch.object(http_client, 'HTTPSConnection', FakeHTTPSConnection)
def test_get_volume_stats(self):
"""Get stats test."""
self.configuration.safe_get.return_value = 'ZadaraVPSAISCSIDriver'
data = self.driver.get_volume_stats(True)
self.assertEqual('Zadara Storage', data['vendor_name'])
self.assertEqual('unknown', data['total_capacity_gb'])
self.assertEqual('unknown', data['free_capacity_gb'])
self.assertEqual({'total_capacity_gb': 'unknown',
'free_capacity_gb': 'unknown',
'reserved_percentage':
self.configuration.reserved_percentage,
'QoS_support': False,
'vendor_name': 'Zadara Storage',
'driver_version': self.driver.VERSION,
'storage_protocol': 'iSER',
'volume_backend_name': 'ZadaraVPSAISCSIDriver'},
data)