EMC ScaleIO Cinder Driver
This patch adds a Cinder volume driver for EMC ScaleIO product. The ScaleIO driver supports the following Cinder features: * Create/delete volume * Create/delete snapshot * Create volume from snapshot * Create cloned volume * Extend volume implements blueprint scaleio-cinder-volume-driver Change-Id: I7007e4ec36586d98cbf53e4f322ab25aa9b414c6
This commit is contained in:
parent
e2de169c6e
commit
185abac1c2
|
@ -0,0 +1,161 @@
|
|||
# Copyright (c) 2013 - 2015 EMC Corporation.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
import copy
|
||||
import requests
|
||||
|
||||
from cinder import test
|
||||
from cinder.tests.unit.volume.drivers.emc.scaleio import mocks
|
||||
|
||||
|
||||
class CustomResponseMode(object):
|
||||
"""A context manager to define a custom set of per-request response modes.
|
||||
|
||||
Example:
|
||||
|
||||
with CustomResponseMode(self, **{
|
||||
'some/api/path': RESPONSE_MODE.Valid,
|
||||
'another/api/path': RESPONSE_MODE.BadStatus,
|
||||
'last/api/path': MockResponse('some data',
|
||||
status_code=403),
|
||||
}):
|
||||
self.assertRaises(SomeException, self.driver.api_call, data)
|
||||
"""
|
||||
def __init__(self, test_instance, **kwargs):
|
||||
self.test_instance = test_instance
|
||||
self.custom_responses = kwargs
|
||||
self.current_responses = None
|
||||
|
||||
def __enter__(self):
|
||||
self.current_responses = self.test_instance.HTTPS_MOCK_RESPONSES
|
||||
|
||||
https_responses = copy.deepcopy(
|
||||
self.test_instance.HTTPS_MOCK_RESPONSES
|
||||
)
|
||||
current_mode = self.test_instance.current_https_response_mode
|
||||
|
||||
for call, new_mode in self.custom_responses.items():
|
||||
if isinstance(new_mode, mocks.MockHTTPSResponse):
|
||||
https_responses[current_mode][call] = new_mode
|
||||
else:
|
||||
https_responses[current_mode][call] = \
|
||||
self.test_instance.get_https_response(call, new_mode)
|
||||
|
||||
self.test_instance.HTTPS_MOCK_RESPONSES = https_responses
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
self.test_instance.HTTPS_MOCK_RESPONSES = self.current_responses
|
||||
|
||||
|
||||
class TestScaleIODriver(test.TestCase):
|
||||
"""Base ``TestCase`` subclass for the ``ScaleIODriver``"""
|
||||
RESPONSE_MODE = type(str('ResponseMode'), (object, ), dict(
|
||||
Valid='0',
|
||||
Invalid='1',
|
||||
BadStatus='2',
|
||||
))
|
||||
__RESPONSE_MODE_NAMES = {
|
||||
'0': 'Valid',
|
||||
'1': 'Invalid',
|
||||
'2': 'BadStatus',
|
||||
}
|
||||
|
||||
BAD_STATUS_RESPONSE = mocks.MockHTTPSResponse(
|
||||
{
|
||||
'errorCode': 500,
|
||||
'message': 'BadStatus Response Test',
|
||||
}, 500
|
||||
)
|
||||
|
||||
HTTPS_MOCK_RESPONSES = {}
|
||||
__COMMON_HTTPS_MOCK_RESPONSES = {
|
||||
RESPONSE_MODE.Valid: {
|
||||
'login': 'login_token',
|
||||
},
|
||||
RESPONSE_MODE.BadStatus: {
|
||||
'login': mocks.MockHTTPSResponse(
|
||||
{
|
||||
'errorCode': 403,
|
||||
'message': 'Bad Login Response Test',
|
||||
}, 403
|
||||
),
|
||||
},
|
||||
}
|
||||
__https_response_mode = RESPONSE_MODE.Valid
|
||||
log = None
|
||||
|
||||
def setUp(self):
|
||||
"""Setup a test case environment.
|
||||
|
||||
Creates a ``ScaleIODriver`` instance
|
||||
Mocks the ``requests.get/post`` methods to return
|
||||
``MockHTTPSResponse``'s instead.
|
||||
"""
|
||||
super(TestScaleIODriver, self).setUp()
|
||||
self.driver = mocks.ScaleIODriver()
|
||||
|
||||
self.mock_object(requests, 'get', self.do_request)
|
||||
self.mock_object(requests, 'post', self.do_request)
|
||||
|
||||
def do_request(self, url, *args, **kwargs):
|
||||
"""Do a fake GET/POST API request.
|
||||
|
||||
Splits `url` on '/api/' to get the what API call is, then returns
|
||||
the value of `self.HTTPS_MOCK_RESPONSES[<response_mode>][<api_call>]`
|
||||
converting to a `MockHTTPSResponse` if necessary.
|
||||
|
||||
:raises test.TestingException: If the current mode/api_call does not
|
||||
exist.
|
||||
:returns MockHTTPSResponse:
|
||||
"""
|
||||
return self.get_https_response(url.split('/api/')[1])
|
||||
|
||||
def set_https_response_mode(self, mode=RESPONSE_MODE.Valid):
|
||||
"""Set the HTTPS response mode.
|
||||
|
||||
RESPONSE_MODE.Valid: Respond with valid data
|
||||
RESPONSE_MODE.Invalid: Respond with invalid data
|
||||
RESPONSE_MODE.BadStatus: Response with not-OK status code.
|
||||
"""
|
||||
self.__https_response_mode = mode
|
||||
|
||||
def get_https_response(self, api_path, mode=None):
|
||||
if mode is None:
|
||||
mode = self.__https_response_mode
|
||||
|
||||
try:
|
||||
response = self.HTTPS_MOCK_RESPONSES[mode][api_path]
|
||||
except KeyError:
|
||||
try:
|
||||
response = self.__COMMON_HTTPS_MOCK_RESPONSES[mode][api_path]
|
||||
except KeyError:
|
||||
raise test.TestingException(
|
||||
'Mock API Endpoint not implemented: [{}]{}'.format(
|
||||
self.__RESPONSE_MODE_NAMES[mode], api_path
|
||||
)
|
||||
)
|
||||
|
||||
if not isinstance(response, mocks.MockHTTPSResponse):
|
||||
return mocks.MockHTTPSResponse(response, 200)
|
||||
return response
|
||||
|
||||
@property
|
||||
def current_https_response_mode(self):
|
||||
return self.__https_response_mode
|
||||
|
||||
def https_response_mode_name(self, mode):
|
||||
return self.__RESPONSE_MODE_NAMES[mode]
|
||||
|
||||
def custom_response_mode(self, **kwargs):
|
||||
return CustomResponseMode(self, **kwargs)
|
|
@ -0,0 +1,116 @@
|
|||
# Copyright (c) 2013 - 2015 EMC Corporation.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
import json
|
||||
import requests
|
||||
import six
|
||||
|
||||
from cinder.volume import configuration as conf
|
||||
from cinder.volume.drivers.emc import scaleio
|
||||
from oslo_config import cfg
|
||||
|
||||
|
||||
class ScaleIODriver(scaleio.ScaleIODriver):
|
||||
"""Mock ScaleIO Driver class.
|
||||
|
||||
Provides some fake configuration options
|
||||
"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
configuration = conf.Configuration(
|
||||
[
|
||||
cfg.StrOpt('fake', default=None),
|
||||
],
|
||||
None
|
||||
)
|
||||
|
||||
# Override the defaults to fake values
|
||||
configuration.set_override('san_ip', override='127.0.0.1')
|
||||
configuration.set_override('sio_rest_server_port', override='8888')
|
||||
configuration.set_override('san_login', override='test')
|
||||
configuration.set_override('san_password', override='pass')
|
||||
configuration.set_override('sio_storage_pool_id', override='test_pool')
|
||||
configuration.set_override('sio_protection_domain_id',
|
||||
override='test_domain')
|
||||
configuration.set_override('sio_storage_pools',
|
||||
override='test_domain:test_pool')
|
||||
|
||||
super(ScaleIODriver, self).__init__(configuration=configuration,
|
||||
*args,
|
||||
**kwargs)
|
||||
|
||||
def update_consistencygroup(self, context, group, add_volumes=None,
|
||||
remove_volumes=None):
|
||||
pass
|
||||
|
||||
def local_path(self, volume):
|
||||
pass
|
||||
|
||||
def reenable_replication(self, context, volume):
|
||||
pass
|
||||
|
||||
def manage_existing(self, volume, existing_ref):
|
||||
pass
|
||||
|
||||
def promote_replica(self, context, volume):
|
||||
pass
|
||||
|
||||
def delete_consistencygroup(self, context, group):
|
||||
pass
|
||||
|
||||
def create_consistencygroup_from_src(self, context, group, volumes,
|
||||
cgsnapshot=None, snapshots=None):
|
||||
pass
|
||||
|
||||
def create_replica_test_volume(self, volume, src_vref):
|
||||
pass
|
||||
|
||||
def create_consistencygroup(self, context, group):
|
||||
pass
|
||||
|
||||
def manage_existing_get_size(self, volume, existing_ref):
|
||||
pass
|
||||
|
||||
def unmanage(self, volume):
|
||||
pass
|
||||
|
||||
def create_cgsnapshot(self, context, cgsnapshot):
|
||||
pass
|
||||
|
||||
def delete_cgsnapshot(self, context, cgsnapshot):
|
||||
pass
|
||||
|
||||
|
||||
class MockHTTPSResponse(requests.Response):
|
||||
"""Mock HTTP Response
|
||||
|
||||
Defines the https replies from the mocked calls to do_request()
|
||||
"""
|
||||
def __init__(self, content, status_code=200):
|
||||
super(MockHTTPSResponse, self).__init__()
|
||||
|
||||
self._content = content
|
||||
self.status_code = status_code
|
||||
|
||||
def json(self, **kwargs):
|
||||
if isinstance(self._content, six.string_types):
|
||||
return super(MockHTTPSResponse, self).json(**kwargs)
|
||||
|
||||
return self._content
|
||||
|
||||
@property
|
||||
def text(self):
|
||||
if not isinstance(self._content, six.string_types):
|
||||
return json.dumps(self._content)
|
||||
|
||||
return super(MockHTTPSResponse, self).text
|
|
@ -0,0 +1,91 @@
|
|||
# Copyright (c) 2013 - 2015 EMC Corporation.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
import urllib
|
||||
|
||||
import six
|
||||
|
||||
from cinder import context
|
||||
from cinder import exception
|
||||
from cinder.tests.unit import fake_volume
|
||||
from cinder.tests.unit.volume.drivers.emc import scaleio
|
||||
|
||||
|
||||
class TestCreateClonedVolume(scaleio.TestScaleIODriver):
|
||||
"""Test cases for ``ScaleIODriver.create_cloned_volume()``"""
|
||||
STORAGE_POOL_ID = six.text_type('1')
|
||||
STORAGE_POOL_NAME = 'SP1'
|
||||
|
||||
PROT_DOMAIN_ID = six.text_type('1')
|
||||
PROT_DOMAIN_NAME = 'PD1'
|
||||
|
||||
def setUp(self):
|
||||
"""Setup a test case environment.
|
||||
|
||||
Creates fake volume objects and sets up the required API responses.
|
||||
"""
|
||||
super(TestCreateClonedVolume, self).setUp()
|
||||
ctx = context.RequestContext('fake', 'fake', auth_token=True)
|
||||
|
||||
self.src_volume = fake_volume.fake_volume_obj(ctx)
|
||||
self.src_volume_name_2x_enc = urllib.quote(
|
||||
urllib.quote(
|
||||
self.driver.id_to_base64(self.src_volume.id)
|
||||
)
|
||||
)
|
||||
|
||||
self.new_volume = fake_volume.fake_volume_obj(
|
||||
ctx, **{'id': 'cloned', 'name': 'cloned_volume'}
|
||||
)
|
||||
|
||||
self.new_volume_name_2x_enc = urllib.quote(
|
||||
urllib.quote(
|
||||
self.driver.id_to_base64(self.new_volume.id)
|
||||
)
|
||||
)
|
||||
self.HTTPS_MOCK_RESPONSES = {
|
||||
self.RESPONSE_MODE.Valid: {
|
||||
'types/Volume/instances/getByName::' +
|
||||
self.src_volume_name_2x_enc: self.src_volume.id,
|
||||
'instances/System/action/snapshotVolumes': '"{}"'.format(
|
||||
self.new_volume.id
|
||||
),
|
||||
},
|
||||
self.RESPONSE_MODE.BadStatus: {
|
||||
'instances/System/action/snapshotVolumes::':
|
||||
self.BAD_STATUS_RESPONSE,
|
||||
'types/Volume/instances/getByName::' +
|
||||
self.src_volume_name_2x_enc: self.BAD_STATUS_RESPONSE,
|
||||
},
|
||||
self.RESPONSE_MODE.Invalid: {
|
||||
'types/Volume/instances/getByName::' +
|
||||
self.src_volume_name_2x_enc: None,
|
||||
},
|
||||
}
|
||||
|
||||
def test_bad_login(self):
|
||||
self.set_https_response_mode(self.RESPONSE_MODE.BadStatus)
|
||||
self.assertRaises(exception.VolumeBackendAPIException,
|
||||
self.driver.create_cloned_volume,
|
||||
self.new_volume, self.src_volume)
|
||||
|
||||
def test_invalid_source_volume(self):
|
||||
self.set_https_response_mode(self.RESPONSE_MODE.Invalid)
|
||||
self.assertRaises(exception.VolumeBackendAPIException,
|
||||
self.driver.create_cloned_volume,
|
||||
self.new_volume, self.src_volume)
|
||||
|
||||
def test_create_cloned_volume(self):
|
||||
self.set_https_response_mode(self.RESPONSE_MODE.Valid)
|
||||
self.driver.create_cloned_volume(self.new_volume, self.src_volume)
|
|
@ -0,0 +1,103 @@
|
|||
# Copyright (c) 2013 - 2015 EMC Corporation.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
import urllib
|
||||
|
||||
import six
|
||||
|
||||
from cinder import context
|
||||
from cinder import exception
|
||||
from cinder.tests.unit import fake_snapshot
|
||||
from cinder.tests.unit.volume.drivers.emc import scaleio
|
||||
from cinder.tests.unit.volume.drivers.emc.scaleio import mocks
|
||||
|
||||
|
||||
class TestCreateSnapShot(scaleio.TestScaleIODriver):
|
||||
"""Test cases for ``ScaleIODriver.create_snapshot()``"""
|
||||
STORAGE_POOL_ID = six.text_type('1')
|
||||
STORAGE_POOL_NAME = 'SP1'
|
||||
|
||||
PROT_DOMAIN_ID = six.text_type('1')
|
||||
PROT_DOMAIN_NAME = 'PD1'
|
||||
|
||||
def setUp(self):
|
||||
"""Setup a test case environment.
|
||||
|
||||
Creates fake volume and snapshot objects and sets up the required
|
||||
API responses.
|
||||
"""
|
||||
super(TestCreateSnapShot, self).setUp()
|
||||
ctx = context.RequestContext('fake', 'fake', auth_token=True)
|
||||
|
||||
self.snapshot = fake_snapshot.fake_snapshot_obj(ctx)
|
||||
self.volume_name_2x_enc = urllib.quote(
|
||||
urllib.quote(self.driver.id_to_base64(self.snapshot.volume_id))
|
||||
)
|
||||
self.snapshot_name_2x_enc = urllib.quote(
|
||||
urllib.quote(self.driver.id_to_base64(self.snapshot.id))
|
||||
)
|
||||
|
||||
self.HTTPS_MOCK_RESPONSES = {
|
||||
self.RESPONSE_MODE.Valid: {
|
||||
'types/Volume/instances/getByName::' +
|
||||
self.volume_name_2x_enc: '"{}"'.format(
|
||||
self.snapshot.volume_id
|
||||
),
|
||||
'instances/System/action/snapshotVolumes': self.snapshot.id,
|
||||
'types/Volume/instances/getByName::' +
|
||||
self.snapshot_name_2x_enc: self.snapshot.id,
|
||||
},
|
||||
self.RESPONSE_MODE.BadStatus: {
|
||||
'types/Volume/instances/getByName::' +
|
||||
self.volume_name_2x_enc: self.BAD_STATUS_RESPONSE,
|
||||
'types/Volume/instances/getByName::' +
|
||||
self.snapshot_name_2x_enc: mocks.MockHTTPSResponse(
|
||||
{
|
||||
'errorCode': 401,
|
||||
'message': 'BadStatus Snapshot Test',
|
||||
}, 401
|
||||
),
|
||||
},
|
||||
self.RESPONSE_MODE.Invalid: {
|
||||
'types/Volume/instances/getByName::' +
|
||||
self.volume_name_2x_enc: None,
|
||||
'instances/System/action/snapshotVolumes':
|
||||
mocks.MockHTTPSResponse(
|
||||
{
|
||||
'errorCode': 400,
|
||||
'message': 'Invalid Volume Snapshot Test'
|
||||
}, 400
|
||||
),
|
||||
},
|
||||
}
|
||||
|
||||
def test_bad_login(self):
|
||||
self.set_https_response_mode(self.RESPONSE_MODE.BadStatus)
|
||||
self.assertRaises(
|
||||
exception.VolumeBackendAPIException,
|
||||
self.driver.create_snapshot,
|
||||
self.snapshot
|
||||
)
|
||||
|
||||
def test_invalid_volume(self):
|
||||
self.set_https_response_mode(self.RESPONSE_MODE.Invalid)
|
||||
self.assertRaises(
|
||||
exception.VolumeBackendAPIException,
|
||||
self.driver.create_snapshot,
|
||||
self.snapshot
|
||||
)
|
||||
|
||||
def test_create_snapshot(self):
|
||||
self.set_https_response_mode(self.RESPONSE_MODE.Valid)
|
||||
self.driver.create_snapshot(self.snapshot)
|
|
@ -0,0 +1,138 @@
|
|||
# Copyright (c) 2013 - 2015 EMC Corporation.
|
||||
# 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.
|
||||
from cinder import context
|
||||
from cinder import exception
|
||||
from cinder.tests.unit import fake_volume
|
||||
|
||||
from cinder.tests.unit.volume.drivers.emc import scaleio
|
||||
|
||||
|
||||
class TestCreateVolume(scaleio.TestScaleIODriver):
|
||||
"""Test cases for ``ScaleIODriver.create_volume()``"""
|
||||
|
||||
PROTECTION_DOMAIN_ID = 'test_prot_id'
|
||||
PROTECTION_DOMAIN_NAME = 'test_prot_name'
|
||||
|
||||
STORAGE_POOL_ID = 'test_pool_id'
|
||||
STORAGE_POOL_NAME = 'test_pool_name'
|
||||
|
||||
def setUp(self):
|
||||
"""Setup a test case environment.
|
||||
|
||||
Creates a fake volume object and sets up the required API responses.
|
||||
"""
|
||||
super(TestCreateVolume, self).setUp()
|
||||
ctx = context.RequestContext('fake', 'fake', auth_token=True)
|
||||
|
||||
self.volume = fake_volume.fake_volume_obj(ctx)
|
||||
|
||||
self.HTTPS_MOCK_RESPONSES = {
|
||||
self.RESPONSE_MODE.Valid: {
|
||||
'types/Volume/instances/getByName::' +
|
||||
self.volume.name: '"{}"'.format(self.volume.id),
|
||||
'types/Volume/instances': [
|
||||
{
|
||||
'Id': self.volume.id,
|
||||
'Name': self.volume.name,
|
||||
'volumeSizeInKb': self.volume.size,
|
||||
'isObfuscated': False,
|
||||
'creationTime': self.volume.launched_at,
|
||||
'mappingToAllSdcsEnabled': False,
|
||||
'mappingSdcInfoList': [],
|
||||
'mappingScsiInitiatorList': [],
|
||||
'ancestorVolumeId': '',
|
||||
'vtreeId': '',
|
||||
'storagePoolId': self.STORAGE_POOL_ID,
|
||||
'useRmcache': False,
|
||||
}
|
||||
],
|
||||
'types/Domain/instances/getByName::' +
|
||||
self.PROTECTION_DOMAIN_NAME:
|
||||
'"{}"'.format(self.PROTECTION_DOMAIN_ID),
|
||||
'types/Pool/instances/getByName::{},{}'.format(
|
||||
self.PROTECTION_DOMAIN_ID,
|
||||
self.STORAGE_POOL_NAME
|
||||
): '"{}"'.format(self.STORAGE_POOL_ID),
|
||||
},
|
||||
self.RESPONSE_MODE.Invalid: {
|
||||
'types/Domain/instances/getByName::' +
|
||||
self.PROTECTION_DOMAIN_NAME: None,
|
||||
'types/Pool/instances/getByName::{},{}'.format(
|
||||
self.PROTECTION_DOMAIN_ID,
|
||||
self.STORAGE_POOL_NAME
|
||||
): None,
|
||||
},
|
||||
self.RESPONSE_MODE.BadStatus: {
|
||||
'types/Volume/instances': self.BAD_STATUS_RESPONSE,
|
||||
'types/Domain/instances/getByName::' +
|
||||
self.PROTECTION_DOMAIN_NAME: self.BAD_STATUS_RESPONSE,
|
||||
'types/Pool/instances/getByName::{},{}'.format(
|
||||
self.PROTECTION_DOMAIN_ID,
|
||||
self.STORAGE_POOL_NAME
|
||||
): self.BAD_STATUS_RESPONSE,
|
||||
},
|
||||
}
|
||||
|
||||
def test_no_domain(self):
|
||||
"""No protection domain name or ID provided."""
|
||||
self.driver.protection_domain_name = None
|
||||
self.driver.protection_domain_id = None
|
||||
self.assertRaises(exception.VolumeBackendAPIException,
|
||||
self.test_create_volume)
|
||||
|
||||
def test_no_domain_id(self):
|
||||
"""Only protection domain name provided."""
|
||||
self.driver.protection_domain_id = None
|
||||
self.driver.protection_domain_name = self.PROTECTION_DOMAIN_NAME
|
||||
self.driver.storage_pool_name = None
|
||||
self.driver.storage_pool_id = self.STORAGE_POOL_ID
|
||||
self.test_create_volume()
|
||||
|
||||
def test_no_domain_id_invalid_response(self):
|
||||
self.set_https_response_mode(self.RESPONSE_MODE.Invalid)
|
||||
self.assertRaises(exception.VolumeBackendAPIException,
|
||||
self.test_no_domain_id)
|
||||
|
||||
def test_no_domain_id_badstatus_response(self):
|
||||
self.set_https_response_mode(self.RESPONSE_MODE.BadStatus)
|
||||
self.assertRaises(exception.VolumeBackendAPIException,
|
||||
self.test_no_domain_id)
|
||||
|
||||
def test_no_storage_id(self):
|
||||
"""Only protection domain name provided."""
|
||||
self.driver.storage_pool_id = None
|
||||
self.driver.storage_pool_name = self.STORAGE_POOL_NAME
|
||||
self.driver.protection_domain_id = self.PROTECTION_DOMAIN_ID
|
||||
self.driver.protection_domain_name = None
|
||||
self.test_create_volume()
|
||||
|
||||
def test_no_storage_id_invalid_response(self):
|
||||
self.set_https_response_mode(self.RESPONSE_MODE.Invalid)
|
||||
self.assertRaises(exception.VolumeBackendAPIException,
|
||||
self.test_no_storage_id)
|
||||
|
||||
def test_no_storage_id_badstatus_response(self):
|
||||
self.set_https_response_mode(self.RESPONSE_MODE.BadStatus)
|
||||
self.assertRaises(exception.VolumeBackendAPIException,
|
||||
self.test_no_storage_id)
|
||||
|
||||
def test_create_volume(self):
|
||||
"""Valid create volume parameters"""
|
||||
self.driver.create_volume(self.volume)
|
||||
|
||||
def test_create_volume_badstatus_response(self):
|
||||
self.set_https_response_mode(self.RESPONSE_MODE.BadStatus)
|
||||
self.assertRaises(exception.VolumeBackendAPIException,
|
||||
self.test_create_volume)
|
|
@ -0,0 +1,91 @@
|
|||
# Copyright (c) 2013 - 2015 EMC Corporation.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
import urllib
|
||||
|
||||
import six
|
||||
|
||||
from cinder import context
|
||||
from cinder import exception
|
||||
from cinder.tests.unit import fake_snapshot
|
||||
from cinder.tests.unit import fake_volume
|
||||
from cinder.tests.unit.volume.drivers.emc import scaleio
|
||||
|
||||
|
||||
class TestCreateVolumeFromSnapShot(scaleio.TestScaleIODriver):
|
||||
"""Test cases for ``ScaleIODriver.create_volume_from_snapshot()``"""
|
||||
STORAGE_POOL_ID = six.text_type('1')
|
||||
STORAGE_POOL_NAME = 'SP1'
|
||||
|
||||
PROT_DOMAIN_ID = six.text_type('1')
|
||||
PROT_DOMAIN_NAME = 'PD1'
|
||||
|
||||
def setUp(self):
|
||||
"""Setup a test case environment.
|
||||
|
||||
Creates fake volume and snapshot objects and sets up the required
|
||||
API responses.
|
||||
"""
|
||||
super(TestCreateVolumeFromSnapShot, self).setUp()
|
||||
ctx = context.RequestContext('fake', 'fake', auth_token=True)
|
||||
|
||||
self.snapshot = fake_snapshot.fake_snapshot_obj(ctx)
|
||||
self.snapshot_name_2x_enc = urllib.quote(
|
||||
urllib.quote(self.driver.id_to_base64(self.snapshot.id))
|
||||
)
|
||||
self.volume = fake_volume.fake_volume_obj(ctx)
|
||||
self.volume_name_2x_enc = urllib.quote(
|
||||
urllib.quote(self.driver.id_to_base64(self.volume.id))
|
||||
)
|
||||
|
||||
self.HTTPS_MOCK_RESPONSES = {
|
||||
self.RESPONSE_MODE.Valid: {
|
||||
'types/Volume/instances/getByName::' +
|
||||
self.snapshot_name_2x_enc: self.snapshot.id,
|
||||
'instances/System/action/snapshotVolumes': self.volume.id,
|
||||
},
|
||||
self.RESPONSE_MODE.BadStatus: {
|
||||
'instances/System/action/snapshotVolumes::':
|
||||
self.BAD_STATUS_RESPONSE,
|
||||
'types/Volume/instances/getByName::' +
|
||||
self.snapshot_name_2x_enc: self.BAD_STATUS_RESPONSE,
|
||||
self.snapshot_name_2x_enc: self.BAD_STATUS_RESPONSE,
|
||||
},
|
||||
self.RESPONSE_MODE.Invalid: {
|
||||
'types/Volume/instances/getByName::' +
|
||||
self.snapshot_name_2x_enc: None,
|
||||
},
|
||||
}
|
||||
|
||||
def test_bad_login(self):
|
||||
self.set_https_response_mode(self.RESPONSE_MODE.BadStatus)
|
||||
self.assertRaises(
|
||||
exception.VolumeBackendAPIException,
|
||||
self.driver.create_volume_from_snapshot,
|
||||
self.volume,
|
||||
self.snapshot
|
||||
)
|
||||
|
||||
def test_invalid_snapshot(self):
|
||||
self.set_https_response_mode(self.RESPONSE_MODE.Invalid)
|
||||
self.assertRaises(
|
||||
exception.VolumeBackendAPIException,
|
||||
self.driver.create_volume_from_snapshot,
|
||||
self.volume,
|
||||
self.snapshot
|
||||
)
|
||||
|
||||
def test_create_volume_from_snapshot(self):
|
||||
self.set_https_response_mode(self.RESPONSE_MODE.Valid)
|
||||
self.driver.create_volume_from_snapshot(self.volume, self.snapshot)
|
|
@ -0,0 +1,99 @@
|
|||
# Copyright (c) 2013 - 2015 EMC Corporation.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
import urllib
|
||||
|
||||
import six
|
||||
|
||||
from cinder import context
|
||||
from cinder import exception
|
||||
from cinder.tests.unit.fake_snapshot import fake_snapshot_obj
|
||||
from cinder.tests.unit.volume.drivers.emc import scaleio
|
||||
from cinder.tests.unit.volume.drivers.emc.scaleio import mocks
|
||||
|
||||
|
||||
class TestDeleteSnapShot(scaleio.TestScaleIODriver):
|
||||
"""Test cases for ``ScaleIODriver.delete_snapshot()``"""
|
||||
STORAGE_POOL_ID = six.text_type('1')
|
||||
STORAGE_POOL_NAME = 'SP1'
|
||||
|
||||
PROT_DOMAIN_ID = six.text_type('1')
|
||||
PROT_DOMAIN_NAME = 'PD1'
|
||||
VOLUME_NOT_FOUND_ERROR = 3
|
||||
|
||||
def setUp(self):
|
||||
"""Setup a test case environment.
|
||||
|
||||
Creates fake volume and snapshot objects and sets up the required
|
||||
API responses.
|
||||
"""
|
||||
super(TestDeleteSnapShot, self).setUp()
|
||||
ctx = context.RequestContext('fake', 'fake', auth_token=True)
|
||||
|
||||
self.snapshot = fake_snapshot_obj(ctx)
|
||||
self.snapshot_name_2x_enc = urllib.quote(
|
||||
urllib.quote(
|
||||
self.driver.id_to_base64(self.snapshot.id)
|
||||
)
|
||||
)
|
||||
|
||||
self.HTTPS_MOCK_RESPONSES = {
|
||||
self.RESPONSE_MODE.Valid: {
|
||||
'types/Volume/instances/getByName::' +
|
||||
self.snapshot_name_2x_enc: self.snapshot.id,
|
||||
'instances/Volume::{}/action/removeMappedSdc'.format(
|
||||
self.snapshot.id
|
||||
): self.snapshot.id,
|
||||
'instances/Volume::{}/action/removeVolume'.format(
|
||||
self.snapshot.id
|
||||
): self.snapshot.id,
|
||||
},
|
||||
self.RESPONSE_MODE.BadStatus: {
|
||||
'types/Volume/instances/getByName::' +
|
||||
self.snapshot_name_2x_enc: self.BAD_STATUS_RESPONSE,
|
||||
},
|
||||
self.RESPONSE_MODE.Invalid: {
|
||||
'types/Volume/instances/getByName::' +
|
||||
self.snapshot_name_2x_enc: mocks.MockHTTPSResponse(
|
||||
{
|
||||
'errorCode': self.VOLUME_NOT_FOUND_ERROR,
|
||||
'message': 'Test Delete Invalid Snapshot',
|
||||
}, 400
|
||||
),
|
||||
},
|
||||
}
|
||||
|
||||
def test_bad_login(self):
|
||||
self.set_https_response_mode(self.RESPONSE_MODE.BadStatus)
|
||||
self.assertRaises(exception.VolumeBackendAPIException,
|
||||
self.driver.delete_snapshot, self.snapshot)
|
||||
|
||||
def test_delete_invalid_snapshot_force_delete(self):
|
||||
self.driver.configuration.set_override('sio_force_delete',
|
||||
override=True)
|
||||
self.set_https_response_mode(self.RESPONSE_MODE.Invalid)
|
||||
self.driver.delete_snapshot(self.snapshot)
|
||||
|
||||
def test_delete_invalid_snapshot(self):
|
||||
self.set_https_response_mode(self.RESPONSE_MODE.Invalid)
|
||||
self.assertRaises(exception.VolumeBackendAPIException,
|
||||
self.driver.delete_snapshot, self.snapshot)
|
||||
|
||||
def test_delete_snapshot(self):
|
||||
"""Setting the unmap volume before delete flag for tests """
|
||||
self.driver.configuration.set_override(
|
||||
'sio_unmap_volume_before_deletion',
|
||||
override=True)
|
||||
self.set_https_response_mode(self.RESPONSE_MODE.Valid)
|
||||
self.driver.delete_snapshot(self.snapshot)
|
|
@ -0,0 +1,79 @@
|
|||
# Copyright (c) 2013 - 2015 EMC Corporation.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
import urllib
|
||||
|
||||
import six
|
||||
|
||||
from cinder import context
|
||||
from cinder import exception
|
||||
from cinder.tests.unit import fake_volume
|
||||
from cinder.tests.unit.volume.drivers.emc import scaleio
|
||||
from cinder.tests.unit.volume.drivers.emc.scaleio import mocks
|
||||
|
||||
|
||||
class TestDeleteVolume(scaleio.TestScaleIODriver):
|
||||
"""Test cases for ``ScaleIODriver.delete_volume()``"""
|
||||
STORAGE_POOL_ID = six.text_type('1')
|
||||
STORAGE_POOL_NAME = 'SP1'
|
||||
|
||||
PROT_DOMAIN_ID = six.text_type('1')
|
||||
PROT_DOMAIN_NAME = 'PD1'
|
||||
|
||||
def setUp(self):
|
||||
"""Setup a test case environment.
|
||||
|
||||
Creates a fake volume object and sets up the required API responses.
|
||||
"""
|
||||
super(TestDeleteVolume, self).setUp()
|
||||
ctx = context.RequestContext('fake', 'fake', auth_token=True)
|
||||
|
||||
self.volume = fake_volume.fake_volume_obj(ctx)
|
||||
self.volume_name_2x_enc = urllib.quote(
|
||||
urllib.quote(self.driver.id_to_base64(self.volume.id))
|
||||
)
|
||||
|
||||
self.HTTPS_MOCK_RESPONSES = {
|
||||
self.RESPONSE_MODE.Valid: {
|
||||
'types/Volume/instances/getByName::' +
|
||||
self.volume_name_2x_enc: self.volume.id,
|
||||
'instances/Volume::{}/action/removeMappedSdc'.format(
|
||||
self.volume.id): self.volume.id,
|
||||
'instances/Volume::{}/action/removeVolume'.format(
|
||||
self.volume.id
|
||||
): self.volume.id,
|
||||
},
|
||||
self.RESPONSE_MODE.BadStatus: {
|
||||
'types/Volume/instances/getByName::' +
|
||||
self.volume_name_2x_enc: mocks.MockHTTPSResponse(
|
||||
{
|
||||
'errorCode': 401,
|
||||
'message': 'BadStatus Volume Test',
|
||||
}, 401
|
||||
),
|
||||
},
|
||||
}
|
||||
|
||||
def test_bad_login_and_volume(self):
|
||||
self.set_https_response_mode(self.RESPONSE_MODE.BadStatus)
|
||||
self.assertRaises(exception.VolumeBackendAPIException,
|
||||
self.driver.delete_volume,
|
||||
self.volume)
|
||||
|
||||
def test_delete_volume(self):
|
||||
"""Setting the unmap volume before delete flag for tests """
|
||||
self.driver.configuration.set_override(
|
||||
'sio_unmap_volume_before_deletion',
|
||||
override=True)
|
||||
self.driver.delete_volume(self.volume)
|
|
@ -0,0 +1,110 @@
|
|||
# Copyright (c) 2013 - 2015 EMC Corporation.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
import urllib
|
||||
|
||||
import six
|
||||
|
||||
from cinder import context
|
||||
from cinder import exception
|
||||
from cinder.tests.unit.fake_volume import fake_volume_obj
|
||||
from cinder.tests.unit.volume.drivers.emc import scaleio
|
||||
from cinder.tests.unit.volume.drivers.emc.scaleio import mocks
|
||||
|
||||
|
||||
class TestExtendVolume(scaleio.TestScaleIODriver):
|
||||
"""Test cases for ``ScaleIODriver.extend_volume()``"""
|
||||
STORAGE_POOL_ID = six.text_type('1')
|
||||
STORAGE_POOL_NAME = 'SP1'
|
||||
|
||||
PROT_DOMAIN_ID = six.text_type('1')
|
||||
PROT_DOMAIN_NAME = 'PD1'
|
||||
|
||||
""" New sizes for the volume.
|
||||
Since ScaleIO has a granularity of 8 GB, multiples of 8 always work.
|
||||
The 7 size should be either rounded up to 8 or raise an exception
|
||||
based on the round_volume_capacity config setting.
|
||||
"""
|
||||
NEW_SIZE = 8
|
||||
BAD_SIZE = 7
|
||||
|
||||
def setUp(self):
|
||||
"""Setup a test case environment.
|
||||
|
||||
Creates fake volume object and sets up the required API responses.
|
||||
"""
|
||||
super(TestExtendVolume, self).setUp()
|
||||
ctx = context.RequestContext('fake', 'fake', auth_token=True)
|
||||
|
||||
self.volume = fake_volume_obj(ctx, **{'id': 'fake_volume'})
|
||||
self.volume_name_2x_enc = urllib.quote(
|
||||
urllib.quote(self.driver.id_to_base64(self.volume.id))
|
||||
)
|
||||
|
||||
self.HTTPS_MOCK_RESPONSES = {
|
||||
self.RESPONSE_MODE.Valid: {
|
||||
'types/Volume/instances/getByName::' +
|
||||
self.volume_name_2x_enc: '"{}"'.format(self.volume.id),
|
||||
'instances/Volume::{}/action/setVolumeSize'.format(
|
||||
self.volume.id
|
||||
): 'OK',
|
||||
},
|
||||
self.RESPONSE_MODE.BadStatus: {
|
||||
'types/Volume/instances/getByName::' +
|
||||
self.volume_name_2x_enc: self.BAD_STATUS_RESPONSE,
|
||||
'types/Volume/instances/getByName::' +
|
||||
self.volume_name_2x_enc: mocks.MockHTTPSResponse(
|
||||
{
|
||||
'errorCode': 401,
|
||||
'message': 'BadStatus Extend Volume Test',
|
||||
}, 401
|
||||
),
|
||||
},
|
||||
self.RESPONSE_MODE.Invalid: {
|
||||
'types/Volume/instances/getByName::' +
|
||||
self.volume_name_2x_enc: None,
|
||||
},
|
||||
}
|
||||
|
||||
def test_bad_login(self):
|
||||
self.set_https_response_mode(self.RESPONSE_MODE.BadStatus)
|
||||
self.assertRaises(exception.VolumeBackendAPIException,
|
||||
self.driver.extend_volume,
|
||||
self.volume,
|
||||
self.NEW_SIZE)
|
||||
|
||||
def test_invalid_volume(self):
|
||||
self.set_https_response_mode(self.RESPONSE_MODE.Invalid)
|
||||
self.assertRaises(exception.VolumeBackendAPIException,
|
||||
self.driver.extend_volume,
|
||||
self.volume,
|
||||
self.NEW_SIZE)
|
||||
|
||||
def test_extend_volume_bad_size_no_round(self):
|
||||
self.driver.configuration.set_override('sio_round_volume_capacity',
|
||||
override=False)
|
||||
self.set_https_response_mode(self.RESPONSE_MODE.Valid)
|
||||
self.assertRaises(exception.VolumeBackendAPIException,
|
||||
self.driver.extend_volume,
|
||||
self.volume,
|
||||
self.BAD_SIZE)
|
||||
|
||||
def test_extend_volume_bad_size_round(self):
|
||||
self.driver.configuration.set_override('sio_round_volume_capacity',
|
||||
override=True)
|
||||
self.driver.extend_volume(self.volume, self.BAD_SIZE)
|
||||
|
||||
def test_extend_volume(self):
|
||||
self.set_https_response_mode(self.RESPONSE_MODE.Valid)
|
||||
self.driver.extend_volume(self.volume, self.NEW_SIZE)
|
|
@ -0,0 +1,110 @@
|
|||
# Copyright (c) 2013 - 2015 EMC Corporation.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
import urllib
|
||||
|
||||
from cinder import exception
|
||||
from cinder.tests.unit.volume.drivers.emc import scaleio
|
||||
|
||||
|
||||
class TestMisc(scaleio.TestScaleIODriver):
|
||||
DOMAIN_NAME = 'PD1'
|
||||
POOL_NAME = 'SP1'
|
||||
STORAGE_POOLS = ['{}:{}'.format(DOMAIN_NAME, POOL_NAME)]
|
||||
|
||||
def setUp(self):
|
||||
"""Set up the test case environment.
|
||||
|
||||
Defines the mock HTTPS responses for the REST API calls.
|
||||
"""
|
||||
super(TestMisc, self).setUp()
|
||||
|
||||
self.domain_name_enc = urllib.quote(self.DOMAIN_NAME)
|
||||
self.pool_name_enc = urllib.quote(self.POOL_NAME)
|
||||
|
||||
self.HTTPS_MOCK_RESPONSES = {
|
||||
self.RESPONSE_MODE.Valid: {
|
||||
'types/Domain/instances/getByName::' +
|
||||
self.domain_name_enc: '"{}"'.format(self.DOMAIN_NAME).encode(
|
||||
'ascii',
|
||||
'ignore'
|
||||
),
|
||||
'types/Pool/instances/getByName::{},{}'.format(
|
||||
self.DOMAIN_NAME,
|
||||
self.POOL_NAME
|
||||
): '"{}"'.format(self.POOL_NAME).encode('ascii', 'ignore'),
|
||||
'types/StoragePool/instances/action/querySelectedStatistics': {
|
||||
'"{}"'.format(self.POOL_NAME): {
|
||||
'capacityInUseInKb': 502,
|
||||
'capacityLimitInKb': 1024,
|
||||
},
|
||||
},
|
||||
},
|
||||
self.RESPONSE_MODE.BadStatus: {
|
||||
'types/Domain/instances/getByName::' +
|
||||
self.domain_name_enc: self.BAD_STATUS_RESPONSE,
|
||||
},
|
||||
self.RESPONSE_MODE.Invalid: {
|
||||
'types/Domain/instances/getByName::' +
|
||||
self.domain_name_enc: None,
|
||||
},
|
||||
}
|
||||
|
||||
def test_valid_configuration(self):
|
||||
self.driver.check_for_setup_error()
|
||||
|
||||
def test_both_storage_pool(self):
|
||||
"""Both storage name and ID provided."""
|
||||
self.driver.storage_pool_id = "test_pool_id"
|
||||
self.driver.storage_pool_name = "test_pool_name"
|
||||
self.assertRaises(exception.InvalidInput,
|
||||
self.driver.check_for_setup_error)
|
||||
|
||||
def test_no_storage_pool(self):
|
||||
"""No storage name or ID provided."""
|
||||
self.driver.storage_pool_name = None
|
||||
self.driver.storage_pool_id = None
|
||||
self.assertRaises(exception.InvalidInput,
|
||||
self.driver.check_for_setup_error)
|
||||
|
||||
def test_both_domain(self):
|
||||
self.driver.protection_domain_name = "test_domain_name"
|
||||
self.driver.protection_domain_id = "test_domain_id"
|
||||
self.assertRaises(exception.InvalidInput,
|
||||
self.driver.check_for_setup_error)
|
||||
|
||||
def test_volume_size_round_true(self):
|
||||
self.driver._check_volume_size(1)
|
||||
|
||||
def test_volume_size_round_false(self):
|
||||
self.driver.configuration.set_override('sio_round_volume_capacity',
|
||||
override=False)
|
||||
self.assertRaises(exception.VolumeBackendAPIException,
|
||||
self.driver._check_volume_size, 1)
|
||||
|
||||
def test_get_volume_stats_bad_status(self):
|
||||
self.driver.storage_pools = self.STORAGE_POOLS
|
||||
self.set_https_response_mode(self.RESPONSE_MODE.BadStatus)
|
||||
self.assertRaises(exception.VolumeBackendAPIException,
|
||||
self.driver.get_volume_stats, True)
|
||||
|
||||
def test_get_volume_stats_invalid_domain(self):
|
||||
self.driver.storage_pools = self.STORAGE_POOLS
|
||||
self.set_https_response_mode(self.RESPONSE_MODE.Invalid)
|
||||
self.assertRaises(exception.VolumeBackendAPIException,
|
||||
self.driver.get_volume_stats, True)
|
||||
|
||||
def test_get_volume_stats(self):
|
||||
self.driver.storage_pools = self.STORAGE_POOLS
|
||||
self.driver.get_volume_stats(True)
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue